pax_global_header00006660000000000000000000000064136214721420014514gustar00rootroot0000000000000052 comment=4718e59b898bbb60b814db3bfe288e286163f271 orafce-VERSION_3_9_0/000077500000000000000000000000001362147214200143335ustar00rootroot00000000000000orafce-VERSION_3_9_0/.gitignore000077500000000000000000000001561362147214200163300ustar00rootroot00000000000000*.o *.a *.so *.so.* *.sdf *.opensdf *.suo *.*.user /.deps/ /orafce.sql /orafce.sql.in /results [Oo]bj/ [Bb]in/orafce-VERSION_3_9_0/COPYRIGHT.orafce000066400000000000000000000013111362147214200170600ustar00rootroot000000000000000-clause license ("Zero Clause BSD") Copyright (C) 2008-2020 by Pavel Stehule Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. orafce-VERSION_3_9_0/INSTALL.orafce000066400000000000000000000015521362147214200166250ustar00rootroot00000000000000Installation ============ This module is normally distributed as a PostgreSQL 'contrib' module. To install it from a pre-configured source tree run the following commands as a user with appropriate privileges from the orafce source directory: export NO_PGXS=1 make make install Alternatively, if you have no source tree you can install using PGXS. Simply run the following commands the adminpack source directory: make make install To install Orafce functions in the database, either run the orafce.sql script using the pgAdmin SQL tool (and then close and reopen the connection to the freshly instrumented server), or run the script using psql, eg: CREATE EXTENSION orafce; Other administration tools that use this module may have different requirements, please consult the tool's documentation for further details. This package requires PostgreSQL 9.4 or later. orafce-VERSION_3_9_0/META.json000066400000000000000000000027251362147214200157620ustar00rootroot00000000000000{ "name": "orafce", "abstract": "Oracle's compatibility functions and packages", "description": "This module allows use a well known Oracle's functions and packages inside PostgreSQL", "version": "3.9.0", "maintainer": [ "Pavel Stehule ", "Takahiro Itagaki " ], "license": { "PostgreSQL": "http://www.postgresql.org/about/licence" }, "prereqs": { "runtime": { "requires": { "plpgsql": 0, "PostgreSQL": "9.4.0" }, "recommends": { "PostgreSQL": "11.0.0" } } }, "provides": { "orafce": { "file": "sql/orafce.sql", "docfile": "README.orafce", "version": "3.9.0", "abstract": "Oracle's compatibility functions and packages" } }, "resources": { "homepage": "http://www.pgsql.cz/index.php/Oracle_functionality_%28en%29", "repository": { "url": "https://github.com/orafce/orafce", "web": "https://github.com/orafce/orafce", "type": "git" } }, "generated_by": "Pavel Stehule", "meta-spec": { "version": "1.0.0", "url": "http://pgxn.org/meta/spec.txt" }, "release_status": "stable", "tags": [ "oracle", "compatibility", "user function", "custom function", "intrerprocess communication", "read from file", "write to file", "bussiness calendar" ] } orafce-VERSION_3_9_0/Makefile000066400000000000000000000035121362147214200157740ustar00rootroot00000000000000MODULE_big = orafce OBJS= parse_keyword.o convert.o file.o datefce.o magic.o others.o plvstr.o plvdate.o shmmc.o plvsubst.o utility.o plvlex.o alert.o pipe.o sqlparse.o putline.o assert.o plunit.o random.o aggregate.o orafce.o varchar2.o nvarchar2.o charpad.o charlen.o EXTENSION = orafce DATA = orafce--3.9.sql orafce--3.2--3.3.sql orafce--3.3--3.4.sql orafce--3.4--3.5.sql orafce--3.5--3.6.sql orafce--3.6--3.7.sql orafce--3.7--3.8.sql orafce--3.8--3.9.sql DOCS = README.asciidoc COPYRIGHT.orafce INSTALL.orafce PG_CONFIG ?= pg_config # make "all" the default target all: REGRESS = orafce orafce2 dbms_output dbms_utility files varchar2 nvarchar2 aggregates nlssort dbms_random REGRESS_OPTS = --load-language=plpgsql --schedule=parallel_schedule --encoding=utf8 #override CFLAGS += -pedantic ifdef NO_PGXS subdir = contrib/$(MODULE_big) top_builddir = ../.. include $(top_builddir)/src/Makefile.global include $(top_srcdir)/contrib/contrib-global.mk else PG_CONFIG = pg_config PGXS := $(shell $(PG_CONFIG) --pgxs) include $(PGXS) endif ifeq ($(enable_nls), yes) SHLIB_LINK += $(filter -lintl,$(LIBS)) endif # remove dependency to libxml2 and libxslt LIBS := $(filter-out -lxml2, $(LIBS)) LIBS := $(filter-out -lxslt, $(LIBS)) plvlex.o: sqlparse.o sqlparse.o: $(srcdir)/sqlscan.c $(srcdir)/sqlparse.h: $(srcdir)/sqlparse.c ; $(srcdir)/sqlparse.c: sqlparse.y ifdef BISON $(BISON) -d $(BISONFLAGS) -o $@ $< else ifdef YACC $(YACC) -d $(YFLAGS) -p cube_yy $< mv -f y.tab.c sqlparse.c mv -f y.tab.h sqlparse.h else bison -d $(BISONFLAGS) -o $@ $< endif endif $(srcdir)/sqlscan.c: sqlscan.l ifdef FLEX $(FLEX) $(FLEXFLAGS) -o'$@' $< else flex $(FLEXFLAGS) -o'$@' $< endif distprep: $(srcdir)/sqlparse.c $(srcdir)/sqlscan.c maintainer-clean: rm -f $(srcdir)/sqlparse.c $(srcdir)/sqlscan.c $(srcdir)/sqlparse.h $(srcdir)/y.tab.c $(srcdir)/y.tab.h orafce-VERSION_3_9_0/NEWS000066400000000000000000000032401362147214200150310ustar00rootroot00000000000000Orafce News - History of user-visible changes Copyright (C) 2008-2016 Orafce Global Development Group Version 3.9.0 - * minor enhancing user_constraints view Version 3.8.0 - 22. May 2019 * PostgreSQL 12 support Version 3.7.0 - 7. Dec 2018 * possibility to better emulate || operator for varchar2 and nvarchar2 types * few bugfixes * only PostgreSQL 9.4 and newer are supported * support for PostgreSQL 11, current master branch (future PostgreSQL 12) is supported too Version 3.6.0 * some Oracle views - user_tab_columns, user_tables, user_objects, ... * support Oracle bad used lpad and nvl functions Version 3.5.0 * fix of important issue - missing IMMUTABLE flag for functions ltrim, btrim, rtrim, lpad, rpad Version 3.4.0 - 2017-03-14 * new aggregate function wm_concat * PostgreSQL 9.6, 10 are supported well Version 3.2.0 - 2016-01-xx * remove support for 8.3, 8.4, 9.0, 9.1 (only 9.2 and higher are supported) * new functions: sysdate, sessiontimezone, dbtimezone Version 3.1 - 2015-07-11 * remove support for 8.2 * add support for 9.5 * change the releasion number system * new functions: to_single_byte, to_multi_byte, nanvl, length, ltrim, btrim, rtrim, lpad, rpad Version 3.0.10 - 1. Jan 2015 * fix compilation issue in new code for Pg <= 9.1 Version 3.0.9 - 27. Dec 2014 * new Varchar2 and Nvarchar2 types * enhanced oracle.substr function * fix PGXN related issues in process Version 3.0.7 - 27. Jul 2014 * PostgreSQL 9.4 compilation * new datatype and related functions: oracle.date Version 3.0.6 - 8. Sep 2013 * PostgreSQL 9.3 compilation * some cleaning, fixes, much more regress tests Version 3.0.5 - X Dec 2012 * PostgreSQL 9.1/9.2 compilation * ... TODO ... orafce-VERSION_3_9_0/README.asciidoc000066400000000000000000000762701362147214200170040ustar00rootroot00000000000000= Orafce - Oracle's compatibility functions and packages Functions and operators that emulate a subset of functions and packages from the Oracle RDBMS. There is a associated Google group - https://groups.google.com/forum/?hl=en#!forum/orafce-general == Oracle functions and Oracle packages This module contains some useful function which can help with porting Oracle application to PostgreSQL or can be useful generally. Built-in Oracle date functions have been tested against Oracle 10 for comformance. Date ranges from 1960 to 2070 work correctly. Dates before 1100-03-01 cannot be verified due to a bug in Oracle. All functions are fully compatible with Oracle and respect all known format strings. Detailed description you can find on internet. Find keywords oracle round trunc date iyyy. == List of format strings for trunc, round functions ---- Y,YY,YYY,YYYY,SYYY,SYEAR year I,IY,IYY,IYYY iso year Q, quarter WW week, day as first day of year IW week, beginning Monday W week, day as first day of month DAY,DY,D first day of week, sunday MONTH,MON,MM,RM month CC,SCC century DDD,DD,J day HH,HH12,HH24 hour MI minute ---- Functions round up. That is, a date of July 1st will be rounded to the next year. The 16th of July will be rounded to August. == Date Functions * add_months(date, integer) date - Returns date plus n months + ----- add_months(date '2005-05-31',1) -> 2005-06-30 ----- * last_date(date) date - Returns last day of the month based on a date value + ---- last_day(date '2005-05-24') -> 2005-05-31 ---- * next_day(date, text) date - Returns the first weekday that is greater than a date value + ---- next_day(date '2005-05-24', 'monday') -> 2005-05-30 ---- * next_day(date, integer) date - Same as above. The second argument should be 1..7 and interpreted as Sunday..Satday. + ---- next_day(date '2005-05-24', 1) -> 2005-05-30 ---- * months_between(date, date) float8 - Returns the number of months between date1 and date2. If a fractional month is calculated, the months_between function calculates the fraction based on a 31-day month. + ---- months_between(date '1995-02-02', date '1995-01-01') -> 1.0322580645161 ---- * trunc(date, text) date - truncate date according to the specified format + ---- trunc(date '2005-07-12', 'iw') -> 2005-07-11 ---- * round(date, text) date - will round dates according to the specified format + ---- round(date '2005-07-12', 'yyyy') -> 2006-01-01 ---- * to_date(text) timestamp - will typecast input text to timestamp. The GUC orafce.nls_date_format is used to specify input text format for this function. If the value is left blank or set as DEFAULT then input text format according to PostgreSQL's datestyle GUC setting. + orafce.nls_date_format value to DEFAULT ---- to_date('2014-05-19 17:23:53+5:30') -> 2014-05-19 17:23:53 ---- + orafce.nls_date_format='YYYY-MMDD HH24:MI:SS' ---- to_date('2014-0519 17:23:53+5:30') -> 2014-05-19 17:23:53 ---- == oracle.date data type This module contain implementation of oracle compatible DATE data type "oracle.date" and functions which are using DATE data type like oracle.add_months,oracle.last_day(),oracle.next_day(),oracle.months_between() etc. Example: ---- set search_path TO oracle,"$user", public, pg_catalog; create table oracle_date(col1 date); insert into oracle_date values('2014-06-24 12:12:11'::date); select * from oracle_date; col1 --------------------- 2014-06-24 12:12:11 (1 row) ---- == oracle.date functions * oracle.add_months(timestamp with time zone, integer) - Returns date and time plus n months + ----- oracle.add_months(oracle.date'2005-05-31 10:12:12',1) -> 2005-06-30 10:12:12 ----- * oracle.last_day(timestamp with time zone) - Returns last day of the month based on a date value + ----- oracle.last_day(oracle.date '2005-05-24 11:12:12') -> 2005-05-31 11:12:12 ----- * oracle.next_day(timestamp with time zone, text) - Returns the first weekday that is greater than a date value + ----- oracle.next_day(oracle.date '2005-05-24 10:12:12', 'monday') -> 2005-05-30 10:12:12 ----- * oracle.next_day(timestamp with time zone, integer) - Same as above. The second argument should be 1..7 and interpreted as Sunday..Satday. + ----- oracle.next_day(oracle.date '2005-05-24 11:21:12', 1) -> 2005-05-29 11:21:12 ----- * oracle.months_between(timestamp with time zone, timestamp with time zone) - Returns the number of months between timestamp1 and timestamp2. If a fractional month is calculated, the months_between function calculates the fraction based on a 31-day month. + ----- oracle.months_between(oracle.date '1995-02-02 10:00:00', oracle.date '1995-01-01 10:21:11') -> 1.03225806451613 ----- * oracle.to_date(text,text) - Returns timestamp without time zone. + ---- oracle.to_date('02/16/09 04:12:12', 'MM/DD/YY HH24:MI:SS') -> 2009-02-16 04:12:12 ---- * oracle.to_date(text) - Returns oracle.date + ---- oracle.to_date('02/16/09 04:12:12') -> 2009-02-16 04:12:12 ---- * oracle.sysdate() - Returns statement timestamp at server timezone (orafce.timezone) + ----- oracle.sysdate() -> 2015-12-09 17:47:56 ----- * oracle.dbtimezone - Returns server time zone - emulated via orafce.timezone + ----- oracle.dbtimezone() -> GMT ----- * oracle.sessiontimezone() - Returns session timezone - current PostgreSQL timezone + ----- oracle.sessiontimezone() -> Europe/Prague ----- * oracle.to_char(timestamp) - Returns timestamp in nls_date_format. + ---- orafce.nls_date_format='YY-MonDD HH24:MI:SS' ---- + ---- oracle.to_char(to_date('14-Jan08 11:44:49+05:30')) -> 14-Jan08 11:44:49 ---- + ---- orafce.nls_date_format='YY-MonDD HH24:MI:SS' ---- + ---- oracle.to_char(oracle.to_date('21052014 12:13:44+05:30','DDMMYYYY HH24:MI:SS')) -> 14-May21 12:13:44 ---- == oracle.date Operators * oracle.+(oracle.date,smallint) - Returns oracle.date + ---- oracle.to_date('2014-07-02 10:08:55','YYYY-MM-DD HH:MI:SS') + 9::smallint -> 2014-07-11 10:08:55 ---- * oracle.+(oracle.date,integer) - Returns oracle.date + ---- oracle.to_date('2014-07-02 10:08:55','YYYY-MM-DD HH:MI:SS') + 9::integer -> 2014-07-11 10:08:55 ---- * oracle.+(oracle.date,bigint) - Returns oracle.date + ---- oracle.to_date('2014-07-02 10:08:55','YYYY-MM-DD HH:MI:SS') + 9::bigint -> 2014-07-11 10:08:55 ---- * oracle.+(oracle.date,numeric) - Returns oracle.date + ---- oracle.to_date('2014-07-02 10:08:55','YYYY-MM-DD HH:MI:SS') + 9::numeric -> 2014-07-11 10:08:55 ---- * oracle.-(oracle.date,smallint) - Returns oracle.date + ---- oracle.to_date('2014-07-02 10:08:55','YYYY-MM-DD HH:MI:SS') - 9::smallint -> 2014-06-23 10:08:55 ---- * oracle.-(oracle.date,integer) - Returns oracle.date + ---- oracle.to_date('2014-07-02 10:08:55','YYYY-MM-DD HH:MI:SS') - 9::integer -> 2014-06-23 10:08:55 ---- * oracle.-(oracle.date,bigint) - Returns oracle.date + ---- oracle.to_date('2014-07-02 10:08:55','YYYY-MM-DD HH:MI:SS') - 9::bigint -> 2014-06-23 10:08:55 ---- * oracle.-(oracle.date,numeric) - Returns oracle.date + ---- oracle.to_date('2014-07-02 10:08:55','YYYY-MM-DD HH:MI:SS') - 9::numeric -> 2014-06-23 10:08:55 ---- * oracle.-(oracle.date,oracle.date) - Returns double precision + ---- oracle.to_date('2014-07-17 11:10:15', 'yyyy-mm-dd hh24:mi:ss') - oracle.to_date('2014-02-01 10:00:00', 'yyyy-mm-dd hh24:mi:ss') -> 166.048785 ---- You need to set search_path TO oracle,"$user", public, pg_catalog because the functions like oracle.add_months,oracle.last_day,oracle.next_day,oracle.months_between is installed side-by-side with pg_catalog.add_months,pg_catalog.last_day,pg_catalog.next_day,pg_catalog.months_between. == Table dual PostgreSQL does not need Oracle's table 'dual', but since it is intensively used by Oracle users, we create it. == Package dbms_output PostgreSQL sends information to the client via RAISE NOTICE. Oracle uses dbms_output.put_line(). This works differently to RAISE NOTICE. Oracle has a session queue, put_line() adds a line to the queue and the function get_line() reads from queue. If flag 'serveroutput' is set, then client over all sql statements reads queue. You can use: ---- select dbms_output.enable(); select dbms_output.put_line('first_line'); select dbms_output.put_line('next_line'); select * from dbms_output.get_lines(0); ---- or ---- select dbms_output.enable(); select dbms_output.serveroutput('t'); select dbms_output.put_line('first_line'); ---- This package contains the following functions: enable(), disable(), serveroutput(), put(), put_line(), new_line(), get_line(), get_lines(). The package queue is implemented in the session's local memory. == Package utl_file This package allows PL/pgSQL prgrams read from and write to any files that are accessible from server. Every session can open maximaly ten files and max line size is 32K. This package contains functions: * utl_file.fclose(file utl_file.file_type) - close file * utl_file.fclose_all() - close all files * utl_file.fcopy(src_location, src_filename, dest_location, dest_filename[, start_line][, end_line]) - copy text file * utl_file.fflush(file utl_file.file_type) - flushes all data from buffers * utl_file.fgetattr(location, filename) - get file attributes * utl_file.fopen(location text, filename text, file_mode text [, maxlinesize int] [, encoding name]) utl_file.file_type - open file * utl_file.fremove(location, filename) - remove file * utl_file.frename(location, filename, dest_dir, dest_file[, overwrite]) - rename file * utl_file.get_line(file utl_file.file_type) text - read one line from file * utl_file.get_nextline(file utl_file.file_type) text - read one line from file or returns NULL * utl_file.is_open(file utl_file.file_type) bool - returns true, if file is opened * utl_file.new_line(file utl_file.file_type [,rows int]) - puts some new line chars to file * utl_file.put(file utl_file.file_type, buffer text) - puts buffer to file * utl_file.put_line(file utl_file.file_type, buffer text) - puts line to file * utl_file.putf(file utl_file.file_type, format buffer [,arg1 text][,arg2 text][..][,arg5 text]) - put formated text into file * utl_file.tmpdir() - get path of temp directory Because PostgreSQL doesn't support call by reference, some function's are gently different: fclose and get_line. ---- declare f utl_file.file_type; begin f := utl_file.fopen('/tmp', 'sample.txt', 'r'); <> loop begin raise notice '%', utl_file.get_line(f); exception when no_data_found then exit readl; end; end loop; f := fclose(f); end; ---- or second (with PostgreSQL specific function get_nextline) ---- declare f utl_file.file_type; line text; begin f := utl_file.fopen('/tmp', 'sample.txt', 'r'); loop line := utl_file.get_nextline(f); exit when line is NULL; raise notice '%', line; exception when others then utl_file.fclose_all(); end; ---- Before using package you have to set table utl_file.utl_file_dir. This contains all allowed directories without ending symbol ('/' or '\'). On WinNT platform you have to put locality parametr with ending symbol '\' everytime. == Package dbms_pipe This package is an emulation of Oracle's package dbms_pipe. It provides inter-session comunication. You can send and read any message with or without waiting; list active pipes; set a pipe as private or public; and, use explicit or implicit pipes. The maximum number of pipes is 50. Shared memory is used to send messages. An example follows: ---- -- Session A select dbms_pipe.create_pipe('my_pipe',10,true); -- explicit pipe creating select dbms_pipe.pack_message('neco je jinak'); select dbms_pipe.pack_message('anything is else'); select dbms_pipe.send_message('my_pipe',20,0); -- change limit and send without waiting select * from dbms_pipe.db_pipes; -- list of current pipes -- Session B select dbms_pipe.receive_message('my_pipe',1); -- wait max 1 sec for message select dbms_pipe.next_item_type(); -- -> 11, text select dbms_pipe.unpack_message_text(); select dbms_pipe.next_item_type(); -- -> 11, text select dbms_pipe.unpack_message_text(); select dbms_pipe.next_item_type(); -- -> 0, no more items select dbms_pipe.remove_pipe('my_pipe'); ---- There are some differences compared to Oracle, however: * limit for pipes isn't in bytes but in elements in pipe * you can send message without waiting * you can send empty messages * next_item_type knows about TIMESTAMP (type 13) * PostgreSQL don't know about the RAW type, use bytea instead == Package dbms_alert Another means of inter-process communication. ---- -- Session A select dbms_alert.register('boo'); select * from dbms_alert.waitany(10); -- Session B select dbms_alert.register('boo'); select * from dbms_alert.waitany(10); -- Session C select dbms_alert.signal('boo','Nice day'); ---- == Package PLVdate This module contains some function for working with bussines days from package PLVdate. Detailed documentation can be found in PLVision library. This package is multicultural, but default configurations are only for european countries (see source code). You should define your own non-business days (max 50 days) and own holidays (max 30 days). A holiday is any non-business day, which is same every year. For example, Christmas day in Western countries. === Functions * plvdate.add_bizdays(day date, days int) date - Get the date created by adding business days to a date * plvdate.nearest_bizday(day date) date - Get the nearest business date to a given date, user defined * plvdate.next_bizday(day date) date - Get the next business date from a given date, user defined * plvdate.bizdays_between(day1 date, day2 date) int - Get the number of business days between two dates * plvdate.prev_bizday(day date) date - Get the previous business date from a given date * plvdate_isbizday(date) bool - Call this function to determine if a date is a business day * plvdate.set_nonbizday(dow varchar) - Set day of week as non bussines day * plvdate.unset_nonbizday(dow varchar) - Unset day of week as non bussines day * plvdate.set_nonbizday(day date) - Set day as non bussines day * plvdate.unset_nonbizday(day date) - Unset day as non bussines day * plvdate.set_nonbizday(day date, repeat bool) - Set day as non bussines day, if 'repeat' is true, then day is nonbiz every year * plvdate.unset_nonbizday(day date, repeat bool) - Unset day as non bussines day, if 'repeat' is true, then day is nonbiz every year * plvdate.use_easter() - Easter Sunday and easter monday will be holiday * plvdate.unuse_easter(); * plvdate.use_easter(useit boolean); * plvdate.using_easter() bool - If we use easter then returns true * plvdate.use_great_friday() - Easter Great Friday will be holiday * plvdate.unuse_easter(); * plvdate.use_easter(useit boolean); * plvdate.using_easter() bool - If we use easter Great Friday as holiday then returns true * plvdate.include_start() - Include starting date in bizdays_between calculation * plvdate.noinclude_start(); * plvdate.include_start(include boolean); * plvdate.including_start() bool; * plvdate.default_holidays(varchar) - load default configurations. You can use the following configurations: Czech, German, Austria, Poland, Slovakia, Russia, GB and USA at this moment. * configuration contains only common holidays for all regions. You can add your own regional holiday with plvdate.set_nonbizday(nonbizday, true) Example: ---- postgres=# select plvdate.default_holidays('czech'); default_holidays ----------------- (1 row) postgres=# select to_char(current_date, 'day'), plvdate.next_bizday(current_date), to_char(plvdate.next_bizday(current_date),'day'); to_char | next_bizday | to_char ----------+-------------+----------- saturday | 2006-03-13 | monday (1 row) ---- Change for non-European environment: ---- select plvdate.unset_nonbizday('saturday'); select plvdate.unset_nonbizday('sunday'); select plvdate.set_nonbizday('friday'); select plvdate.set_nonbizday('2006-05-19', true); select plvdate.unuse_easter(); ---- == Package PLVstr and PLVchr This package contains some useful string and character functions. Each function supports positive and negative offsets -- i.e., offset from the end of the string. For example: ---- plvstr.left('abcdef',2) -> ab plvstr.left('abcdef',-2) -> abcd plvstr.substr('abcdef',1,1) -> a plvstr.substr('abcdef',-1,1) -> f plvstr.substr('abcde',-2,1) -> d ---- List of functions: * plvstr.normalize(str text) - Normalize string - Replace white chars by space, replace spaces by space * plvstr.is_prefix(str text, prefix text, cs bool) - Returns true, if prefix is prefix of str * plvstr.is_prefix(str text, prefix text) - Returns true, if prefix is prefix of str * plvstr.is_prefix(str int, prefix int) - Returns true, if prefix is prefix of str * plvstr.is_prefix(str bigint, prefix bigint) - Returns true, if prefix is prefix of str * plvstr.substr(str text, start int, len int) - Returns substring started on start_in to end * plvstr.substr(str text, start int) - Returns substring started on start_in to end * plvstr.instr(str text, patt text, start int, nth int) - Search pattern in string * plvstr.instr(str text, patt text, start int) - Search pattern in string * plvstr.instr(str text, patt text) - Search pattern in string * plvstr.lpart(str text, div text, start int, nth int, all_if_notfound bool) - Call this function to return the left part of a string * plvstr.lpart(str text, div text, start int, nth int) - Call this function to return the left part of a string * plvstr.lpart(str text, div text, start int) - Call this function to return the left part of a string * plvstr.lpart(str text, div text) - Call this function to return the left part of a string * plvstr.rpart(str text, div text, start int, nth int, all_if_notfound bool) - Call this function to return the right part of a string * plvstr.rpart(str text, div text, start int, nth int) - Call this function to return the right part of a string * plvstr.rpart(str text, div text, start int) - Call this function to return the right part of a string * plvstr.rpart(str text, div text) - Call this function to return the right part of a string * plvstr.lstrip(str text, substr text, num int) - Call this function to remove characters from the beginning * plvstr.lstrip(str text, substr text) - Call this function to remove characters from the beginning * plvstr.rstrip(str text, substr text, num int) - Call this function to remove characters from the end * plvstr.rstrip(str text, substr text) - Call this function to remove characters from the end * plvstr.rvrs(str text, start int, _end int) - Reverse string or part of string * plvstr.rvrs(str text, start int) - Reverse string or part of string * plvstr.rvrs(str text) - Reverse string or part of string * plvstr.left(str text, n int) - Returns firs num_in charaters. You can use negative num_in * plvstr.right(str text, n int) - Returns last num_in charaters. You can use negative num_ni * plvstr.swap(str text, replace text, start int, lengh int) - Replace a substring in a string with a specified string * plvstr.swap(str text, replace text) - Replace a substring in a string with a specified string * plvstr.betwn(str text, start int, _end int, inclusive bool) - Find the Substring Between Start and End Locations * plvstr.betwn(str text, start text, _end text, startnth int, endnth int, inclusive bool, gotoend bool) - Find the Substring Between Start and End Locations * plvstr.betwn(str text, start text, _end text) - Find the Substring Between Start and End Locations * plvstr.betwn(str text, start text, _end text, startnth int, endnth int) - Find the Substring Between Start and End Locations * plvchr.nth(str text, n int) - Call this function to return the Nth character in a string * plvchr.first(str text) - Call this function to return the first character in a string * plvchr.last(str text) - Call this function to return the last character in a string * plvchr.is_blank(c int) - Is blank * plvchr.is_blank(c text) - Is blank * plvchr.is_digit(c int) - Is digit * plvchr.is_digit(c text) - Is digit * plvchr.is_quote(c int) - Is quote * plvchr.is_quote(c text) - Is quote * plvchr.is_other(c int) - Is other * plvchr.is_other(c text) - Is other * plvchr.is_letter(c int) - Is letter * plvchr.is_letter(c text) - Is letter * plvchr.char_name(c text) - Returns the name of the character to ascii code as a VARCHAR. * plvchr.quoted1(str text) - Quoted text between ''' * plvchr.quoted2(str text) - Quoted text between '"' * plvchr.stripped(str text, char_in text) - Strips a string of all instances of the specified characters == Package PLVsubst The PLVsubst package performs string substitutions based on a substitution keyword. * plvsubst.string(template_in text, vals_in text[]) - Scans a string for all instances of the substitution keyword and replace it with the next value in the substitution values list * plvsubst.string(template_in text, vals_in text[], subst_in text) * plvsubst.string(template_in text, vals_in text, delim_in text) * plvsubst.string(template_in text, vals_in text, delim_in text, subst_in text) * plvsubst.setsubst(str text) - Set substitution keyword to default '%s' * plvsubst.subst() - Retrieve substitution keyword Examples: ---- select plvsubst.string('My name is %s %s.', ARRAY['Pavel','Stěhule']); string -------------------------- My name is Pavel Stěhule. (1 row) select plvsubst.string('My name is %s %s.', 'Pavel,Stěhule'); string -------------------------- My name is Pavel Stěhule. (1 row) select plvsubst.string('My name is $$ $$.', 'Pavel|Stěhule','|','$$'); string -------------------------- My name is Pavel Stěhule. (1 row) ---- == Package DBMS_utility * dms_utility.format_call_stack() -- return a formatted string with content of call stack ---- postgres=# select foo2(); foo2 --------------------------------- ----- Call Stack ----- line object number statement name 1 return function foo 1 return function foo1 1 return function foo2 (1 row) ---- == Package PLVlex This package isn't compatible with original PLVlex. ---- postgres=# select * from plvlex.tokens('select * from a.b.c join d ON x=y', true, true); pos | token | code | class | separator | mod ----+--------+------+---------+-----------+------ 0 | select | 527 | KEYWORD | | 7 | * | 42 | OTHERS | | self 9 | from | 377 | KEYWORD | | 25 | a.b.c | | IDENT | | 20 | join | 418 | KEYWORD | | 25 | d | | IDENT | | 27 | on | 473 | KEYWORD | | 30 | x | | IDENT | | 31 | = | 61 | OTHERS | | self 32 | y | | IDENT | | (10 rows) ---- Warning: Keyword's codes can be changed between PostgreSQL versions! o plvlex.tokens(str text, skip_spaces bool, qualified_names bool) - Returns table of lexical elements in str. == DBMS_ASSERT This package protect user input against SQL injection. * dbms_assert.enquote_literal(varchar) varchar - Add leading and trailing quotes, verify that all single quotes are paired with adjacent single quotes. * dbms_assert.enquote_name(varchar [, boolean]) varchar - Enclose name in double quotes. Optional second parameter ensure loweralize of name. Attention - On Oracle is second parameter capitalize! * dbms_assert.noop(varchar) varchar - Returns value without any checking. * dbms_assert.qualified_sql_name(varchar) varchar - This function verifies that the input string is qualified SQL name. * dbms_assert.schema_name(varchar) varchar - Function verifies that input string is an existing schema name. * dbms_assert.simple_sql_name(varchar) varchar -This function verifies that the input string is simple SQL name. * dbms_assert.object_name(varchar) varchar - Verifies that input string is qualified SQL identifier of an existing SQL object. == PLUnit This unit contains some assert functions. * plunit.assert_true(bool [, varchar]) - Asserts that the condition is true. * plunit.assert_false(bool [, varchar]) - Asserts that the condition is false. * plunit.assert_null(anyelement [, varchar]) - Asserts that the actual is null. * plunit.assert_not_null(anyelement [, varchar]) - Asserts that the actual isn't null. * plunit.assert_equals(anyelement, anyelement [, double precision] [, varchar]) - Asserts that expected and actual are equal. * plunit.assert_not_equals(anyelement, anyelement [, double precision] [, varchar]) - Asserts that expected and actual are equal. * plunit.fail([varchar]) - Fail can be used to cause a test procedure to fail immediately using the supplied message. == Package DBMS_random * dbms_random.initialize(int) - Initialize package with a seed value. * dbms_random.normal() - Returns random numbers in a standard normal distribution. * dbms_random.random() - Returns random number from -2^31 .. 2^31. * dbms_random.seed(int) * dbms_random.seed(text) - Reset seed value. * dbms_random.string(opt text(1), len int) - Create random string * dbms_random.terminate() - Terminate package (do nothing in Pg) * dbms_random.value() - Returns a random number from [0.0 - 1.0) * dbms_random.value(low double precision, high double precision) - Returns a random number from [low - high) == Others functions This module contains implementation of functions: concat, nvl, nvl2, lnnvl, decode, bitand, nanvl, sinh, cosh, tanh and oracle.substr. * oracle.substr(str text, start int, len int) - Oracle compatible substring * oracle.substr(str text, start int) - Oracle compatible substring * oracle.substr(str numeric, start numeric) - Oracle compatible substring * oracle.substr(str numeric, start numeric, len numeric) - Oracle compatible substring * oracle.substr(str varchar, start numeric) - Oracle compatible substring * oracle.substr(str varchar, start numeric,len numeric) - Oracle compatible substring * oracle.lpad(string, length [, fill]) - Oracle compatible lpad * oracle.rpad(string, length [, fill]) - Oracle compatible rpad * oracle.ltrim(string text [, characters text]) - Oracle compatible ltrim * oracle.rtrim(string text [, characters text]) - Oracle compatible rtrim * oracle.btrim(string text [, characters text]) - Oracle compatible btrim * oracle.length(string char) - Oracle compatible length * pg_catalog.listagg(str text [, separator text]) - aggregate values to list * pg_catalog.wm_concat(str text) - aggregate values to comma separatated list * pg_catalog.median(float4) - calculate a median * pg_catalog.median(float8) - calculate a median * pg_catalog.to_number(text) - converts a string to a number * pg_catalog.to_number(numeric) - converts a string to a number * pg_catalog.to_number(numeric,numeric) - converts a string to a number * public.to_multi_byte(text) - Convert all single-byte characters to their corresponding multibyte characters * public.to_single_byte(text) - Convert all multi-byte characters to their corresponding single-byte characters You might need to set search_path to 'oracle, pg_catalog, "$user", public' because oracle.substr, oracle.lpad, oracle.rpad, oracle.ltrim, oracle.rtrim, oracle.btrim, oracle.length are installed side-by-side with pg_catalog.substr, pg_catalog.lpad, pg_catalog.rpad, pg_catalog.ltrim, pg_catalog.rtrim, pg_catalog.btrim, pg_catalog.length respectively. Note that in case of lpad and rpad, parameters string and fill can be of types CHAR, VARCHAR, TEXT, VARCHAR2 or NVARCHAR2 (note that the last two are orafce-provided types). The default fill character is a half-width space. Similarly for ltrim, rtrim and btrim. Note that oracle.length has a limitation that it works only in units of characters because PostgreSQL CHAR type only supports character semantics. == VARCHAR2 and NVARCHAR2 Support orafce's VARCHAR2 implements parts of Oracle database specification about VARCHAR2: * Unit of type modifier = 'bytes' (for character semantics, see NVARCHAR2) * Unlike PostgreSQL varchar, implicit cast to VARCHAR2 does not truncate white spaces over declared maximum length * For these types is possible to use null safe || operator, when you enable orafce.varchar2_null_safe_concat TO true . The behave is very similar to Oracle. Attention: - when result is empty string, then result is NULL. This behave is disabled by default. Attention: - there is possible incompatibility between 3.7 and older Orafce releases. A operator function is now marked as stable (was immutable before). Is not possible to create functional indexes over stable or volatile expressions. ---- -- null safe concat (disabled by default) SELECT NULL || 'hello'::varchar2 || NULL; SET orafce.varchar2_null_safe_concat TO true; SELECT NULL || 'hello'::varchar2 || NULL; ---- Please note that PostgreSQL does not allow to dynamically specify how we interpret varchar strings. It always interprets them as 'character' strings as determined by database encoding. So, we can not support both BYTE and CHARACTER semantics for a given varchar type in the same database. We choose to implement the BYTE semantics as that is default in Oracle. For CHARACTER semantics, please see NVARCHAR2 which by default always implements the CHARACTER semantics. Please be careful when using the above type to store strings consisting of multibyte encoded characters wherein each character may be composed of an arbitrary number of bytes. NVARCHAR2 implements the following: * Unit of type modifier = 'characters' (using the character set/encoding of the database) Use this type if character semantics is preferred. Please note that unlike Oracle, orafce's VARCHAR2 and NVARCHAR2 do not impose the 4000 bytes limit on the 'declared' size. In fact it is same as that of PostgreSQL varchar, which is about 10MB (although varchar can theoretically store values of size up to 1GB) Some byte-based string functions to be used with VARCHAR2 strings * substrb(VARCHAR2, int [, int]) - extract a substring of specified length (in bytes) starting at a given byte position (counting from one); if the third argument isnot specified then length to the end of the string is considered * strposb(VARCHAR2, VARCHAR2) - returns the location of specified substring in a given string (counting from one) * lengthb(VARCHAR2) - returns the length (in bytes) of a given string == Emulated views * oracle.user_tab_columns * oracle.user_tables * oracle.user_cons_columns * oracle.user_constraints * oracle.product_componenent_version * oracle.user_objects * oracle.dba_segments == TODO * better documentation * better seralization in dbms_pipe (via _send and _recv functions) * alter shared memory structures by temporary tables: only locks are in shmem, (bitmaps), data in tmp tbl == License This module is released under BSD licence. == Contributors The project was founded in 2008 by Pavel Stehule . Other contributors: * Peter Eisentraut (petere) * Gavin Sherry (swm) * Pavel Stehule (okbob) * Heikki Linnakangas (hlinnaka) * Gabriele Bartolini (gbartolini) * Zdenek Kotala (hlipa) * Takahiro Itagaki (itagaki) * Marco Nenciarini (mnencia) * Pavan Deolasee (pavanvd) * Jeffrey Cohen (jcohen) * Amit Langote (amitlan) * Rahila Syed (rahila) * Beena Emerson (b-emerson) * Vinayak Pokale * Fujii Masao orafce-VERSION_3_9_0/aggregate.c000066400000000000000000000172671362147214200164420ustar00rootroot00000000000000#include "postgres.h" #include #include "funcapi.h" #include "builtins.h" #include "lib/stringinfo.h" #include "utils/builtins.h" #include "orafce.h" PG_FUNCTION_INFO_V1(orafce_listagg1_transfn); PG_FUNCTION_INFO_V1(orafce_wm_concat_transfn); PG_FUNCTION_INFO_V1(orafce_listagg2_transfn); PG_FUNCTION_INFO_V1(orafce_listagg_finalfn); PG_FUNCTION_INFO_V1(orafce_median4_transfn); PG_FUNCTION_INFO_V1(orafce_median4_finalfn); PG_FUNCTION_INFO_V1(orafce_median8_transfn); PG_FUNCTION_INFO_V1(orafce_median8_finalfn); typedef struct { int alen; /* allocated length */ int nextlen; /* next allocated length */ int nelems; /* number of valid entries */ union { float4 *float4_values; float8 *float8_values; } d; } MedianState; int orafce_float4_cmp(const void *a, const void *b); int orafce_float8_cmp(const void *a, const void *b); /**************************************************************** * listagg * * Concates values and returns string. * * Syntax: * FUNCTION listagg(string varchar, delimiter varchar = '') * RETURNS varchar; * * Note: any NULL value is ignored. * ****************************************************************/ /* subroutine to initialize state */ static StringInfo makeStringAggState(FunctionCallInfo fcinfo) { StringInfo state; MemoryContext aggcontext; MemoryContext oldcontext; if (!AggCheckCallContext(fcinfo, &aggcontext)) { /* cannot be called directly because of internal-type argument */ elog(ERROR, "listagg_transfn called in non-aggregate context"); } /* * Create state in aggregate context. It'll stay there across subsequent * calls. */ oldcontext = MemoryContextSwitchTo(aggcontext); state = makeStringInfo(); MemoryContextSwitchTo(oldcontext); return state; } static void appendStringInfoText(StringInfo str, const text *t) { appendBinaryStringInfo(str, VARDATA_ANY(t), VARSIZE_ANY_EXHDR(t)); } Datum orafce_listagg1_transfn(PG_FUNCTION_ARGS) { StringInfo state; state = PG_ARGISNULL(0) ? NULL : (StringInfo) PG_GETARG_POINTER(0); /* Append the element unless null. */ if (!PG_ARGISNULL(1)) { if (state == NULL) state = makeStringAggState(fcinfo); appendStringInfoText(state, PG_GETARG_TEXT_PP(1)); /* value */ } /* * The transition type for string_agg() is declared to be "internal", * which is a pass-by-value type the same size as a pointer. */ PG_RETURN_POINTER(state); } Datum orafce_wm_concat_transfn(PG_FUNCTION_ARGS) { StringInfo state; state = PG_ARGISNULL(0) ? NULL : (StringInfo) PG_GETARG_POINTER(0); /* Append the element unless null. */ if (!PG_ARGISNULL(1)) { if (state == NULL) state = makeStringAggState(fcinfo); else appendStringInfoChar(state, ','); appendStringInfoText(state, PG_GETARG_TEXT_PP(1)); /* value */ } /* * The transition type for string_agg() is declared to be "internal", * which is a pass-by-value type the same size as a pointer. */ PG_RETURN_POINTER(state); } Datum orafce_listagg2_transfn(PG_FUNCTION_ARGS) { return string_agg_transfn(fcinfo); } Datum orafce_listagg_finalfn(PG_FUNCTION_ARGS) { return string_agg_finalfn(fcinfo); } static MedianState * accumFloat4(MedianState *mstate, float4 value, MemoryContext aggcontext) { MemoryContext oldcontext; if (mstate == NULL) { /* First call - initialize */ oldcontext = MemoryContextSwitchTo(aggcontext); mstate = palloc(sizeof(MedianState)); mstate->alen = 1024; mstate->nextlen = 2 * 1024; mstate->nelems = 0; mstate->d.float4_values = palloc(mstate->alen * sizeof(float4)); MemoryContextSwitchTo(oldcontext); } else { /* enlarge float4_values if needed */ if (mstate->nelems >= mstate->alen) { int newlen = mstate->nextlen; oldcontext = MemoryContextSwitchTo(aggcontext); mstate->nextlen += mstate->alen; mstate->alen = newlen; mstate->d.float4_values = repalloc(mstate->d.float4_values, mstate->alen * sizeof(float4)); MemoryContextSwitchTo(oldcontext); } } mstate->d.float4_values[mstate->nelems++] = value; return mstate; } static MedianState * accumFloat8(MedianState *mstate, float8 value, MemoryContext aggcontext) { MemoryContext oldcontext; if (mstate == NULL) { /* First call - initialize */ oldcontext = MemoryContextSwitchTo(aggcontext); mstate = palloc(sizeof(MedianState)); mstate->alen = 1024; mstate->nextlen = 2 * 1024; mstate->nelems = 0; mstate->d.float8_values = palloc(mstate->alen * sizeof(float8)); MemoryContextSwitchTo(oldcontext); } else { /* enlarge float4_values if needed */ if (mstate->nelems >= mstate->alen) { int newlen = mstate->nextlen; oldcontext = MemoryContextSwitchTo(aggcontext); mstate->nextlen += mstate->alen; mstate->alen = newlen; mstate->d.float8_values = repalloc(mstate->d.float8_values, mstate->alen * sizeof(float8)); MemoryContextSwitchTo(oldcontext); } } mstate->d.float8_values[mstate->nelems++] = value; return mstate; } Datum orafce_median4_transfn(PG_FUNCTION_ARGS) { MemoryContext aggcontext; MedianState *state = NULL; float4 elem; if (!AggCheckCallContext(fcinfo, &aggcontext)) { /* cannot be called directly because of internal-type argument */ elog(ERROR, "median4_transfn called in non-aggregate context"); } state = PG_ARGISNULL(0) ? NULL : (MedianState *) PG_GETARG_POINTER(0); if (PG_ARGISNULL(1)) PG_RETURN_POINTER(state); elem = PG_GETARG_FLOAT4(1); state = accumFloat4(state, elem, aggcontext); PG_RETURN_POINTER(state); } int orafce_float4_cmp(const void *_a, const void *_b) { float4 a = *((float4 *) _a); float4 b = *((float4 *) _b); if (isnan(a)) { if (isnan(b)) return 0; else return 1; } else if (isnan(b)) { return -1; } else { if (a > b) return 1; else if (a < b) return -1; else return 0; } } Datum orafce_median4_finalfn(PG_FUNCTION_ARGS) { MedianState *state = NULL; int lidx; int hidx; float4 result; if (PG_ARGISNULL(0)) PG_RETURN_NULL(); state = (MedianState *) PG_GETARG_POINTER(0); if (state == NULL) PG_RETURN_NULL(); qsort(state->d.float4_values, state->nelems, sizeof(float4), orafce_float4_cmp); lidx = state->nelems / 2 + 1 - 1; hidx = (state->nelems + 1) / 2 - 1; if (lidx == hidx) result = state->d.float4_values[lidx]; else result = (state->d.float4_values[lidx] + state->d.float4_values[hidx]) / 2.0f; PG_RETURN_FLOAT4(result); } Datum orafce_median8_transfn(PG_FUNCTION_ARGS) { MemoryContext aggcontext; MedianState *state = NULL; float8 elem; if (!AggCheckCallContext(fcinfo, &aggcontext)) { /* cannot be called directly because of internal-type argument */ elog(ERROR, "median4_transfn called in non-aggregate context"); } state = PG_ARGISNULL(0) ? NULL : (MedianState *) PG_GETARG_POINTER(0); if (PG_ARGISNULL(1)) PG_RETURN_POINTER(state); elem = PG_GETARG_FLOAT8(1); state = accumFloat8(state, elem, aggcontext); PG_RETURN_POINTER(state); } int orafce_float8_cmp(const void *_a, const void *_b) { float8 a = *((float8 *) _a); float8 b = *((float8 *) _b); if (isnan(a)) { if (isnan(b)) return 0; else return 1; } else if (isnan(b)) { return -1; } else { if (a > b) return 1; else if (a < b) return -1; else return 0; } } Datum orafce_median8_finalfn(PG_FUNCTION_ARGS) { MedianState *state = NULL; int lidx; int hidx; float8 result; if (PG_ARGISNULL(0)) PG_RETURN_NULL(); state = (MedianState *) PG_GETARG_POINTER(0); if (state == NULL) PG_RETURN_NULL(); qsort(state->d.float8_values, state->nelems, sizeof(float8), orafce_float8_cmp); lidx = state->nelems / 2 + 1 - 1; hidx = (state->nelems + 1) / 2 - 1; if (lidx == hidx) result = state->d.float8_values[lidx]; else result = (state->d.float8_values[lidx] + state->d.float8_values[hidx]) / 2.0; PG_RETURN_FLOAT8(result); } orafce-VERSION_3_9_0/alert.c000066400000000000000000000525021362147214200156120ustar00rootroot00000000000000#include "postgres.h" #include "executor/spi.h" #include "access/htup_details.h" #include "catalog/pg_type.h" #include "commands/trigger.h" #include "funcapi.h" #include "miscadmin.h" #include "string.h" #include "storage/lwlock.h" #include "utils/timestamp.h" #include "orafce.h" #include "builtins.h" #include "pipe.h" #include "shmmc.h" #include "utils/rel.h" PG_FUNCTION_INFO_V1(dbms_alert_register); PG_FUNCTION_INFO_V1(dbms_alert_remove); PG_FUNCTION_INFO_V1(dbms_alert_removeall); PG_FUNCTION_INFO_V1(dbms_alert_set_defaults); PG_FUNCTION_INFO_V1(dbms_alert_signal); PG_FUNCTION_INFO_V1(dbms_alert_waitany); PG_FUNCTION_INFO_V1(dbms_alert_waitone); PG_FUNCTION_INFO_V1(dbms_alert_defered_signal); extern unsigned int sid; float8 sensitivity = 250.0; extern LWLockId shmem_lockid; #ifndef _GetCurrentTimestamp #define _GetCurrentTimestamp() GetCurrentTimestamp() #endif #ifndef GetNowFloat #ifdef HAVE_INT64_TIMESTAMP #define GetNowFloat() ((float8) _GetCurrentTimestamp() / 1000000.0) #else #define GetNowFloat() _GetCurrentTimestamp() #endif #endif #define TDAYS (1000*24*3600) /* * There are maximum 30 events and 255 collaborating sessions * */ alert_event *events; alert_lock *locks; alert_lock *session_lock = NULL; #define NOT_FOUND -1 #define NOT_USED -1 /* * Compare text and cstr */ static int textcmpm(text *txt, char *str) { int retval; char *p; int len; len = VARSIZE(txt) - VARHDRSZ; p = VARDATA(txt); while (len-- && *p != '\0') { if (0 != (retval = *p++ - *str++)) return retval; } if (len > 0) return 1; if (*str != '\0') return -1; return 0; } /* * find or create event rec * */ static alert_lock* find_lock(int sid, bool create) { int i; int first_free = NOT_FOUND; if (session_lock != NULL) return session_lock; for (i = 0; i < MAX_LOCKS; i++) { if (locks[i].sid == sid) return &locks[i]; else if (locks[i].sid == NOT_USED && first_free == NOT_FOUND) first_free = i; } if (create) { if (first_free != NOT_FOUND) { locks[first_free].sid = sid; locks[first_free].echo = NULL; session_lock = &locks[first_free]; return &locks[first_free]; } else ereport(ERROR, (errcode(ERRCODE_ORA_PACKAGES_LOCK_REQUEST_ERROR), errmsg("lock request error"), errdetail("Failed to create session lock."), errhint("There are too many collaborating sessions. Increase MAX_LOCKS in 'pipe.h'."))); } return NULL; } static alert_event* find_event(text *event_name, bool create, int *event_id) { int i; for (i = 0; i < MAX_EVENTS;i++) { if (events[i].event_name != NULL && textcmpm(event_name,events[i].event_name) == 0) { if (event_id != NULL) *event_id = i; return &events[i]; } } if (create) { for (i=0; i < MAX_EVENTS; i++) { if (events[i].event_name == NULL) { events[i].event_name = ora_scstring(event_name); events[i].max_receivers = 0; events[i].receivers = NULL; events[i].messages = NULL; events[i].receivers_number = 0; if (event_id != NULL) *event_id = i; return &events[i]; } } ereport(ERROR, (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("event registeration error"), errdetail("Too many registered events."), errhint("There are too many collaborating sessions. Increase MAX_EVENTS in 'pipe.h'."))); } return NULL; } static void register_event(text *event_name) { alert_event *ev; int *new_receivers; int first_free; int i; find_lock(sid, true); ev = find_event(event_name, true, NULL); first_free = NOT_FOUND; for (i = 0; i < ev->max_receivers; i++) { if (ev->receivers[i] == sid) return; /* event is registered */ if (ev->receivers[i] == NOT_USED && first_free == NOT_FOUND) first_free = i; } /* * I can have a maximum of MAX_LOCKS receivers for one event. * Array receivers is increased for 16 fields */ if (first_free == NOT_FOUND) { if (ev->max_receivers + 16 > MAX_LOCKS) ereport(ERROR, (errcode(ERRCODE_ORA_PACKAGES_LOCK_REQUEST_ERROR), errmsg("lock request error"), errdetail("Failed to create session lock."), errhint("There are too many collaborating sessions. Increase MAX_LOCKS in 'pipe.h'."))); /* increase receiver's array */ new_receivers = (int*)salloc((ev->max_receivers + 16)*sizeof(int)); for (i = 0; i < ev->max_receivers + 16; i++) { if (i < ev->max_receivers) new_receivers[i] = ev->receivers[i]; else new_receivers[i] = NOT_USED; } ev->max_receivers += 16; if (ev->receivers) ora_sfree(ev->receivers); ev->receivers = new_receivers; first_free = ev->max_receivers - 16; } ev->receivers_number += 1; ev->receivers[first_free] = sid; } /* * Remove receiver from default receivers of message, * I expect clean all message_items */ static void unregister_event(int event_id, int sid) { alert_event *ev; int i; ev = &events[event_id]; if (ev->receivers_number > 0) { for (i = 0; i < ev->max_receivers; i++) { if (ev->receivers[i] == sid) { ev->receivers[i] = NOT_USED; ev->receivers_number -= 1; break; } } if (ev->receivers_number == 0) { ora_sfree(ev->receivers); ora_sfree(ev->event_name); ev->receivers = NULL; ev->event_name = NULL; } } } /* * remove receiver from list of receivers. * Message has always minimal one receiver * Return true, if exist other receiver */ static bool remove_receiver(message_item *msg, int sid) { int i; bool find_other = false; bool found = false; for (i = 0; i < msg->receivers_number; i++) { if (msg->receivers[i] == sid) { msg->receivers[i] = NOT_USED; found = true; } else if (msg->receivers[i] != NOT_USED) { find_other = true; } if (found && find_other) break; } return find_other; } /* * * Reads message message_id for user sid. If arg:all is true, * then get any message. If arg:remove_all then remove all * signaled messages for sid. If arg:filter_message then * skip other messages than message_id, else read and remove * all others messages than message_id. * */ static char* find_and_remove_message_item(int message_id, int sid, bool all, bool remove_all, bool filter_message, int *sleep, char **event_name) { alert_lock *alck; int _message_id; char *result = NULL; if (sleep != NULL) *sleep = 0; alck = find_lock(sid, false); if (event_name) *event_name = NULL; if (alck != NULL && alck->echo != NULL) { /* if I have registered and created item */ struct _message_echo *echo, *last_echo; echo = alck->echo; last_echo = NULL; while (echo != NULL) { char *message_text; bool destroy_msg_item = false; if (filter_message && echo->message_id != message_id) { last_echo = echo; echo = echo->next_echo; continue; } message_text = echo->message->message; _message_id = echo->message_id; if (!remove_receiver(echo->message, sid)) { destroy_msg_item = true; if (echo->message->prev_message != NULL) echo->message->prev_message->next_message = echo->message->next_message; else events[echo->message_id].messages = echo->message->next_message; if (echo->message->next_message != NULL) echo->message->next_message->prev_message = echo->message->prev_message; ora_sfree(echo->message->receivers); ora_sfree(echo->message); } if (last_echo == NULL) { alck->echo = echo->next_echo; ora_sfree(echo); echo = alck->echo; } else { last_echo->next_echo = echo->next_echo; ora_sfree(echo); echo = last_echo; } if (remove_all) { if (message_text != NULL && destroy_msg_item) ora_sfree(message_text); continue; } else if (_message_id == message_id || all) { /* I have to do local copy */ if (message_text) { result = pstrdup(message_text); if (destroy_msg_item) ora_sfree(message_text); } if (event_name != NULL) *event_name = pstrdup(events[_message_id].event_name); break; } } } return result; } /* * Queue mustn't to contain duplicate messages */ static void create_message(text *event_name, text *message) { int event_id; alert_event *ev; message_item *msg_item = NULL; int i,j,k; find_event(event_name, false, &event_id); /* process event only when any recipient exitsts */ if (NULL != (ev = find_event(event_name, false, &event_id))) { if (ev->receivers_number > 0) { msg_item = ev->messages; while (msg_item != NULL) { if (msg_item->message == NULL && message == NULL) return; if (msg_item->message != NULL && message != NULL) if (0 == textcmpm(message,msg_item->message)) return; msg_item = msg_item->next_message; } msg_item = salloc(sizeof(message_item)); msg_item->receivers = salloc( ev->receivers_number*sizeof(int)); msg_item->receivers_number = ev->receivers_number; if (message != NULL) msg_item->message = ora_scstring(message); else msg_item->message = NULL; msg_item->message_id = event_id; for (i = j = 0; j < ev->max_receivers; j++) { if (ev->receivers[j] != NOT_USED) { msg_item->receivers[i++] = ev->receivers[j]; for (k = 0; k < MAX_LOCKS; k++) if (locks[k].sid == ev->receivers[j]) { /* create echo */ message_echo *echo = salloc(sizeof(message_echo)); echo->message = msg_item; echo->message_id = event_id; echo->next_echo = NULL; if (locks[k].echo == NULL) locks[k].echo = echo; else { message_echo *p; p = locks[k].echo; while (p->next_echo != NULL) p = p->next_echo; p->next_echo = echo; } } } } msg_item->next_message = NULL; if (ev->messages == NULL) { msg_item->prev_message = NULL; ev->messages = msg_item; } else { message_item *p; p = ev->messages; while (p->next_message != NULL) p = p->next_message; p->next_message = msg_item; msg_item->prev_message = p; } } } } #define WATCH_PRE(t, et, c) \ et = GetNowFloat() + (float8)t; c = 0; \ do \ { \ #define WATCH_POST(t,et,c) \ if (GetNowFloat() >= et) \ break; \ if (cycle++ % 100 == 0) \ CHECK_FOR_INTERRUPTS(); \ pg_usleep(10000L); \ } while(t != 0); /* * * PROCEDURE DBMS_ALERT.REGISTER (name IN VARCHAR2); * * Registers the calling session to receive notification of alert name. * */ Datum dbms_alert_register(PG_FUNCTION_ARGS) { text *name = PG_GETARG_TEXT_P(0); int cycle = 0; float8 endtime; float8 timeout = 2; WATCH_PRE(timeout, endtime, cycle); if (ora_lock_shmem(SHMEMMSGSZ, MAX_PIPES, MAX_EVENTS, MAX_LOCKS, false)) { register_event(name); LWLockRelease(shmem_lockid); PG_RETURN_VOID(); } WATCH_POST(timeout, endtime, cycle); LOCK_ERROR(); PG_RETURN_VOID(); } /* * * PROCEDURE DBMS_ALERT.REMOVE(name IN VARCHAR2); * * Unregisters the calling session from receiving notification of alert name. * Don't raise any exceptions. * */ Datum dbms_alert_remove(PG_FUNCTION_ARGS) { text *name = PG_GETARG_TEXT_P(0); alert_event *ev; int ev_id; int cycle = 0; float8 endtime; float8 timeout = 2; WATCH_PRE(timeout, endtime, cycle); if (ora_lock_shmem(SHMEMMSGSZ, MAX_PIPES,MAX_EVENTS,MAX_LOCKS,false)) { ev = find_event(name, false, &ev_id); if (NULL != ev) { find_and_remove_message_item(ev_id, sid, false, true, true, NULL, NULL); unregister_event(ev_id, sid); } LWLockRelease(shmem_lockid); PG_RETURN_VOID(); } WATCH_POST(timeout, endtime, cycle); LOCK_ERROR(); PG_RETURN_VOID(); } /* * * PROCEDURE DBMS_ALERT.REMOVEALL; * * Unregisters the calling session from notification of all alerts. * */ Datum dbms_alert_removeall(PG_FUNCTION_ARGS) { int i; int cycle = 0; float8 endtime; float8 timeout = 2; WATCH_PRE(timeout, endtime, cycle); if (ora_lock_shmem(SHMEMMSGSZ, MAX_PIPES,MAX_EVENTS,MAX_LOCKS,false)) { for (i = 0; i < MAX_EVENTS; i++) if (events[i].event_name != NULL) { find_and_remove_message_item(i, sid, false, true, true, NULL, NULL); unregister_event(i, sid); } LWLockRelease(shmem_lockid); PG_RETURN_VOID(); } WATCH_POST(timeout, endtime, cycle); LOCK_ERROR(); PG_RETURN_VOID(); } /* * * PROCEDURE DBMS_ALERT.WAITANY(name OUT VARCHAR2 ,message OUT VARCHAR2 * ,status OUT INTEGER * ,timeout IN NUMBER DEFAULT MAXWAIT); * * Waits for up to timeout seconds to be notified of any alerts for which * the session is registered. If status = 0 then name and message contain * alert information. If status = 1 then timeout seconds elapsed without * notification of any alert. * */ Datum dbms_alert_waitany(PG_FUNCTION_ARGS) { float8 timeout; TupleDesc tupdesc; AttInMetadata *attinmeta; HeapTuple tuple; Datum result; char *str[3] = {NULL, NULL, "1"}; int cycle = 0; float8 endtime; TupleDesc btupdesc; if (PG_ARGISNULL(0)) timeout = TDAYS; else timeout = PG_GETARG_FLOAT8(0); WATCH_PRE(timeout, endtime, cycle); if (ora_lock_shmem(SHMEMMSGSZ, MAX_PIPES, MAX_EVENTS, MAX_LOCKS, false)) { str[1] = find_and_remove_message_item(-1, sid, true, false, false, NULL, &str[0]); if (str[0]) { str[2] = "0"; LWLockRelease(shmem_lockid); break; } LWLockRelease(shmem_lockid); } WATCH_POST(timeout, endtime, cycle); get_call_result_type(fcinfo, NULL, &tupdesc); btupdesc = BlessTupleDesc(tupdesc); attinmeta = TupleDescGetAttInMetadata(btupdesc); tuple = BuildTupleFromCStrings(attinmeta, str); result = HeapTupleGetDatum(tuple); if (str[0]) pfree(str[0]); if (str[1]) pfree(str[1]); return result; } /* * * PROCEDURE DBMS_ALERT.WAITONE(name IN VARCHAR2, message OUT VARCHAR2 * ,status OUT INTEGER * ,timeout IN NUMBER DEFAULT MAXWAIT); * * Waits for up to timeout seconds for notification of alert name. If status = 0 * then message contains alert information. If status = 1 then timeout * seconds elapsed without notification. * */ Datum dbms_alert_waitone(PG_FUNCTION_ARGS) { text *name; float8 timeout; TupleDesc tupdesc; AttInMetadata *attinmeta; HeapTuple tuple; Datum result; int message_id; char *str[2] = {NULL,"1"}; char *event_name; int cycle = 0; float8 endtime; TupleDesc btupdesc; if (PG_ARGISNULL(0)) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("event name is NULL"), errdetail("Eventname may not be NULL."))); if (PG_ARGISNULL(1)) timeout = TDAYS; else timeout = PG_GETARG_FLOAT8(1); name = PG_GETARG_TEXT_P(0); WATCH_PRE(timeout, endtime, cycle); if (ora_lock_shmem(SHMEMMSGSZ, MAX_PIPES, MAX_EVENTS, MAX_LOCKS, false)) { if (NULL != find_event(name, false, &message_id)) { str[0] = find_and_remove_message_item(message_id, sid, false, false, false, NULL, &event_name); if (event_name != NULL) { str[1] = "0"; pfree(event_name); LWLockRelease(shmem_lockid); break; } } LWLockRelease(shmem_lockid); } WATCH_POST(timeout, endtime, cycle); get_call_result_type(fcinfo, NULL, &tupdesc); btupdesc = BlessTupleDesc(tupdesc); attinmeta = TupleDescGetAttInMetadata(btupdesc); tuple = BuildTupleFromCStrings(attinmeta, str); result = HeapTupleGetDatum(tuple); if (str[0]) pfree(str[0]); return result; } /* * * PROCEDURE DBMS_ALERT.SET_DEFAULTS(sensitivity IN NUMBER); * * The SET_DEFAULTS procedure is used to set session configurable settings * used by the DBMS_ALERT package. Currently, the polling loop interval sleep time * is the only session setting that can be modified using this procedure. The * header for this procedure is, * */ Datum dbms_alert_set_defaults(PG_FUNCTION_ARGS) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("feature not supported"), errdetail("Sensitivity isn't supported."))); PG_RETURN_VOID(); } /* * This code was originally in plpgsql * */ /* CREATE OR REPLACE FUNCTION dbms_alert._defered_signal() RETURNS trigger AS $$ BEGIN PERFORM dbms_alert._signal(NEW.event, NEW.message); DELETE FROM ora_alerts WHERE oid=NEW.oid; RETURN NEW; END; $$ LANGUAGE plpgsql SECURITY DEFINER VOLATILE; */ #define DatumGetItemPointer(X) ((ItemPointer) DatumGetPointer(X)) #define ItemPointerGetDatum(X) PointerGetDatum(X) Datum dbms_alert_defered_signal(PG_FUNCTION_ARGS) { TriggerData *trigdata = (TriggerData *) fcinfo->context; TupleDesc tupdesc; HeapTuple rettuple; char *relname; text *name; text *message; int event_col; int message_col; Datum datum; bool isnull; int cycle = 0; float8 endtime; float8 timeout = 2; if (!CALLED_AS_TRIGGER(fcinfo)) ereport(ERROR, (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION), errmsg("not called by trigger manager"))); if (!TRIGGER_FIRED_BY_INSERT(trigdata->tg_event)) ereport(ERROR, (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION), errmsg("not called on valid event"))); if (SPI_connect() < 0) ereport(ERROR, (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION), errmsg("SPI_connect failed"))); if (strcmp((relname = SPI_getrelname(trigdata->tg_relation)), "ora_alerts") != 0) ereport(ERROR, (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION), errmsg("not called with valid relation"))); rettuple = trigdata->tg_trigtuple; tupdesc = trigdata->tg_relation->rd_att; if (SPI_ERROR_NOATTRIBUTE == (event_col = SPI_fnumber(tupdesc, "event"))) ereport(ERROR, (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION), errmsg("attribute event not found"))); if (SPI_ERROR_NOATTRIBUTE == (message_col = SPI_fnumber(tupdesc, "message"))) ereport(ERROR, (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION), errmsg("attribute message not found"))); datum = SPI_getbinval(rettuple, tupdesc, event_col, &isnull); if (isnull) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("event name is NULL"), errdetail("Eventname may not be NULL."))); name = DatumGetTextP(datum); datum = SPI_getbinval(rettuple, tupdesc, message_col, &isnull); if (isnull) message = NULL; else message = DatumGetTextP(datum); WATCH_PRE(timeout, endtime, cycle); if (ora_lock_shmem(SHMEMMSGSZ, MAX_PIPES, MAX_EVENTS, MAX_LOCKS, false)) { ItemPointer tid; Oid argtypes[1] = {TIDOID}; char nulls[1] = {' '}; Datum values[1]; void *plan; create_message(name, message); LWLockRelease(shmem_lockid); tid = &rettuple->t_data->t_ctid; if (!(plan = SPI_prepare("DELETE FROM ora_alerts WHERE ctid = $1", 1, argtypes))) ereport(ERROR, (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION), errmsg("SPI_prepare failed"))); values[0] = ItemPointerGetDatum(tid); if (SPI_OK_DELETE != SPI_execute_plan(plan, values, nulls, false, 1)) ereport(ERROR, (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION), errmsg("can't execute sql"))); SPI_finish(); return PointerGetDatum(rettuple); } WATCH_POST(timeout, endtime, cycle); LOCK_ERROR(); PG_RETURN_NULL(); } /* * * PROCEDURE DBMS_ALERT.SIGNAL(name IN VARCHAR2,message IN VARCHAR2); * * Signals the occurrence of alert name and attaches message. (Sessions * registered for alert name are notified only when the signaling transaction * commits.) * */ /* CREATE OR REPLACE FUNCTION dbms_alert.signal(_event text, _message text) RETURNS void AS $$ BEGIN PERFORM 1 FROM pg_catalog.pg_class c WHERE pg_catalog.pg_table_is_visible(c.oid) AND c.relkind='r' AND c.relname = 'ora_alerts'; IF NOT FOUND THEN CREATE TEMP TABLE ora_alerts(event text, message text) WITH OIDS; REVOKE ALL ON TABLE ora_alerts FROM PUBLIC; CREATE CONSTRAINT TRIGGER ora_alert_signal AFTER INSERT ON ora_alerts INITIALLY DEFERRED FOR EACH ROW EXECUTE PROCEDURE dbms_alert._defered_signal(); END IF; INSERT INTO ora_alerts(event, message) VALUES(_event, _message); END; $$ LANGUAGE plpgsql VOLATILE SECURITY DEFINER; */ #define SPI_EXEC(cmd,_type_) \ if (SPI_OK_##_type_ != SPI_exec(cmd, 1)) \ ereport(ERROR, \ (errcode(ERRCODE_INTERNAL_ERROR), \ errmsg("SPI execute error"), \ errdetail("Can't execute %s.", cmd))); Datum dbms_alert_signal(PG_FUNCTION_ARGS) { void *plan; Oid argtypes[] = {TEXTOID, TEXTOID}; Datum values[2]; char nulls[2] = {' ',' '}; if (PG_ARGISNULL(0)) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("event name is NULL"), errdetail("Eventname may not be NULL."))); if (PG_ARGISNULL(1)) nulls[1] = 'n'; values[0] = PG_GETARG_DATUM(0); values[1] = PG_GETARG_DATUM(1); if (SPI_connect() < 0) ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), errmsg("SPI_connect failed"))); SPI_EXEC("SELECT 1 FROM pg_catalog.pg_class c " "WHERE pg_catalog.pg_table_is_visible(c.oid) " "AND c.relkind='r' AND c.relname = 'ora_alerts'", SELECT); if (0 == SPI_processed) { SPI_EXEC("CREATE TEMP TABLE ora_alerts(event text, message text)", UTILITY); SPI_EXEC("REVOKE ALL ON TABLE ora_alerts FROM PUBLIC", UTILITY); SPI_EXEC("CREATE CONSTRAINT TRIGGER ora_alert_signal AFTER INSERT ON ora_alerts " "INITIALLY DEFERRED FOR EACH ROW EXECUTE PROCEDURE dbms_alert.defered_signal()", UTILITY); } if (!(plan = SPI_prepare( "INSERT INTO ora_alerts(event,message) VALUES($1, $2)", 2, argtypes))) ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), errmsg("SPI_prepare failed"))); if (SPI_OK_INSERT != SPI_execute_plan(plan, values, nulls, false, 1)) ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), errmsg("can't execute sql"))); SPI_finish(); PG_RETURN_VOID(); } orafce-VERSION_3_9_0/assert.c000066400000000000000000000220221362147214200157760ustar00rootroot00000000000000#include "postgres.h" #include "funcapi.h" #include "assert.h" #include "miscadmin.h" #include "utils/acl.h" #include "utils/builtins.h" #include "utils/syscache.h" #include "catalog/namespace.h" #if PG_VERSION_NUM >= 120000 #include "catalog/pg_namespace_d.h" #endif #include "ctype.h" #include "string.h" #include "orafce.h" #include "builtins.h" #if PG_VERSION_NUM >= 100000 #include "utils/regproc.h" #endif PG_FUNCTION_INFO_V1(dbms_assert_enquote_literal); PG_FUNCTION_INFO_V1(dbms_assert_enquote_name); PG_FUNCTION_INFO_V1(dbms_assert_noop); PG_FUNCTION_INFO_V1(dbms_assert_qualified_sql_name); PG_FUNCTION_INFO_V1(dbms_assert_schema_name); PG_FUNCTION_INFO_V1(dbms_assert_simple_sql_name); PG_FUNCTION_INFO_V1(dbms_assert_object_name); #define CUSTOM_EXCEPTION(code, msg) \ ereport(ERROR, \ (errcode(ERRCODE_ORA_PACKAGES_##code), \ errmsg(msg))) #define INVALID_SCHEMA_NAME_EXCEPTION() \ CUSTOM_EXCEPTION(INVALID_SCHEMA_NAME, "invalid schema name") #define INVALID_OBJECT_NAME_EXCEPTION() \ CUSTOM_EXCEPTION(INVALID_OBJECT_NAME, "invalid object name") #define ISNOT_SIMPLE_SQL_NAME_EXCEPTION() \ CUSTOM_EXCEPTION(ISNOT_SIMPLE_SQL_NAME, "string is not simple SQL name") #define ISNOT_QUALIFIED_SQL_NAME_EXCEPTION() \ CUSTOM_EXCEPTION(ISNOT_QUALIFIED_SQL_NAME, "string is not qualified SQL name") #define EMPTY_STR(str) ((VARSIZE(str) - VARHDRSZ) == 0) static bool check_sql_name(char *cp, int len); static bool ParseIdentifierString(char *rawstring); /* * Procedure ParseIdentifierString is based on SplitIdentifierString * from varlena.c. We need different behave of quote symbol evaluation. */ bool ParseIdentifierString(char *rawstring) { char *nextp = rawstring; bool done = false; while (isspace((unsigned char) *nextp)) nextp++; /* skip leading whitespace */ if (*nextp == '\0') return true; /* allow empty string */ /* At the top of the loop, we are at start of a new identifier. */ do { char *curname; char *endp; if (*nextp == '\"') { /* Quoted name --- collapse quote-quote pairs, no downcasing */ curname = nextp + 1; for (;;) { endp = strchr(nextp + 1, '\"'); if (endp == NULL) return false; /* mismatched quotes */ if (endp[1] != '\"') break; /* found end of quoted name */ /* Collapse adjacent quotes into one quote, and look again */ memmove(endp, endp + 1, strlen(endp)); nextp = endp; } /* endp now points at the terminating quote */ nextp = endp + 1; } else { /* Unquoted name --- extends to separator or whitespace */ curname = nextp; while (*nextp && *nextp != '.' && !isspace((unsigned char) *nextp)) { if (!isalnum(*nextp) && *nextp != '_') return false; nextp++; } endp = nextp; if (curname == nextp) return false; /* empty unquoted name not allowed */ } while (isspace((unsigned char) *nextp)) nextp++; /* skip trailing whitespace */ if (*nextp == '.') { nextp++; while (isspace((unsigned char) *nextp)) nextp++; /* skip leading whitespace for next */ /* we expect another name, so done remains false */ } else if (*nextp == '\0') done = true; else return false; /* invalid syntax */ /* Loop back if we didn't reach end of string */ } while (!done); return true; } /**************************************************************** * DBMS_ASSERT.ENQUOTE_LITERAL * * Syntax: * FUNCTION ENQUOTE_LITERAL(str varchar) RETURNS varchar; * * Purpouse: * Add leading and trailing quotes, verify that all single quotes * are paired with adjacent single quotes. * ****************************************************************/ Datum dbms_assert_enquote_literal(PG_FUNCTION_ARGS) { PG_RETURN_DATUM(DirectFunctionCall1(quote_literal, PG_GETARG_DATUM(0))); } /**************************************************************** * DBMS_ASSERT.ENQUOTE_NAME * * Syntax: * FUNCTION ENQUOTE_NAME(str varchar) RETURNS varchar; * FUNCTION ENQUOTE_NAME(str varchar, loweralize boolean := true) * RETURNS varchar; * Purpouse: * Enclose name in double quotes. * Atention!: * On Oracle is second parameter capitalize! * ****************************************************************/ Datum dbms_assert_enquote_name(PG_FUNCTION_ARGS) { Datum name = PG_GETARG_DATUM(0); bool loweralize = PG_GETARG_BOOL(1); Oid collation = PG_GET_COLLATION(); name = DirectFunctionCall1(quote_ident, name); if (loweralize) name = DirectFunctionCall1Coll(lower, collation, name); PG_RETURN_DATUM(name); } /**************************************************************** * DBMS_ASSERT.NOOP * * Syntax: * FUNCTION NOOP(str varchar) RETURNS varchar; * * Purpouse: * Returns value without any checking. * ****************************************************************/ Datum dbms_assert_noop(PG_FUNCTION_ARGS) { text *str = PG_GETARG_TEXT_P(0); PG_RETURN_TEXT_P(TextPCopy(str)); } /**************************************************************** * DBMS_ASSERT.QUALIFIED_SQL_NAME * * Syntax: * FUNCTION QUALIFIED_SQL_NAME(str varchar) RETURNS varchar; * * Purpouse: * This function verifies that the input string is qualified SQL * name. * Exception: 44004 string is not a qualified SQL name * ****************************************************************/ Datum dbms_assert_qualified_sql_name(PG_FUNCTION_ARGS) { text *qname; if (PG_ARGISNULL(0)) ISNOT_QUALIFIED_SQL_NAME_EXCEPTION(); qname = PG_GETARG_TEXT_P(0); if (EMPTY_STR(qname)) ISNOT_QUALIFIED_SQL_NAME_EXCEPTION(); if (!ParseIdentifierString(text_to_cstring(qname))) ISNOT_QUALIFIED_SQL_NAME_EXCEPTION(); PG_RETURN_TEXT_P(qname); } /**************************************************************** * DBMS_ASSERT.SCHEMA_NAME * * Syntax: * FUNCTION SCHEMA_NAME(str varchar) RETURNS varchar; * * Purpouse: * Function verifies that input string is an existing schema * name. * Exception: 44001 Invalid schema name * ****************************************************************/ Datum dbms_assert_schema_name(PG_FUNCTION_ARGS) { Oid namespaceId; AclResult aclresult; text *sname; char *nspname; List *names; if (PG_ARGISNULL(0)) INVALID_SCHEMA_NAME_EXCEPTION(); sname = PG_GETARG_TEXT_P(0); if (EMPTY_STR(sname)) INVALID_SCHEMA_NAME_EXCEPTION(); nspname = text_to_cstring(sname); names = stringToQualifiedNameList(nspname); if (list_length(names) != 1) INVALID_SCHEMA_NAME_EXCEPTION(); #if PG_VERSION_NUM >= 120000 namespaceId = GetSysCacheOid(NAMESPACENAME, Anum_pg_namespace_oid, CStringGetDatum(strVal(linitial(names))), 0, 0, 0); #else namespaceId = GetSysCacheOid(NAMESPACENAME, CStringGetDatum(strVal(linitial(names))), 0, 0, 0); #endif if (!OidIsValid(namespaceId)) INVALID_SCHEMA_NAME_EXCEPTION(); aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_USAGE); if (aclresult != ACLCHECK_OK) INVALID_SCHEMA_NAME_EXCEPTION(); PG_RETURN_TEXT_P(sname); } /**************************************************************** * DBMS_ASSERT.SIMPLE_SQL_NAME * * Syntax: * FUNCTION SIMPLE_SQL_NAME(str varchar) RETURNS varchar; * * Purpouse: * This function verifies that the input string is simple SQL * name. * Exception: 44003 String is not a simple SQL name * ****************************************************************/ static bool check_sql_name(char *cp, int len) { if (*cp == '"') { for (cp++, len -= 2; len-- > 0; cp++) { /* all double quotes have to be paired */ if (*cp == '"') { if (len-- == 0) return false; /* next char has to be quote */ if (*cp != '"') return false; } } if (*cp != '"') return false; } else { /* Doesn't allow national characters in sql name :( */ for (; len-- > 0; cp++) if (!isalnum(*cp) && *cp != '_') return false; } return true; } Datum dbms_assert_simple_sql_name(PG_FUNCTION_ARGS) { text *sname; int len; char *cp; if (PG_ARGISNULL(0)) ISNOT_SIMPLE_SQL_NAME_EXCEPTION(); sname = PG_GETARG_TEXT_P(0); if (EMPTY_STR(sname)) ISNOT_SIMPLE_SQL_NAME_EXCEPTION(); len = VARSIZE(sname) - VARHDRSZ; cp = VARDATA(sname); if (!check_sql_name(cp, len)) ISNOT_SIMPLE_SQL_NAME_EXCEPTION(); PG_RETURN_TEXT_P(sname); } /**************************************************************** * DBMS_ASSERT.OBJECT_NAME * * Syntax: * FUNCTION OBJECT_NAME(str varchar) RETURNS varchar; * * Purpouse: * Verifies that input string is qualified SQL identifier of * an existing SQL object. * Exception: 44002 Invalid object name * ****************************************************************/ Datum dbms_assert_object_name(PG_FUNCTION_ARGS) { List *names; text *str; char *object_name; Oid classId; if (PG_ARGISNULL(0)) INVALID_OBJECT_NAME_EXCEPTION(); str = PG_GETARG_TEXT_P(0); if (EMPTY_STR(str)) INVALID_OBJECT_NAME_EXCEPTION(); object_name = text_to_cstring(str); names = stringToQualifiedNameList(object_name); classId = RangeVarGetRelid(makeRangeVarFromNameList(names), NoLock, true); if (!OidIsValid(classId)) INVALID_OBJECT_NAME_EXCEPTION(); PG_RETURN_TEXT_P(str); } orafce-VERSION_3_9_0/assert.h000066400000000000000000000006061362147214200160070ustar00rootroot00000000000000#ifndef __ASSERT__ #define __ASSERT__ #define ERRCODE_ORA_PACKAGES_INVALID_SCHEMA_NAME MAKE_SQLSTATE('4','4','0','0','1') #define ERRCODE_ORA_PACKAGES_INVALID_OBJECT_NAME MAKE_SQLSTATE('4','4','0','0','2') #define ERRCODE_ORA_PACKAGES_ISNOT_SIMPLE_SQL_NAME MAKE_SQLSTATE('4','4','0','0','3') #define ERRCODE_ORA_PACKAGES_ISNOT_QUALIFIED_SQL_NAME MAKE_SQLSTATE('4','4','0','0','4') #endif orafce-VERSION_3_9_0/builtins.h000066400000000000000000000344321362147214200163430ustar00rootroot00000000000000 #ifndef ORAFCE_BUILTINS #define ORAFCE_BUILTINS #ifndef PGDLLEXPORT #ifdef _MSC_VER #define PGDLLEXPORT __declspec(dllexport) /* * PG_MODULE_MAGIC and PG_FUNCTION_INFO_V1 macros are broken for MSVC. * So, we redefine them. */ #undef PG_MODULE_MAGIC #define PG_MODULE_MAGIC \ extern PGDLLEXPORT const Pg_magic_struct *PG_MAGIC_FUNCTION_NAME(void); \ const Pg_magic_struct * \ PG_MAGIC_FUNCTION_NAME(void) \ { \ static const Pg_magic_struct Pg_magic_data = PG_MODULE_MAGIC_DATA; \ return &Pg_magic_data; \ } \ extern int no_such_variable #undef PG_FUNCTION_INFO_V1 #define PG_FUNCTION_INFO_V1(funcname) \ extern PGDLLEXPORT const Pg_finfo_record * CppConcat(pg_finfo_,funcname)(void); \ const Pg_finfo_record * \ CppConcat(pg_finfo_,funcname) (void) \ { \ static const Pg_finfo_record my_finfo = { 1 }; \ return &my_finfo; \ } \ extern int no_such_variable #else #define PGDLLEXPORT PGDLLIMPORT #endif #endif /* from aggregate.c */ extern PGDLLEXPORT Datum orafce_listagg1_transfn(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum orafce_wm_concat_transfn(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum orafce_listagg2_transfn(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum orafce_listagg_finalfn(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum orafce_median4_transfn(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum orafce_median4_finalfn(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum orafce_median8_transfn(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum orafce_median8_finalfn(PG_FUNCTION_ARGS); /* from alert.c */ extern PGDLLEXPORT Datum dbms_alert_register(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_alert_remove(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_alert_removeall(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_alert_set_defaults(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_alert_signal(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_alert_waitany(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_alert_waitone(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_alert_defered_signal(PG_FUNCTION_ARGS); /* from assert.c */ extern PGDLLEXPORT Datum dbms_assert_enquote_literal(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_assert_enquote_name(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_assert_noop(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_assert_qualified_sql_name(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_assert_schema_name(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_assert_simple_sql_name(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_assert_object_name(PG_FUNCTION_ARGS); /* from convert.c */ extern PGDLLEXPORT Datum orafce_to_char_int4(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum orafce_to_char_int8(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum orafce_to_char_float4(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum orafce_to_char_float8(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum orafce_to_char_numeric(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum orafce_to_char_timestamp(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum orafce_to_number(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum orafce_to_multi_byte(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum orafce_to_single_byte(PG_FUNCTION_ARGS); /* from datefce.c */ extern PGDLLEXPORT Datum next_day(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum next_day_by_index(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum last_day(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum months_between(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum add_months(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum ora_to_date(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum ora_date_trunc(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum ora_date_round(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum ora_timestamptz_trunc(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum ora_timestamptz_round(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum ora_timestamp_trunc(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum ora_timestamp_round(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum orafce_sysdate(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum orafce_sessiontimezone(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum orafce_dbtimezone(PG_FUNCTION_ARGS); /* from file.c */ extern PGDLLEXPORT Datum utl_file_fopen(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum utl_file_is_open(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum utl_file_get_line(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum utl_file_get_nextline(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum utl_file_put(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum utl_file_put_line(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum utl_file_new_line(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum utl_file_putf(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum utl_file_fflush(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum utl_file_fclose(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum utl_file_fclose_all(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum utl_file_fremove(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum utl_file_frename(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum utl_file_fcopy(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum utl_file_fgetattr(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum utl_file_tmpdir(PG_FUNCTION_ARGS); /* from others.c */ extern PGDLLEXPORT Datum ora_nvl(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum ora_nvl2(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum ora_concat(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum ora_nlssort(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum ora_set_nls_sort(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum ora_lnnvl(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum ora_decode(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum orafce_dump(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum ora_get_major_version(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum ora_get_major_version_num(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum ora_get_full_version_num(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum ora_get_platform(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum ora_get_status(PG_FUNCTION_ARGS); /* from pipe.c */ extern PGDLLEXPORT Datum dbms_pipe_pack_message_text(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_pipe_unpack_message_text(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_pipe_send_message(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_pipe_receive_message(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_pipe_unique_session_name(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_pipe_list_pipes(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_pipe_next_item_type(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_pipe_create_pipe(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_pipe_create_pipe_2(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_pipe_create_pipe_1(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_pipe_reset_buffer(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_pipe_purge(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_pipe_remove_pipe(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_pipe_pack_message_date(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_pipe_unpack_message_date(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_pipe_pack_message_timestamp(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_pipe_unpack_message_timestamp(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_pipe_pack_message_number(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_pipe_unpack_message_number(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_pipe_pack_message_bytea(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_pipe_unpack_message_bytea(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_pipe_pack_message_record(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_pipe_unpack_message_record(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_pipe_pack_message_integer(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_pipe_pack_message_bigint(PG_FUNCTION_ARGS); /* from plunit.c */ extern PGDLLEXPORT Datum plunit_assert_true(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plunit_assert_true_message(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plunit_assert_false(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plunit_assert_false_message(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plunit_assert_null(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plunit_assert_null_message(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plunit_assert_not_null(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plunit_assert_not_null_message(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plunit_assert_equals(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plunit_assert_equals_message(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plunit_assert_equals_range(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plunit_assert_equals_range_message(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plunit_assert_not_equals(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plunit_assert_not_equals_message(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plunit_assert_not_equals_range(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plunit_assert_not_equals_range_message(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plunit_fail(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plunit_fail_message(PG_FUNCTION_ARGS); /* from plvdate.c */ extern PGDLLEXPORT Datum plvdate_add_bizdays(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plvdate_nearest_bizday(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plvdate_next_bizday(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plvdate_bizdays_between(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plvdate_prev_bizday(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plvdate_isbizday(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plvdate_set_nonbizday_dow(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plvdate_unset_nonbizday_dow(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plvdate_set_nonbizday_day(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plvdate_unset_nonbizday_day(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plvdate_use_easter(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plvdate_using_easter(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plvdate_use_great_friday(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plvdate_using_great_friday(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plvdate_include_start(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plvdate_including_start(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plvdate_default_holidays(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plvdate_version(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plvdate_days_inmonth(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plvdate_isleapyear(PG_FUNCTION_ARGS); /* from plvlec.c */ extern PGDLLEXPORT Datum plvlex_tokens(PG_FUNCTION_ARGS); /* from plvstr.c */ extern PGDLLEXPORT Datum plvstr_rvrs(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plvstr_normalize(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plvstr_is_prefix_text(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plvstr_is_prefix_int(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plvstr_is_prefix_int64(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plvstr_lpart(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plvstr_rpart(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plvstr_lstrip(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plvstr_rstrip(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plvstr_left(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plvstr_right(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plvstr_substr2(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plvstr_substr3(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plvstr_instr2(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plvstr_instr3(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plvstr_instr4(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plvstr_betwn_i(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plvstr_betwn_c(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plvstr_swap(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plvchr_nth(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plvchr_first(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plvchr_last(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plvchr_is_kind_i(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plvchr_is_kind_a(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plvchr_char_name(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum oracle_substr2(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum oracle_substr3(PG_FUNCTION_ARGS); /* from plvsubst.c */ extern PGDLLEXPORT Datum plvsubst_string_array(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plvsubst_string_string(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plvsubst_setsubst(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plvsubst_setsubst_default(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum plvsubst_subst(PG_FUNCTION_ARGS); /* from putline.c */ extern PGDLLEXPORT Datum dbms_output_enable(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_output_enable_default(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_output_disable(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_output_serveroutput(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_output_put(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_output_put_line(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_output_new_line(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_output_get_line(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_output_get_lines(PG_FUNCTION_ARGS); /* from random.c */ extern PGDLLEXPORT Datum dbms_random_initialize(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_random_normal(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_random_random(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_random_seed_int(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_random_seed_varchar(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_random_string(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_random_terminate(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_random_value(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_random_value_range(PG_FUNCTION_ARGS); /* from utility.c */ extern PGDLLEXPORT Datum dbms_utility_format_call_stack0(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_utility_format_call_stack1(PG_FUNCTION_ARGS); /* from oraguc.c */ extern void PGDLLEXPORT _PG_init(void); /* from charpad.c */ extern PGDLLEXPORT Datum orafce_lpad(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum orafce_rpad(PG_FUNCTION_ARGS); /* from charlen.c */ extern PGDLLEXPORT Datum orafce_bpcharlen(PG_FUNCTION_ARGS); /* from varchar2.c */ extern PGDLLEXPORT Datum varchar2in(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum varchar2out(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum varchar2(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum varchar2recv(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum orafce_concat2(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum orafce_varchar_transform(PG_FUNCTION_ARGS); /* from nvarchar2.c */ extern PGDLLEXPORT Datum nvarchar2in(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum nvarchar2out(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum nvarchar2(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum nvarchar2recv(PG_FUNCTION_ARGS); #endif orafce-VERSION_3_9_0/charlen.c000066400000000000000000000016231362147214200161150ustar00rootroot00000000000000/* * charlen.c * * provides a modified version of bpcharlen() that does not * ignore trailing spaces of CHAR arguments to provide an * Oracle compatible length() function */ #include "postgres.h" #include "utils/builtins.h" #include "access/hash.h" #include "access/tuptoaster.h" #include "libpq/pqformat.h" #include "nodes/nodeFuncs.h" #include "utils/array.h" #include "utils/formatting.h" #include "mb/pg_wchar.h" #include "fmgr.h" #include "orafce.h" #include "builtins.h" PG_FUNCTION_INFO_V1(orafce_bpcharlen); Datum orafce_bpcharlen(PG_FUNCTION_ARGS) { BpChar *arg = PG_GETARG_BPCHAR_PP(0); int len; /* byte-length of the argument (trailing spaces not ignored) */ len = VARSIZE_ANY_EXHDR(arg); /* in multibyte encoding, convert to number of characters */ if (pg_database_encoding_max_length() != 1) len = pg_mbstrlen_with_len(VARDATA_ANY(arg), len); PG_RETURN_INT32(len); } orafce-VERSION_3_9_0/charpad.c000066400000000000000000000237351362147214200161130ustar00rootroot00000000000000/*---------------------------------------------------------------------------- * * charpad.c * LPAD and RPAD SQL functions for PostgreSQL. * *---------------------------------------------------------------------------- */ #include "postgres.h" #include "utils/builtins.h" #include "utils/formatting.h" #include "mb/pg_wchar.h" #include "fmgr.h" #include "orafce.h" #include "builtins.h" /* flags */ #define ON true #define OFF false /* Upper limit on total width of the padded output of *pad functions */ #define PAD_MAX 4000 PG_FUNCTION_INFO_V1(orafce_lpad); PG_FUNCTION_INFO_V1(orafce_rpad); /* * orafce_lpad(string text, length int32 [, fill text]) * * Fill up the string to length 'length' by prepending * the characters fill (a half-width space by default) */ Datum orafce_lpad(PG_FUNCTION_ARGS) { text *string1 = PG_GETARG_TEXT_PP(0); int32 output_width = PG_GETARG_INT32(1); text *string2 = PG_GETARG_TEXT_PP(2); text *ret; char *ptr1, *ptr2 = NULL, *ptr2start = NULL, *ptr2end = NULL, *ptr_ret, *spc = " "; int mlen, dsplen, s1blen, s2blen, hslen, total_blen = 0, s1_width = 0, s2_add_width = 0, s1_add_blen = 0, s2_add_blen = 0; bool s2_operate = ON, half_space = OFF, init_ptr = ON; /* validate output width (the 2nd argument) */ if (output_width < 0) output_width = 0; if (output_width > PAD_MAX) output_width = PAD_MAX; /* get byte-length of the 1st and 3rd argument strings */ s1blen = VARSIZE_ANY_EXHDR(string1); s2blen = VARSIZE_ANY_EXHDR(string2); /* validate the lengths */ if (s1blen < 0) s1blen = 0; if (s2blen < 0) s2blen = 0; /* if the filler length is zero disable filling */ if (s2blen == 0) { s2_operate = OFF; /* turn off string2 processing flag */ output_width = 0; /* same behavior as Oracle database */ } /* byte-length of half-width space */ hslen = pg_mblen(spc); /* * Calculate the length of the portion of string1 to include in * the final output */ ptr1 = VARDATA_ANY(string1); while (s1blen > 0) { /* byte-length and display length per character of string1 */ mlen = pg_mblen(ptr1); dsplen = pg_dsplen(ptr1); /* accumulate display length of string1 */ s1_width += dsplen; /* * if string1 is longer/wider than the requested output_width, * discard this character and prepend a half-width space instead */ if(s1_width >= output_width) { if(s1_width != output_width) { /* secure bytes for a half-width space in the final output */ if (output_width != 0) { s1_add_blen += hslen; half_space = ON; } } else /* exactly fits, so include this chracter */ { s1_add_blen += mlen; } /* * turn off string2 processing because string1 already * consumed output_width */ s2_operate = OFF; /* done with string1 */ break; } /* accumulate string1's portion of byte-length of the output */ s1_add_blen += mlen; /* advance one character within string1 */ ptr1 += mlen; /* loop counter */ s1blen -= mlen; } /* Calculate the length of the portion composed of string2 to use for padding */ if (s2_operate) { /* remaining part of output_width is composed of string2 */ s2_add_width = output_width - s1_width; ptr2 = ptr2start = VARDATA_ANY(string2); ptr2end = ptr2 + s2blen; while (s2_add_width > 0) { /* byte-length and display length per character of string2 */ mlen = pg_mblen(ptr2); dsplen = pg_dsplen(ptr2); /* * output_width can not fit this character of string2, so discard it and * prepend a half-width space instead */ if(dsplen > s2_add_width) { s2_add_blen += hslen; half_space = ON; /* done with string2 */ break; } /* accumulate string2's portion of byte-length of the output */ s2_add_blen += mlen; /* loop counter */ s2_add_width -= dsplen; /* advance one character within string2 */ ptr2 += mlen; /* when get to the end of string2, reset ptr2 to the start */ if (ptr2 == ptr2end) ptr2 = ptr2start; } } /* allocate enough space to contain output_width worth of characters */ total_blen = s1_add_blen + s2_add_blen; ret = (text *) palloc(VARHDRSZ + total_blen); ptr_ret = VARDATA(ret); /* * add a half-width space as a padding necessary to satisfy the required * output_width * * (memory already allocated as reserved by either s1_add_blen * or s2_add_blen) */ if (half_space) { memcpy(ptr_ret, spc, hslen); ptr_ret += hslen; } /* prepend string2 padding */ while(s2_add_blen > 0) { /* reset ptr2 to the string2 start */ if(init_ptr) { init_ptr = OFF; ptr2 = ptr2start; } mlen = pg_mblen(ptr2); if ( s2_add_blen < mlen ) break; memcpy(ptr_ret, ptr2, mlen); ptr_ret += mlen; ptr2 += mlen; /* loop counter */ s2_add_blen -= mlen; /* when get to the end of string2, reset ptr2 back to the start */ if (ptr2 == ptr2end) ptr2 = ptr2start; } init_ptr = ON; /* string1 */ while(s1_add_blen > 0) { /* reset ptr1 back to the start of string1 */ if(init_ptr) { init_ptr = OFF; ptr1 = VARDATA_ANY(string1); } mlen = pg_mblen(ptr1); if( s1_add_blen < mlen ) break; memcpy(ptr_ret, ptr1, mlen); ptr_ret += mlen; ptr1 += mlen; /* loop counter */ s1_add_blen -= mlen; } SET_VARSIZE(ret, ptr_ret - (char *) ret); PG_RETURN_TEXT_P(ret); } /* * orafce_rpad(string text, length int32 [, fill text]) * * Fill up the string to length 'length' by appending * the characters fill (a half-width space by default) */ Datum orafce_rpad(PG_FUNCTION_ARGS) { text *string1 = PG_GETARG_TEXT_PP(0); int32 output_width = PG_GETARG_INT32(1); text *string2 = PG_GETARG_TEXT_PP(2); text *ret; char *ptr1, *ptr2 = NULL, *ptr2start = NULL, *ptr2end = NULL, *ptr_ret, *spc = " "; int mlen, dsplen, s1blen, s2blen, hslen, total_blen = 0, s1_width = 0, s2_add_width = 0, s1_add_blen = 0, s2_add_blen = 0; bool s2_operate = ON, half_space = OFF, init_ptr = ON; /* validate output width (the 2nd argument) */ if (output_width < 0) output_width = 0; if (output_width > PAD_MAX) output_width = PAD_MAX; /* get byte-length of the 1st and 3rd argument strings */ s1blen = VARSIZE_ANY_EXHDR(string1); s2blen = VARSIZE_ANY_EXHDR(string2); /* validate the lengths */ if (s1blen < 0) s1blen = 0; if (s2blen < 0) s2blen = 0; /* if the filler length is zero disable filling */ if (s2blen == 0) { s2_operate = OFF; /* turn off string2 processing flag */ output_width = 0; /* same behavior as Oracle database */ } /* byte-length of half-width space */ hslen = pg_mblen(spc); /* * Calculate the length of the portion of string1 to include in * the final output */ ptr1 = VARDATA_ANY(string1); while (s1blen > 0) { /* byte-length and display length per character of string1 */ mlen = pg_mblen(ptr1); dsplen = pg_dsplen(ptr1); /* accumulate display length of string1 */ s1_width += dsplen; /* * if string1 is longer/wider than the requested output_width, * discard this character and prepend a half-width space instead */ if(s1_width >= output_width) { if(s1_width != output_width) { /* secure bytes for a half-width space in the final output */ if (output_width != 0) { s1_add_blen += hslen; half_space = ON; } } else /* exactly fits, so include this chracter */ { s1_add_blen += mlen; } /* * turn off string2 processing because string1 already * consumed output_width */ s2_operate = OFF; /* done with string1 */ break; } /* accumulate string1's portion of byte-length of the output */ s1_add_blen += mlen; /* advance one character within string1 */ ptr1 += mlen; /* loop counter */ s1blen -= mlen; } /* Calculate the length of the portion composed of string2 to use for padding */ if (s2_operate) { /* remaining part of output_width is composed of string2 */ s2_add_width = output_width - s1_width; ptr2 = ptr2start = VARDATA_ANY(string2); ptr2end = ptr2 + s2blen; while (s2_add_width > 0) { /* byte-length and display length per character of string2 */ mlen = pg_mblen(ptr2); dsplen = pg_dsplen(ptr2); /* * output_width can not fit this character of string2, so discard it and * prepend a half-width space instead */ if(dsplen > s2_add_width) { s2_add_blen += hslen; half_space = ON; /* done with string2 */ break; } /* accumulate string2's portion of byte-length of the output */ s2_add_blen += mlen; /* loop counter */ s2_add_width -= dsplen; /* advance one character within string2 */ ptr2 += mlen; /* when get to the end of string2, reset ptr2 to the start */ if (ptr2 == ptr2end) ptr2 = ptr2start; } } /* allocate enough space to contain output_width worth of characters */ total_blen = s1_add_blen + s2_add_blen; ret = (text *) palloc(VARHDRSZ + total_blen); ptr_ret = VARDATA(ret); /* string1 */ while(s1_add_blen > 0) { /* reset ptr1 back to the start of string1 */ if(init_ptr) { init_ptr = OFF; ptr1 = VARDATA_ANY(string1); } mlen = pg_mblen(ptr1); if( s1_add_blen < mlen ) break; memcpy(ptr_ret, ptr1, mlen); ptr_ret += mlen; ptr1 += mlen; /* loop counter */ s1_add_blen -= mlen; } init_ptr = ON; /* append string2 padding */ while(s2_add_blen > 0) { /* reset ptr2 to the string2 start */ if(init_ptr) { init_ptr = OFF; ptr2 = ptr2start; } mlen = pg_mblen(ptr2); if ( s2_add_blen < mlen ) break; memcpy(ptr_ret, ptr2, mlen); ptr_ret += mlen; ptr2 += mlen; /* loop counter */ s2_add_blen -= mlen; /* when get to the end of string2, reset ptr2 back to the start */ if (ptr2 == ptr2end) ptr2 = ptr2start; } /* * add a half-width space as a padding necessary to satisfy the required * output_width * * (memory already allocated as reserved by either s1_add_blen * or s2_add_blen) */ if (half_space) { memcpy(ptr_ret, spc, hslen); ptr_ret += hslen; } SET_VARSIZE(ret, ptr_ret - (char *) ret); PG_RETURN_TEXT_P(ret); } orafce-VERSION_3_9_0/convert.c000066400000000000000000000231671362147214200161700ustar00rootroot00000000000000#include #include "postgres.h" #include "fmgr.h" #include "lib/stringinfo.h" #include "mb/pg_wchar.h" #include "utils/builtins.h" #include "utils/numeric.h" #include "utils/pg_locale.h" #include "utils/formatting.h" #include "orafce.h" #include "builtins.h" PG_FUNCTION_INFO_V1(orafce_to_char_int4); PG_FUNCTION_INFO_V1(orafce_to_char_int8); PG_FUNCTION_INFO_V1(orafce_to_char_float4); PG_FUNCTION_INFO_V1(orafce_to_char_float8); PG_FUNCTION_INFO_V1(orafce_to_char_numeric); PG_FUNCTION_INFO_V1(orafce_to_char_timestamp); PG_FUNCTION_INFO_V1(orafce_to_number); PG_FUNCTION_INFO_V1(orafce_to_multi_byte); PG_FUNCTION_INFO_V1(orafce_to_single_byte); static int getindex(const char **map, char *mbchar, int mblen); Datum orafce_to_char_int4(PG_FUNCTION_ARGS) { int32 arg0 = PG_GETARG_INT32(0); StringInfo buf = makeStringInfo(); appendStringInfo(buf, "%d", arg0); PG_RETURN_TEXT_P(cstring_to_text(buf->data)); } Datum orafce_to_char_int8(PG_FUNCTION_ARGS) { int64 arg0 = PG_GETARG_INT64(0); StringInfo buf = makeStringInfo(); appendStringInfo(buf, INT64_FORMAT, arg0); PG_RETURN_TEXT_P(cstring_to_text(buf->data)); } Datum orafce_to_char_float4(PG_FUNCTION_ARGS) { char *p; char *result; struct lconv *lconv = PGLC_localeconv(); result = DatumGetCString(DirectFunctionCall1(float4out, PG_GETARG_DATUM(0))); for (p = result; *p; p++) if (*p == '.') *p = lconv->decimal_point[0]; PG_RETURN_TEXT_P(cstring_to_text(result)); } Datum orafce_to_char_float8(PG_FUNCTION_ARGS) { char *p; char *result; struct lconv *lconv = PGLC_localeconv(); result = DatumGetCString(DirectFunctionCall1(float8out, PG_GETARG_DATUM(0))); for (p = result; *p; p++) if (*p == '.') *p = lconv->decimal_point[0]; PG_RETURN_TEXT_P(cstring_to_text(result)); } Datum orafce_to_char_numeric(PG_FUNCTION_ARGS) { Numeric arg0 = PG_GETARG_NUMERIC(0); StringInfo buf = makeStringInfo(); struct lconv *lconv = PGLC_localeconv(); char *p; char *decimal = NULL; appendStringInfoString(buf, DatumGetCString(DirectFunctionCall1(numeric_out, NumericGetDatum(arg0)))); for (p = buf->data; *p; p++) if (*p == '.') { *p = lconv->decimal_point[0]; decimal = p; /* save decimal point position for the next loop */ } /* Simulate the default Oracle to_char template (TM9 - Text Minimum) by removing unneeded digits after the decimal point; if no digits are left, then remove the decimal point too */ for (p = buf->data + buf->len - 1; decimal && p >= decimal; p--) { if (*p == '0' || *p == lconv->decimal_point[0]) *p = 0; else break; /* non-zero digit found, exit the loop */ } PG_RETURN_TEXT_P(cstring_to_text(buf->data)); } /******************************************************************** * * orafec_to_char_timestamp * * Syntax: * * text to_date(timestamp date_txt) * * Purpose: * * Returns date and time format w.r.t NLS_DATE_FORMAT GUC * *********************************************************************/ Datum orafce_to_char_timestamp(PG_FUNCTION_ARGS) { Timestamp ts = PG_GETARG_TIMESTAMP(0); text *result = NULL; if(nls_date_format && strlen(nls_date_format) > 0) { /* it will return the DATE in nls_date_format*/ result = DatumGetTextP(DirectFunctionCall2(timestamp_to_char, TimestampGetDatum(ts), CStringGetDatum(cstring_to_text(nls_date_format)))); } else { result = cstring_to_text(DatumGetCString(DirectFunctionCall1(timestamp_out, TimestampGetDatum(ts)))); } PG_RETURN_TEXT_P(result); } Datum orafce_to_number(PG_FUNCTION_ARGS) { text *arg0 = PG_GETARG_TEXT_PP(0); char *buf; struct lconv *lconv = PGLC_localeconv(); Numeric res; char *p; buf = text_to_cstring(arg0); for (p = buf; *p; p++) if (*p == lconv->decimal_point[0] && lconv->decimal_point[0]) *p = '.'; else if (*p == lconv->thousands_sep[0] && lconv->thousands_sep[0]) *p = ','; res = DatumGetNumeric(DirectFunctionCall3(numeric_in, CStringGetDatum(buf), 0, -1)); PG_RETURN_NUMERIC(res); } /* 3 is enough, but it is defined as 4 in backend code. */ #ifndef MAX_CONVERSION_GROWTH #define MAX_CONVERSION_GROWTH 4 #endif /* * Convert a tilde (~) to ... * 1: a full width tilde. (same as JA16EUCTILDE in oracle) * 0: a full width overline. (same as JA16EUC in oracle) */ #define JA_TO_FULL_WIDTH_TILDE 1 static const char * TO_MULTI_BYTE_UTF8[95] = { "\343\200\200", "\357\274\201", "\342\200\235", "\357\274\203", "\357\274\204", "\357\274\205", "\357\274\206", "\342\200\231", "\357\274\210", "\357\274\211", "\357\274\212", "\357\274\213", "\357\274\214", "\357\274\215", "\357\274\216", "\357\274\217", "\357\274\220", "\357\274\221", "\357\274\222", "\357\274\223", "\357\274\224", "\357\274\225", "\357\274\226", "\357\274\227", "\357\274\230", "\357\274\231", "\357\274\232", "\357\274\233", "\357\274\234", "\357\274\235", "\357\274\236", "\357\274\237", "\357\274\240", "\357\274\241", "\357\274\242", "\357\274\243", "\357\274\244", "\357\274\245", "\357\274\246", "\357\274\247", "\357\274\250", "\357\274\251", "\357\274\252", "\357\274\253", "\357\274\254", "\357\274\255", "\357\274\256", "\357\274\257", "\357\274\260", "\357\274\261", "\357\274\262", "\357\274\263", "\357\274\264", "\357\274\265", "\357\274\266", "\357\274\267", "\357\274\270", "\357\274\271", "\357\274\272", "\357\274\273", "\357\277\245", "\357\274\275", "\357\274\276", "\357\274\277", "\342\200\230", "\357\275\201", "\357\275\202", "\357\275\203", "\357\275\204", "\357\275\205", "\357\275\206", "\357\275\207", "\357\275\210", "\357\275\211", "\357\275\212", "\357\275\213", "\357\275\214", "\357\275\215", "\357\275\216", "\357\275\217", "\357\275\220", "\357\275\221", "\357\275\222", "\357\275\223", "\357\275\224", "\357\275\225", "\357\275\226", "\357\275\227", "\357\275\230", "\357\275\231", "\357\275\232", "\357\275\233", "\357\275\234", "\357\275\235", #if JA_TO_FULL_WIDTH_TILDE "\357\275\236" #else "\357\277\243" #endif }; static const char * TO_MULTI_BYTE_EUCJP[95] = { "\241\241", "\241\252", "\241\311", "\241\364", "\241\360", "\241\363", "\241\365", "\241\307", "\241\312", "\241\313", "\241\366", "\241\334", "\241\244", "\241\335", "\241\245", "\241\277", "\243\260", "\243\261", "\243\262", "\243\263", "\243\264", "\243\265", "\243\266", "\243\267", "\243\270", "\243\271", "\241\247", "\241\250", "\241\343", "\241\341", "\241\344", "\241\251", "\241\367", "\243\301", "\243\302", "\243\303", "\243\304", "\243\305", "\243\306", "\243\307", "\243\310", "\243\311", "\243\312", "\243\313", "\243\314", "\243\315", "\243\316", "\243\317", "\243\320", "\243\321", "\243\322", "\243\323", "\243\324", "\243\325", "\243\326", "\243\327", "\243\330", "\243\331", "\243\332", "\241\316", "\241\357", "\241\317", "\241\260", "\241\262", "\241\306", "\243\341", "\243\342", "\243\343", "\243\344", "\243\345", "\243\346", "\243\347", "\243\350", "\243\351", "\243\352", "\243\353", "\243\354", "\243\355", "\243\356", "\243\357", "\243\360", "\243\361", "\243\362", "\243\363", "\243\364", "\243\365", "\243\366", "\243\367", "\243\370", "\243\371", "\243\372", "\241\320", "\241\303", "\241\321", #if JA_TO_FULL_WIDTH_TILDE "\241\301" #else "\241\261" #endif }; Datum orafce_to_multi_byte(PG_FUNCTION_ARGS) { text *src; text *dst; const char *s; char *d; int srclen; #if defined(_MSC_VER) && (defined(_M_X64) || defined(__amd64__)) __int64 dstlen; #else int dstlen; #endif int i; const char **map; switch (GetDatabaseEncoding()) { case PG_UTF8: map = TO_MULTI_BYTE_UTF8; break; case PG_EUC_JP: case PG_EUC_JIS_2004: map = TO_MULTI_BYTE_EUCJP; break; /* * TODO: Add converter for encodings. */ default: /* no need to convert */ PG_RETURN_DATUM(PG_GETARG_DATUM(0)); } src = PG_GETARG_TEXT_PP(0); s = VARDATA_ANY(src); srclen = VARSIZE_ANY_EXHDR(src); dst = (text *) palloc(VARHDRSZ + srclen * MAX_CONVERSION_GROWTH); d = VARDATA(dst); for (i = 0; i < srclen; i++) { unsigned char u = (unsigned char) s[i]; if (0x20 <= u && u <= 0x7e) { const char *m = map[u - 0x20]; while (*m) { *d++ = *m++; } } else { *d++ = s[i]; } } dstlen = d - VARDATA(dst); SET_VARSIZE(dst, VARHDRSZ + dstlen); PG_RETURN_TEXT_P(dst); } static int getindex(const char **map, char *mbchar, int mblen) { int i; for (i = 0; i < 95; i++) { if (!memcmp(map[i], mbchar, mblen)) return i; } return -1; } Datum orafce_to_single_byte(PG_FUNCTION_ARGS) { text *src; text *dst; char *s; char *d; int srclen; #if defined(_MSC_VER) && (defined(_M_X64) || defined(__amd64__)) __int64 dstlen; #else int dstlen; #endif const char **map; switch (GetDatabaseEncoding()) { case PG_UTF8: map = TO_MULTI_BYTE_UTF8; break; case PG_EUC_JP: case PG_EUC_JIS_2004: map = TO_MULTI_BYTE_EUCJP; break; /* * TODO: Add converter for encodings. */ default: /* no need to convert */ PG_RETURN_DATUM(PG_GETARG_DATUM(0)); } src = PG_GETARG_TEXT_PP(0); s = VARDATA_ANY(src); srclen = VARSIZE_ANY_EXHDR(src); /* XXX - The output length should be <= input length */ dst = (text *) palloc0(VARHDRSZ + srclen); d = VARDATA(dst); while (*s && (s - VARDATA_ANY(src) < srclen)) { char *u = s; int clen; int mapindex; clen = pg_mblen(u); s += clen; if (clen == 1) *d++ = *u; else if ((mapindex = getindex(map, u, clen)) >= 0) { const char m = 0x20 + mapindex; *d++ = m; } else { memcpy(d, u, clen); d += clen; } } dstlen = d - VARDATA(dst); SET_VARSIZE(dst, VARHDRSZ + dstlen); PG_RETURN_TEXT_P(dst); } orafce-VERSION_3_9_0/datefce.c000066400000000000000000000552131362147214200161000ustar00rootroot00000000000000#include "postgres.h" #include "access/xact.h" #include "commands/variable.h" #include "mb/pg_wchar.h" #include "utils/date.h" #include "utils/builtins.h" #include "utils/numeric.h" #include "utils/formatting.h" #include #include "orafce.h" #include "builtins.h" #define ENABLE_INTERNATIONALIZED_WEEKDAY #ifdef ENABLE_INTERNATIONALIZED_WEEKDAY typedef struct WeekDays { int encoding; const char *names[7]; } WeekDays; /* * { encoding, { "sun", "mon", "tue", "wed", "thu", "fri", "sat" } }, */ static const WeekDays WEEKDAYS[] = { /* Japanese, UTF8 */ { PG_UTF8, { "\346\227\245", "\346\234\210", "\347\201\253", "\346\260\264", "\346\234\250", "\351\207\221", "\345\234\237" } }, /* Japanese, EUC_JP */ { PG_EUC_JP, { "\306\374", "\267\356", "\262\320", "\277\345", "\314\332", "\266\342", "\305\332" } }, /* Japanese, EUC_JIS_2004 (same as EUC_JP) */ { PG_EUC_JIS_2004, { "\306\374", "\267\356", "\262\320", "\277\345", "\314\332", "\266\342", "\305\332" } }, }; static const WeekDays *mru_weekdays = NULL; static int weekday_search(const WeekDays *weekdays, const char *str, int len) { int i; for (i = 0; i < 7; i++) { size_t n = strlen(weekdays->names[i]); if (n > len) continue; /* too short */ if (pg_strncasecmp(weekdays->names[i], str, n) == 0) return i; } return -1; /* not found */ } #endif /* ENABLE_INTERNATIONALIZED_WEEKDAY */ #define CASE_fmt_YYYY case 0: case 1: case 2: case 3: case 4: case 5: case 6: #define CASE_fmt_IYYY case 7: case 8: case 9: case 10: #define CASE_fmt_Q case 11: #define CASE_fmt_WW case 12: #define CASE_fmt_IW case 13: #define CASE_fmt_W case 14: #define CASE_fmt_DAY case 15: case 16: case 17: #define CASE_fmt_MON case 18: case 19: case 20: case 21: #define CASE_fmt_CC case 22: case 23: #define CASE_fmt_DDD case 24: case 25: case 26: #define CASE_fmt_HH case 27: case 28: case 29: #define CASE_fmt_MI case 30: STRING_PTR_FIELD_TYPE date_fmt[] = { "Y", "Yy", "Yyy", "Yyyy", "Year", "Syyyy", "syear", "I", "Iy", "Iyy", "Iyyy", "Q", "Ww", "Iw", "W", "Day", "Dy", "D", "Month", "Mon", "Mm", "Rm", "Cc", "Scc", "Ddd", "Dd", "J", "Hh", "Hh12", "Hh24", "Mi", NULL }; STRING_PTR_FIELD_TYPE ora_days[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", NULL}; #define CHECK_SEQ_SEARCH(_l, _s) \ do { \ if ((_l) < 0) { \ ereport(ERROR, \ (errcode(ERRCODE_INVALID_DATETIME_FORMAT), \ errmsg("invalid value for %s", (_s)))); \ } \ } while (0) PG_FUNCTION_INFO_V1(next_day); PG_FUNCTION_INFO_V1(next_day_by_index); PG_FUNCTION_INFO_V1(last_day); PG_FUNCTION_INFO_V1(months_between); PG_FUNCTION_INFO_V1(add_months); PG_FUNCTION_INFO_V1(ora_to_date); PG_FUNCTION_INFO_V1(ora_date_trunc); PG_FUNCTION_INFO_V1(ora_date_round); PG_FUNCTION_INFO_V1(ora_timestamptz_trunc); PG_FUNCTION_INFO_V1(ora_timestamptz_round); PG_FUNCTION_INFO_V1(ora_timestamp_trunc); PG_FUNCTION_INFO_V1(ora_timestamp_round); PG_FUNCTION_INFO_V1(orafce_sysdate); PG_FUNCTION_INFO_V1(orafce_sessiontimezone); PG_FUNCTION_INFO_V1(orafce_dbtimezone); /* * Search const value in char array * */ int ora_seq_search(const char *name, STRING_PTR_FIELD_TYPE array[], int max) { int i; if (!*name) return -1; for (i = 0; array[i]; i++) { if (strlen(array[i]) == max && pg_strncasecmp(name, array[i], max) == 0) return i; } return -1; /* not found */ } static int ora_seq_prefix_search(const char *name, STRING_PTR_FIELD_TYPE array[], int max) { int i; if (!*name) return -1; for (i = 0; array[i]; i++) { if (pg_strncasecmp(name, array[i], max) == 0) return i; } return -1; /* not found */ } /******************************************************************** * * next_day * * Syntax: * * date next_day(date value, text weekday) * * Purpose: * * Returns the first weekday that is greater than a date value. * ********************************************************************/ Datum next_day(PG_FUNCTION_ARGS) { DateADT day = PG_GETARG_DATEADT(0); text *day_txt = PG_GETARG_TEXT_PP(1); const char *str = VARDATA_ANY(day_txt); int len = VARSIZE_ANY_EXHDR(day_txt); int off; int d = -1; #ifdef ENABLE_INTERNATIONALIZED_WEEKDAY /* Check mru_weekdays first for performance. */ if (mru_weekdays) { if ((d = weekday_search(mru_weekdays, str, len)) >= 0) goto found; else mru_weekdays = NULL; } #endif /* * Oracle uses only 3 heading characters of the input. * Ignore all trailing characters. */ if (len >= 3 && (d = ora_seq_prefix_search(str, ora_days, 3)) >= 0) goto found; #ifdef ENABLE_INTERNATIONALIZED_WEEKDAY do { int i; int encoding = GetDatabaseEncoding(); for (i = 0; i < lengthof(WEEKDAYS); i++) { if (encoding == WEEKDAYS[i].encoding) { if ((d = weekday_search(&WEEKDAYS[i], str, len)) >= 0) { mru_weekdays = &WEEKDAYS[i]; goto found; } } } } while(0); #endif CHECK_SEQ_SEARCH(-1, "DAY/Day/day"); found: off = d - j2day(day+POSTGRES_EPOCH_JDATE); PG_RETURN_DATEADT((off <= 0) ? day+off+7 : day + off); } /* next_day(date, integer) is not documented in Oracle manual, but ... */ Datum next_day_by_index(PG_FUNCTION_ARGS) { DateADT day = PG_GETARG_DATEADT(0); int idx = PG_GETARG_INT32(1); int off; /* * off is 1..7 (Sun..Sat). * * TODO: It should be affected by NLS_TERRITORY. For example, * 1..7 should be interpreted as Mon..Sun in GERMAN. */ CHECK_SEQ_SEARCH((idx < 1 || 7 < idx) ? -1 : 0, "DAY/Day/day"); /* j2day returns 0..6 as Sun..Sat */ off = (idx - 1) - j2day(day+POSTGRES_EPOCH_JDATE); PG_RETURN_DATEADT((off <= 0) ? day+off+7 : day + off); } /******************************************************************** * * last_day * * Syntax: * * date last_day(date value) * * Purpose: * * Returns last day of the month based on a date value * ********************************************************************/ Datum last_day(PG_FUNCTION_ARGS) { DateADT day = PG_GETARG_DATEADT(0); DateADT result; int y, m, d; j2date(day + POSTGRES_EPOCH_JDATE, &y, &m, &d); result = date2j(y, m+1, 1) - POSTGRES_EPOCH_JDATE; PG_RETURN_DATEADT(result - 1); } static const int month_days[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; static int days_of_month(int y, int m) { int days; if (m < 0 || 12 < m) ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("date out of range"))); days = month_days[m - 1]; if (m == 2 && (y % 400 == 0 || (y % 4 == 0 && y % 100 != 0))) days += 1; /* February 29 in leap year */ return days; } /******************************************************************** * * months_between * * Syntax: * * float8 months_between(date date1, date date2) * * Purpose: * * Returns the number of months between date1 and date2. If * a fractional month is calculated, the months_between function * calculates the fraction based on a 31-day month. * ********************************************************************/ Datum months_between(PG_FUNCTION_ARGS) { DateADT date1 = PG_GETARG_DATEADT(0); DateADT date2 = PG_GETARG_DATEADT(1); int y1, m1, d1; int y2, m2, d2; float8 result; j2date(date1 + POSTGRES_EPOCH_JDATE, &y1, &m1, &d1); j2date(date2 + POSTGRES_EPOCH_JDATE, &y2, &m2, &d2); /* Ignore day components for last days, or based on a 31-day month. */ if (d1 == days_of_month(y1, m1) && d2 == days_of_month(y2, m2)) result = (y1 - y2) * 12 + (m1 - m2); else result = (y1 - y2) * 12 + (m1 - m2) + (d1 - d2) / 31.0; PG_RETURN_NUMERIC( DirectFunctionCall1(float8_numeric, Float8GetDatumFast(result))); } /******************************************************************** * * add_months * * Syntax: * * date add_months(date day, int val) * * Purpose: * * Returns a date plus n months. * ********************************************************************/ Datum add_months(PG_FUNCTION_ARGS) { DateADT day = PG_GETARG_DATEADT(0); int n = PG_GETARG_INT32(1); int y, m, d; int days; DateADT result; div_t v; bool last_day; j2date(day + POSTGRES_EPOCH_JDATE, &y, &m, &d); last_day = (d == days_of_month(y, m)); v = div(y * 12 + m - 1 + n, 12); y = v.quot; if (y < 0) y += 1; /* offset because of year 0 */ m = v.rem + 1; days = days_of_month(y, m); if (last_day || d > days) d = days; result = date2j(y, m, d) - POSTGRES_EPOCH_JDATE; PG_RETURN_DATEADT (result); } /* * ISO year * */ #define DATE2J(y,m,d) (date2j((y),(m),(d)) - POSTGRES_EPOCH_JDATE) #define J2DAY(date) (j2day(date + POSTGRES_EPOCH_JDATE)) static DateADT iso_year (int y, int m, int d) { DateADT result, result2, day; int off; result = DATE2J(y,1,1); day = DATE2J(y,m,d); off = 4 - J2DAY(result); result += off + ((off >= 0) ? - 3: + 4); /* to monday */ if (result > day) { result = DATE2J(y-1,1,1); off = 4 - J2DAY(result); result += off + ((off >= 0) ? - 3: + 4); /* to monday */ } if (((day - result) / 7 + 1) > 52) { result2 = DATE2J(y+1,1,1); off = 4 - J2DAY(result2); result2 += off + ((off >= 0) ? - 3: + 4); /* to monday */ if (day >= result2) return result2; } return result; } static DateADT _ora_date_trunc(DateADT day, int f) { int y, m, d; DateADT result; j2date(day + POSTGRES_EPOCH_JDATE, &y, &m, &d); switch (f) { CASE_fmt_CC if (y > 0) result = DATE2J((y/100)*100+1,1,1); else result = DATE2J(-((99 - (y - 1)) / 100) * 100 + 1,1,1); break; CASE_fmt_YYYY result = DATE2J(y,1,1); break; CASE_fmt_IYYY result = iso_year(y,m,d); break; CASE_fmt_MON result = DATE2J(y,m,1); break; CASE_fmt_WW result = day - (day - DATE2J(y,1,1)) % 7; break; CASE_fmt_IW result = day - (day - iso_year(y,m,d)) % 7; break; CASE_fmt_W result = day - (day - DATE2J(y,m,1)) % 7; break; CASE_fmt_DAY result = day - J2DAY(day); break; CASE_fmt_Q result = DATE2J(y,((m-1)/3)*3+1,1); break; default: result = day; } return result; } static DateADT _ora_date_round(DateADT day, int f) { int y, m, d, z; DateADT result; j2date(day + POSTGRES_EPOCH_JDATE, &y, &m, &d); switch (f) { CASE_fmt_CC if (y > 0) result = DATE2J((y/100)*100+(day < DATE2J((y/100)*100+50,1,1) ?1:101),1,1); else result = DATE2J((y/100)*100+(day < DATE2J((y/100)*100-50+1,1,1) ?-99:1),1,1); break; CASE_fmt_YYYY result = DATE2J(y+(day= 52) { bool overl = ((date2j(y+2,1,1)-date2j(y+1,1,1)) == 366); bool isSaturday = (J2DAY(day) == 6); DateADT iy2 = iso_year(y+2, 1, 8); DateADT day1 = DATE2J(y+1,1,1); /* exception saturdays */ if (iy1 >= (day1) && day >= day1 - 2 && isSaturday) { result = overl?iy2:iy1; } /* iso year stars in last year and day >= iso year */ else if (iy1 <= (day1) && day >= iy1 - 3) { DateADT cmp = iy1 - (iy1 < day1?0:1); int d = J2DAY(day1); /* some exceptions */ if ((day >= cmp - 2) && (!(d == 3 && overl))) { /* if year don't starts in thursday */ if ((d < 4 && J2DAY(day) != 5 && !isSaturday) ||(d == 2 && isSaturday && overl)) { result = iy2; } } } } } break; } CASE_fmt_MON result = DATE2J(y,m+(day= 52) { /* only for last iso week */ DateADT isoyear = iso_year(y+1, 1, 8); if (isoyear > (DATE2J(y+1,1,1)-1)) if (day > isoyear - 7) { int d = J2DAY(day); result -= (d == 0 || d > 4?7:0); } } break; } CASE_fmt_W z = (day - DATE2J(y,m,1)) % 7; result = day - z + (z < 4?0:7); break; CASE_fmt_DAY z = J2DAY(day); if (y > 0) result = day - z + (z < 4?0:7); else result = day + (5 - (z>0?(z>1?z:z+7):7)); break; CASE_fmt_Q result = DATE2J(y,((m-1)/3)*3+(day<(DATE2J(y,((m-1)/3)*3+2,16))?1:4),1); break; default: result = day; } return result; } /******************************************************************** * * ora_to_date * * Syntax: * * timestamp to_date(text date_txt) * * Purpose: * * Returns date and time format w.r.t NLS_DATE_FORMAT GUC * ********************************************************************/ Datum ora_to_date(PG_FUNCTION_ARGS) { text *date_txt = PG_GETARG_TEXT_PP(0); Timestamp result; if(nls_date_format && strlen(nls_date_format)) { Datum newDate; /* it will return timestamp at GMT */ newDate = DirectFunctionCall2(to_timestamp, CStringGetDatum(date_txt), CStringGetDatum(cstring_to_text(nls_date_format))); /* convert to local timestamp */ result = DatumGetTimestamp(DirectFunctionCall1(timestamptz_timestamp, newDate)); } else result = DatumGetTimestamp(DirectFunctionCall3(timestamp_in, CStringGetDatum(text_to_cstring(date_txt)), ObjectIdGetDatum(InvalidOid), Int32GetDatum(-1))); PG_RETURN_TIMESTAMP(result); } /******************************************************************** * * ora_date_trunc|ora_timestamptz_trunc .. trunc * * Syntax: * * date trunc(date date1, text format) * * Purpose: * * Returns d with the time portion of the day truncated to the unit * specified by the format fmt. * ********************************************************************/ Datum ora_date_trunc(PG_FUNCTION_ARGS) { DateADT day = PG_GETARG_DATEADT(0); text *fmt = PG_GETARG_TEXT_PP(1); DateADT result; int f = ora_seq_search(VARDATA_ANY(fmt), date_fmt, VARSIZE_ANY_EXHDR(fmt)); CHECK_SEQ_SEARCH(f, "round/trunc format string"); result = _ora_date_trunc(day, f); PG_RETURN_DATEADT(result); } /* * Workaround for access to session_timezone on WIN32, * * session timezone isn't accessed directly, but taken by show_timezone, * and reparsed. For better performance, the result is cached in fn_extra. * */ static pg_tz * get_session_timezone(FunctionCallInfo fcinfo) { #if defined(WIN32) pg_tz *result = (pg_tz *) fcinfo->flinfo->fn_extra; if (result == NULL) { const char *tzn = show_timezone(); void *extra; if (!check_timezone(((char **) &tzn), &extra, PGC_S_CLIENT)) elog(ERROR, "cannot to parse timezone \"%s\"", tzn); result = *((pg_tz **) extra); fcinfo->flinfo->fn_extra = result; /* * check_timezone allocates small block of pg_tz * size. This block * should be released by free(extra), but I cannot release memory * allocated by application in library on MS platform. So I have to * accept small memory leak - elsewhere exception - broken heap :( * * * cannot be called free( extra ); */ } return result; #else return session_timezone; #endif } /* * redotz is used only for timestamp with time zone */ static void tm_trunc(struct pg_tm *tm, text *fmt, bool *redotz) { int f; f = ora_seq_search(VARDATA_ANY(fmt), date_fmt, VARSIZE_ANY_EXHDR(fmt)); CHECK_SEQ_SEARCH(f, "round/trunc format string"); tm->tm_sec = 0; switch (f) { CASE_fmt_IYYY CASE_fmt_WW CASE_fmt_W CASE_fmt_IW CASE_fmt_DAY CASE_fmt_CC j2date(_ora_date_trunc(DATE2J(tm->tm_year, tm->tm_mon, tm->tm_mday), f) + POSTGRES_EPOCH_JDATE, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); tm->tm_hour = 0; tm->tm_min = 0; *redotz = true; break; CASE_fmt_YYYY tm->tm_mon = 1; CASE_fmt_Q tm->tm_mon = (3*((tm->tm_mon - 1)/3)) + 1; CASE_fmt_MON tm->tm_mday = 1; CASE_fmt_DDD tm->tm_hour = 0; *redotz = true; /* for all cases >= DAY */ CASE_fmt_HH tm->tm_min = 0; } } Datum ora_timestamptz_trunc(PG_FUNCTION_ARGS) { TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0); TimestampTz result; text *fmt = PG_GETARG_TEXT_PP(1); int tz; fsec_t fsec; struct pg_tm tt, *tm = &tt; const char *tzn; bool redotz = false; if (TIMESTAMP_NOT_FINITE(timestamp)) PG_RETURN_TIMESTAMPTZ(timestamp); if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn, NULL) != 0) ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); tm_trunc(tm, fmt, &redotz); fsec = 0; if (redotz) tz = DetermineTimeZoneOffset(tm, get_session_timezone(fcinfo)); if (tm2timestamp(tm, fsec , &tz, &result) != 0) ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); PG_RETURN_TIMESTAMPTZ(result); } /******************************************************************** * * ora_date_round|ora_timestamptz_round .. round * * Syntax: * * date round(date date1, text format) * * Purpose: * * Returns d with the time portion of the day roundeded to the unit * specified by the format fmt. * ********************************************************************/ Datum ora_date_round(PG_FUNCTION_ARGS) { DateADT day = PG_GETARG_DATEADT(0); text *fmt = PG_GETARG_TEXT_PP(1); DateADT result; int f = ora_seq_search(VARDATA_ANY(fmt), date_fmt, VARSIZE_ANY_EXHDR(fmt)); CHECK_SEQ_SEARCH(f, "round/trunc format string"); result = _ora_date_round(day, f); PG_RETURN_DATEADT(result); } #define NOT_ROUND_MDAY(_p_) \ do { if (_p_) rounded = false; } while(0) #define ROUND_MDAY(_tm_) \ do { if (rounded) _tm_->tm_mday += _tm_->tm_hour >= 12?1:0; } while(0) static void tm_round(struct pg_tm *tm, text *fmt, bool *redotz) { int f; bool rounded = true; f = ora_seq_search(VARDATA_ANY(fmt), date_fmt, VARSIZE_ANY_EXHDR(fmt)); CHECK_SEQ_SEARCH(f, "round/trunc format string"); /* set rounding rule */ switch (f) { CASE_fmt_IYYY NOT_ROUND_MDAY(tm->tm_mday < 8 && tm->tm_mon == 1); NOT_ROUND_MDAY(tm->tm_mday == 30 && tm->tm_mon == 6); if (tm->tm_mday >= 28 && tm->tm_mon == 12 && tm->tm_hour >= 12) { DateADT isoyear = iso_year(tm->tm_year+1, 1, 8); DateADT day0 = DATE2J(tm->tm_year+1,1,1); DateADT dayc = DATE2J(tm->tm_year, tm->tm_mon, tm->tm_mday); if ((isoyear <= day0) || (day0 <= dayc + 2)) { rounded = false; } } break; CASE_fmt_YYYY NOT_ROUND_MDAY(tm->tm_mday == 30 && tm->tm_mon == 6); break; CASE_fmt_MON NOT_ROUND_MDAY(tm->tm_mday == 15); break; CASE_fmt_Q NOT_ROUND_MDAY(tm->tm_mday == 15 && tm->tm_mon == ((tm->tm_mon-1)/3)*3+2); break; CASE_fmt_WW CASE_fmt_IW /* last day in year */ NOT_ROUND_MDAY(DATE2J(tm->tm_year, tm->tm_mon, tm->tm_mday) == (DATE2J(tm->tm_year+1, 1,1) - 1)); break; CASE_fmt_W /* last day in month */ NOT_ROUND_MDAY(DATE2J(tm->tm_year, tm->tm_mon, tm->tm_mday) == (DATE2J(tm->tm_year, tm->tm_mon+1,1) - 1)); break; } switch (f) { /* easier convert to date */ CASE_fmt_IW CASE_fmt_DAY CASE_fmt_IYYY CASE_fmt_WW CASE_fmt_W CASE_fmt_CC CASE_fmt_MON CASE_fmt_YYYY CASE_fmt_Q ROUND_MDAY(tm); j2date(_ora_date_round(DATE2J(tm->tm_year, tm->tm_mon, tm->tm_mday), f) + POSTGRES_EPOCH_JDATE, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); tm->tm_hour = 0; tm->tm_min = 0; *redotz = true; break; CASE_fmt_DDD tm->tm_mday += (tm->tm_hour >= 12)?1:0; tm->tm_hour = 0; tm->tm_min = 0; *redotz = true; break; CASE_fmt_MI tm->tm_min += (tm->tm_sec >= 30)?1:0; break; CASE_fmt_HH tm->tm_hour += (tm->tm_min >= 30)?1:0; tm->tm_min = 0; break; } tm->tm_sec = 0; } Datum ora_timestamptz_round(PG_FUNCTION_ARGS) { TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0); TimestampTz result; text *fmt = PG_GETARG_TEXT_PP(1); int tz; fsec_t fsec; struct pg_tm tt, *tm = &tt; const char *tzn; bool redotz = false; if (TIMESTAMP_NOT_FINITE(timestamp)) PG_RETURN_TIMESTAMPTZ(timestamp); if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn, NULL) != 0) ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); tm_round(tm, fmt, &redotz); fsec = 0; if (redotz) tz = DetermineTimeZoneOffset(tm, get_session_timezone(fcinfo)); if (tm2timestamp(tm, fsec, &tz, &result) != 0) ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); PG_RETURN_TIMESTAMPTZ(result); } Datum ora_timestamp_trunc(PG_FUNCTION_ARGS) { Timestamp timestamp = PG_GETARG_TIMESTAMP(0); Timestamp result; text *fmt = PG_GETARG_TEXT_PP(1); fsec_t fsec; struct pg_tm tt, *tm = &tt; bool redotz = false; if (TIMESTAMP_NOT_FINITE(timestamp)) PG_RETURN_TIMESTAMP(timestamp); if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0) ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); tm_trunc(tm, fmt, &redotz); fsec = 0; if (tm2timestamp(tm, fsec, NULL, &result) != 0) ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); PG_RETURN_TIMESTAMP(result); } Datum ora_timestamp_round(PG_FUNCTION_ARGS) { Timestamp timestamp = PG_GETARG_TIMESTAMP(0); Timestamp result; text *fmt = PG_GETARG_TEXT_PP(1); fsec_t fsec; struct pg_tm tt, *tm = &tt; bool redotz = false; if (TIMESTAMP_NOT_FINITE(timestamp)) PG_RETURN_TIMESTAMPTZ(timestamp); if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0) ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); tm_round(tm, fmt, &redotz); if (tm2timestamp(tm, fsec, NULL, &result) != 0) ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); PG_RETURN_TIMESTAMP(result); } /******************************************************************** * * ora_sysdate - sysdate * * Syntax: * * timestamp sysdate() * * Purpose: * * Returns statement_timestamp in server time zone * Note - server time zone doesn't exists on PostgreSQL - emulated * by orafce_timezone * ********************************************************************/ Datum orafce_sysdate(PG_FUNCTION_ARGS) { Datum sysdate; Datum sysdate_scaled; sysdate = DirectFunctionCall2(timestamptz_zone, CStringGetTextDatum(orafce_timezone), TimestampTzGetDatum(GetCurrentStatementStartTimestamp())); /* necessary to cast to timestamp(0) to emulate Oracle's date */ sysdate_scaled = DirectFunctionCall2(timestamp_scale, sysdate, Int32GetDatum(0)); PG_RETURN_DATUM(sysdate_scaled); } /******************************************************************** * * ora_systemtimezone * * Syntax: * * text sessiontimezone() * * Purpose: * * Returns session time zone * ********************************************************************/ Datum orafce_sessiontimezone(PG_FUNCTION_ARGS) { PG_RETURN_TEXT_P(cstring_to_text(show_timezone())); } /******************************************************************** * * ora_dbtimezone * * Syntax: * * text dbtimezone() * * Purpose: * * Returns server time zone - emulated by orafce_timezone * ********************************************************************/ Datum orafce_dbtimezone(PG_FUNCTION_ARGS) { PG_RETURN_TEXT_P(cstring_to_text(orafce_timezone)); } orafce-VERSION_3_9_0/doc/000077500000000000000000000000001362147214200151005ustar00rootroot00000000000000orafce-VERSION_3_9_0/doc/orafce_documentation/000077500000000000000000000000001362147214200212705ustar00rootroot00000000000000orafce-VERSION_3_9_0/doc/orafce_documentation/Orafce_Documentation_01.md000066400000000000000000000075751362147214200262200ustar00rootroot00000000000000Orafce Documentation === Orafce - Oracle's compatibility functions and packages --- This documentation describes the environment settings and functionality offered for features that are compatible with Oracle databases. Chapter 1 Overview --- Features compatible with Oracle databases are provided. These features enable you to easily migrate to PostgreSQL and reduce the costs of reconfiguring applications. The table below lists features compatible with Oracle databases. ### 1.1 Features compatible with Oracle databases **Data type** |Item|Overview| |:---|:---| |VARCHAR2|Variable-length character data type| |NVARCHAR2|Variable-length national character data type| |DATE|Data type that stores date and time| **SQL Queries** |Item|Overview| |:---|:---| |DUAL table|Table provided by the system| **SQL Functions** - Mathematical functions |Item|Overview| |:---|:---| |BITAND|Performs a bitwise AND operation| |COSH|Calculates the hyperbolic cosine of a number| |SINH|Calculates the hyperbolic sine of a number| |TANH|Calculates the hyperbolic tangent of a number| - String functions |Item|Overview| |:---|:---| |INSTR|Returns the position of a substring in a string| |LENGTH|Returns the length of a string in number of characters| |LENGTHB|Returns the length of a string in number of bytes| |LPAD|Left-pads a string to a specified length with a sequence of characters| |LTRIM|Removes the specified characters from the beginning of a string| |NLSSORT|Returns a byte string used to sort strings in linguistic sort sequence based on locale| |RPAD|Right-pads a string to a specified length with a sequence of characters| |RTRIM|Removes the specified characters from the end of a string| |SUBSTR|Extracts part of a string using characters to specify position and length| |SUBSTRB|Extracts part of a string using bytes to specify position and length| - Date/time functions |Item|Overview| |:---|:---| |ADD_MONTHS|Adds months to a date| |DBTIMEZONE|Returns the value of the database time zone| |LAST_DAY|Returns the last day of the month in which the specified date falls| |MONTHS_BETWEEN|Returns the number of months between two dates| |NEXT_DAY|Returns the date of the first instance of a particular day of the week that follows the specified date| |ROUND|Rounds a date| |SESSIONTIMEZONE|Returns the time zone of the session| |SYSDATE|Returns the system date| |TRUNC|Truncates a date| - Data type formatting functions |Item|Overview| |:---|:---| |TO_CHAR|Converts a value to a string| |TO_DATE|Converts a string to a date in accordance with the specified format| |TO_MULTI_BYTE|Converts a single-byte string to a multibyte string| |TO_NUMBER|Converts a value to a number in accordance with the specified format| |TO_SINGLE_BYTE|Converts a multibyte string to a single-byte string| - Conditional expressions |Item|Overview| |:---|:---| |DECODE|Compares values, and if they match, returns a corresponding value| |LNNVL|Evaluates if a value is false or unknown| |NANVL|Returns a substitute value when a value is not a number (NaN)| |NVL|Returns a substitute value when a value is NULL| |NVL2|Returns a substitute value based on whether a value is NULL or not NULL| - Aggregate functions |Item|Overview| |:---|:---| |LISTAGG|Returns a concatenated, delimited list of string values| |MEDIAN|Calculates the median of a set of values| - Functions that return internal information |Item|Overview| |:---|:---| |DUMP|Returns internal information of a value| **SQL Operators** |Item|Overview| |:---|:---| |Datetime operator|Datetime operator for the DATE type| **Packages** |Item|Overview| |:---|:---| |DBMS_ALERT|Sends alerts to multiple sessions| |DBMS_ASSERT|Validates the properties of an input value| |DBMS_OUTPUT|Sends messages to clients| |DBMS_PIPE|Creates a pipe for inter-session communication| |DBMS_RANDOM|Generates random numbers| |DBMS_UTILITY|Provides various utilities| |UTL_FILE|Enables text file operations| orafce-VERSION_3_9_0/doc/orafce_documentation/Orafce_Documentation_02.md000066400000000000000000000106221362147214200262040ustar00rootroot00000000000000Chapter 2 Notes on Using orafce --- Orafce is defined as user-defined functions in the "public" schema created by default when database clusters are created, so they can be available for all users without the need for special settings. For this reason, ensure that "public" (without the double quotation marks) is included in the list of schema search paths specified in the search_path parameter. The following features provided by orafce are implemented in PostgreSQL and orafce using different external specifications. In the default configuration of PostgreSQL, the standard features of PostgreSQL take precedence. **Features implemented in PostgreSQL and orafce using different external specifications** - Data type |Item|Standard feature of PostgreSQL|Compatibility feature added by orafce| |:---|:---|:---| |DATE|Stores date only.|Stores date and time.| - Function |Item|Standard feature of PostgreSQL|Compatibility feature added by orafce| |:---|:---|:---| |LENGTH|If the string is CHAR type, trailing spaces are not included in the length.|If the string is CHAR type, trailing spaces are included in the length.| |SUBSTR|If 0 or a negative value is specified for the start position, simply subtracting 1 from the start position, the position will be shifted to the left, from where extraction will start.| - If 0 is specified for the start position, extraction will start from the beginning of the string.
- If a negative value is specified for the start position, extraction will start from the position counted from the end of the string.| |LPAD
RPAD| - If the string is CHAR type, trailing spaces are removed and then the value is padded.
- The result length is handled as a number of characters.| - If the string is CHAR type, the value is padded without removing trailing spaces.
- The result length is based on the width of the displayed string. Therefore, fullwidth characters are handled using a width of 2, and halfwidth characters are handled using a width of 1.| |LTRIM
RTRIM
BTRIM (*1)|If the string is CHAR type, trailing spaces are removed and then the value is removed.|If the string is CHAR type, the value is removed without removing trailing spaces.| |TO_DATE|The data type of the return value is DATE.|The data type of the return value is TIMESTAMP.| *1: BTRIM does not exist for Oracle databases, however, an external specification different to PostgreSQL is implemented in orafce to align with the behavior of the TRIM functions. Also, the following features cannot be used in the default configuration of PostgreSQL. **Features that cannot be used in the default configuration of PostgreSQL** - Function |Feature| |:---| |SYSDATE| |DBTIMEZONE| |SESSIONTIMEZONE| |TO_CHAR (date/time value)| - Operator |Feature| |:---| |Datetime operator| To use these features, set "oracle" and "pg_catalog" in the "search_path" parameter of postgresql.conf. You must specify "oracle" before "pg_catalog" when doing this. ~~~ search_path = '"$user", public, oracle, pg_catalog' ~~~ **Information** ---- - The search_path parameter specifies the order in which schemas are searched. Each feature compatible with Oracle databases is defined in the oracle schema. - It is recommended to set search_path in postgresql.conf. In this case, it will be effective for each instance. - The configuration of search_path can be done at the user level or at the database level. Setting examples are shown below. - If the standard features of PostgreSQL take precedence, and features that cannot be used with the default configuration of PostgreSQL are not required, it is not necessary to change the settings of search_path. - Example of setting at the user level - This can be set by executing an SQL command. In this example, user1 is used as the username. ~~~ ALTER USER user1 SET search_path = "$user",public,oracle,pg_catalog; ~~~ - Example of setting at the database level - This can be set by executing an SQL command. In this example, db1 is used as the database name.
You must specify "oracle" before "pg_catalog". ~~~ ALTER DATABASE db1 SET search_path = "$user",public,oracle,pg_catalog; ~~~ ---- **See** ---- - Refer to "Server Administration" > "Client Connection Defaults" > "Statement Behavior" in the PostgreSQL Documentation for information on search_path. - Refer to "Reference" > "SQL Commands" in the PostgreSQL Documentation for information on ALTER USER and ALTER DATABASE. ---- orafce-VERSION_3_9_0/doc/orafce_documentation/Orafce_Documentation_03.md000066400000000000000000000062601362147214200262100ustar00rootroot00000000000000 Chapter 3 Data Types --- The following data types are supported: - VARCHAR2 - NVARCHAR2 - DATE ### 3.1 VARCHAR2 **Syntax** ![VARCHAR2](gif/VARCHAR2.gif) Specify the VARCHAR2 type as follows. |Data type syntax|Explanation| |:---|:---| |VARCHAR2(*len*)|String with a variable length up to *len* characters
For *len*, specify an integer greater than 0.
If *len* is omitted, the string can be any length.| **General rules** - VARCHAR2 is a character data type. Specify the number of bytes for the length. - Strings are of variable length. The specified value will be stored as is. The upper limit for this data type is approximately one gigabyte. **Note** ---- The VARCHAR2 type does not support collating sequences. Therefore, the following error occurs when a collating sequence like that of an ORDER BY clause is required. At this time, the following HINT will prompt to use a COLLATE clause, however, because collating sequences are not supported, it is not possible to use this clause. ~~~ ERROR: could not determine which collation to use for string comparison HINT: Use the COLLATE clause to set the collation explicitly. ~~~ If the error shown above is displayed, explicitly cast the column to VARCHAR or TEXT type. ---- ### 3.2 NVARCHAR2 **Syntax** ![NVARCHAR2](gif/NVARCHAR2.gif) Specify the NVARCHAR2 type as follows. |Data type syntax|Explanation| |:---|:---| |NVARCHAR2(*len*)| National character string with a variable length up to *len* characters.
For *len*, specify an integer greater than 0.
If *len* is omitted, the string can be any length.| **General rules** - NVARCHAR2 is a national character data type. Specify the number of characters for the length. - Strings are of variable length. The specified value will be stored as is. The upper limit for this data type is approximately one gigabyte. **Note** ---- The NVARCHAR2 type does not support collating sequences. Therefore, the following error occurs when a collating sequence like that of an ORDER BY clause is required. At this time, the following HINT will prompt to use a COLLATE clause, however, because collating sequences are not supported, it is not possible to use this clause. ~~~ ERROR: could not determine which collation to use for string comparison HINT: Use the COLLATE clause to set the collation explicitly. ~~~ If the error shown above is displayed, explicitly cast the column to NCHAR VARYING or TEXT type. ---- ### 3.3 DATE **Syntax** ![DATE](gif/DATE.gif) Specify the DATE type as follows. |Data type syntax|Explanation| |:---|:---| |DATE|Stores date and time| **General rules** - DATE is a date/time data type. - Date and time are stored in DATE. The time zone is not stored. **Note** ---- If the DATE type of orafce is used in DDL statements such as table definitions, always set search_path before executing a DDL statement. Even if search_path is changed after definition, the data type will be the DATE type of PostgreSQL. ---- **Information** ---- The DATE type of orafce is equivalent to the TIMESTAMP type of PostgreSQL. Therefore, of the existing functions of PostgreSQL, functions for which the data type of the argument is TIMESTAMP can be used. ---- orafce-VERSION_3_9_0/doc/orafce_documentation/Orafce_Documentation_04.md000066400000000000000000000010041362147214200262000ustar00rootroot00000000000000Chapter 4 Queries --- The following queries are supported: - DUAL Table ### 4.1 DUAL Table DUAL table is a virtual table provided by the system. Use when executing SQL where access to a base table is not required, such as when performing tests to get result expressions such as functions and operators. **Example** ---- In the following example, the current system date is returned. ~~~ SELECT CURRENT_DATE "date" FROM DUAL; date ------------ 2013-05-14 (1 row) ~~~ ---- orafce-VERSION_3_9_0/doc/orafce_documentation/Orafce_Documentation_05.md000066400000000000000000001341461362147214200262170ustar00rootroot00000000000000Chapter 5 SQL Function Reference --- ### 5.1 Mathematical Functions The following mathematical functions are supported: - BITAND - COSH - SINH - TANH #### 5.1.1 BITAND **Description** Performs a bitwise AND operation. **Syntax** ![BITAND]( gif/BITAND.gif) **General rules** - BITAND performs an AND operation on each bit of two integers, and returns the result. - Specify integer type values. - The data type of the return value is BIGINT. **Example** ---- In the following example, the result of the AND operation on numeric literals 5 and 3 is returned. ~~~ SELECT BITAND(5,3) FROM DUAL; bitand ------- 1 (1 row) ~~~ ---- #### 5.1.2 COSH **Description** Calculates the hyperbolic cosine of a number. **Syntax** ![COSH]( gif/COSH.gif) **General rules** - COSH returns the hyperbolic cosine of the specified number. - The number must be a numeric data type. - The data type of the return value is DOUBLE PRECISION. **Example** ---- In the following example, the hyperbolic cosine of the numeric literal 2.236 is returned. ~~~ SELECT COSH(2.236) FROM DUAL; cosh ----------------- 4.7313591000247 (1 row) ~~~ ---- #### 5.1.3 SINH **Description** Calculates the hyperbolic sine of a number. **Syntax** ![SINH]( gif/SINH.gif) **General rules** - SINH returns the hyperbolic sine of the specified number. - The number must be a numeric data type. - The data type of the return value is DOUBLE PRECISION. **Example** ---- In the following example, the hyperbolic sine of the numeric literal 1.414 is returned. ~~~ SELECT SINH(1.414) FROM DUAL; sinh ----------------- 1.93460168824956 (1 row) ~~~ ---- #### 5.1.4 TANH **Description** Calculates the hyperbolic tangent of a number. **Syntax** ![TANH]( gif/TANH.gif) **General rules** - TANH returns the hyperbolic tangent of the specified number. - The number must be a numeric data type. - The data type of the return value is DOUBLE PRECISION. **Example** ---- In the following example, the hyperbolic tangent of the numeric literal 3 is returned. ~~~ SELECT TANH(3) FROM DUAL; tanh ----------------- 0.995054753686731 (1 row) ~~~ ---- ### 5.2 String Functions The following string functions are supported: - BTRIM - INSTR - LENGTH - LENGTHB - LPAD - LTRIM - NLSSORT - RPAD - RTRIM - SUBSTR - SUBSTRB #### 5.2.1 BTRIM **Description** Removes the specified characters from the beginning and end of a string. **Syntax** ![BTRIM]( gif/BTRIM.gif) **General rules** - BTRIM returns a string with *trimChars* removed from the beginning and end of string *str*. - If multiple trim characters are specified, all characters matching the trim characters are removed. If *trimChars* is omitted, all leading and trailing halfwidth spaces are removed. - The data type of the return value is TEXT. **Note** ---- - BTRIM does not exist for Oracle databases. - The CHAR type specification for BTRIM uses orafce for its behavior, which is different to that of BTRIM of PostgreSQL. The search_path parameter must be modified for it to behave the same as the specification described above. ---- **Information** ---- The general rule for BTRIM of PostgreSQL is as follows: - If the string is CHAR type, trailing spaces are removed and then the trim characters are removed. ---- **See** ---- - Refer to "Notes on Using orafce" for information on how to edit search_path. - Refer to "The SQL Language" > "Functions and Operators" > "String Functions and Operators" in the PostgreSQL Documentation for information on BTRIM. ---- **Example** ---- In the following example, a string that has had "a" removed from both ends of "aabcaba" is returned. ~~~ SELECT BTRIM('aabcaba','a') FROM DUAL; btrim ------- bcab (1 row) ~~~ ---- #### 5.2.2 INSTR **Description** Returns the position of a substring in a string. **Syntax** ![INSTR]( gif/INSTR.gif) **General rules** - INSTR searches for substring *str2* in string *str1* and returns the position (in characters) in *str1* of the first character of the occurrence. - The search starts from the specified start position *startPos* in *str1*. - When *startPos* is 0 or negative, the start position will be the specified number of characters from the left of the end of *str1*, and INSTR will search backward from that point. - If the start position is not specified, the search will be performed from the beginning of *str1*. - If *occurrences* is specified, the position in *str1* of the nth occurrence of *str2* is returned. Only positive numbers can be specified. - If *occurrences* is not specified, the start position of the first occurrence that is found is returned. - If *str2* is not found in *str1*, 0 is returned. - For *startPos* and *occurrences*, specify a SMALLINT or INTEGER type. - The data type of the return value is INTEGER. **Example** ---- In the following example, characters "BC" are found in string "ABCACBCAAC", and the position of those characters is returned. ~~~ SELECT INSTR('ABCACBCAAC','BC') FROM DUAL; instr ------- 2 (1 row) SELECT INSTR('ABCACBCAAC','BC',-1,2) FROM DUAL; instr ------- 2 (1 row) ~~~ ---- #### 5.2.3 LENGTH **Description** Returns the length of a string in number of characters. **Syntax** ![LENGTH]( gif/LENGTH.gif) **General rules** - LENGTH returns the number of characters in string *str*. - If the string is CHAR type, trailing spaces are included in the length. - The data type of the return value is INTEGER. **Note** ---- The LENGTH specification above uses orafce for its behavior, which is different to that of LENGTH of PostgreSQL. The search_path parameter must be modified for it to behave according to the orafce specification. ---- **Information** ---- The general rule for LENGTH of PostgreSQL is as follows: - If the string is CHAR type, trailing spaces are not included in the length. ---- **See** ---- - Refer to "Notes on Using orafce" for information on how to edit search_path. - Refer to "The SQL Language" > "Functions and Operators" > "String Functions and Operators" in the PostgreSQL Documentation for information on LENGTH. ---- **Example** ---- In the following example, the number of characters in column col2 (defined using CHAR(10)) in table t1 is returned. ~~~ SELECT col2,LENGTH(col2) FROM t1 WHERE col1 = '1001'; col2 | length ------------+-------- AAAAA | 10 (1 row) ~~~ ---- #### 5.2.4 LENGTHB **Description** Returns the length of a string in number of bytes. **Syntax** ![LENGTHB]( gif/LENGTHB.gif) **General rules** - LENGTHB returns the number of bytes in string *str*. - If the string is CHAR type, trailing spaces are included in the length. - The data type of the return value is INTEGER. **Example** ---- In the following example, the number of bytes in column col2 (defined using CHAR(10)) in table t1 is returned. Note that, in the second SELECT statement, each character in "\*" has a length of 3 bytes, for a total of 9 bytes, and 7 bytes are added for the 7 trailing spaces. This gives a result of 16 bytes. ~~~ SELECT col2,LENGTHB(col2) FROM t1 WHERE col1 = '1001'; col2 | lengthb ---------------+--------- AAAAA | 10 (1 row) SELECT col2,LENGTHB(col2) FROM t1 WHERE col1 = '1004'; col2 | lengthb ---------------+--------- *** | 16 (1 row) ~~~ ---- #### 5.2.5 LPAD **Description** Left-pads a string to a specified length with a sequence of characters. **Syntax** ![LPAD]( gif/LPAD.gif) **General rules** - LPAD returns the result after repeatedly padding the beginning of string *str* with padding characters *paddingStr* until the string reaches length *len*. - If the string is CHAR type, the padding characters are added to the string without removing trailing spaces. - In the resultant string, fullwidth characters are recognized as having a length of 2, and halfwidth characters having a length of 1. If a fullwidth character cannot be included in the resultant string because there is only space available for one halfwidth character, the string is padded with a single-byte space. - The data type of the return value is TEXT. **Note** ---- The LPAD specification above uses orafce for its behavior, which is different to that of LPAD of PostgreSQL. The search_path parameter must be modified for it to behave according to the orafce specification. ---- **Information** ---- The general rules for LPAD of PostgreSQL are as follows: - If the string is CHAR type, trailing spaces are removed and then the padding characters are added to the string. - The result length is the number of characters. ---- **See** ---- - Refer to "Notes on Using orafce" for information on how to edit search_path. - Refer to "The SQL Language" > "Functions and Operators" > "String Functions and Operators" in the PostgreSQL Documentation for information on LPAD. ---- **Example** ---- In the following example, a 10-character string that has been formed by left-padding the string "abc" with "a" is returned. ~~~ SELECT LPAD('abc',10,'a') FROM DUAL; lpad ------------ aaaaaaaabc (1 row) ~~~ ---- #### 5.2.6 LTRIM **Description** Removes the specified characters from the beginning of a string. **Syntax** ![LTRIM]( gif/LTRIM.gif) **General rules** - LTRIM returns a string with *trimChars* removed from the beginning of string *str*. - If multiple trim characters are specified, all characters matching the trim characters are removed. If *trimChars* is omitted, all leading halfwidth spaces are removed. - The data type of the return value is TEXT. **Note** ---- The LTRIM specification above uses orafce for its behavior, which is different to that of LTRIM of PostgreSQL. The search_path parameter must be modified for it to behave according to the orafce specification. ---- **Information** ---- The general rule for LTRIM of PostgreSQL is as follows: - If the string is CHAR type, trailing spaces are removed and then the trim characters are removed. ---- **See** ---- - Refer to "Notes on Using orafce" for information on how to edit search_path. - Refer to "The SQL Language" > "Functions and Operators" > "String Functions and Operators" in the PostgreSQL Documentation for information on LTRIM. ---- **Example** ---- In the following example, a string that has had "ab" removed from the beginning of "aabcab" is returned. ~~~ SELECT LTRIM('aabcab','ab') FROM DUAL; ltrim ------- cab (1 row) ~~~ ---- #### 5.2.7 NLSSORT **Description** Returns a byte string that denotes the lexical order of the locale (COLLATE). **Syntax** ![NLSSORT]( gif/NLSSORT.gif) **General rules** - NLSSORT is used for comparing and sorting in the collating sequence of a locale (COLLATE) that differs from the default locale. - Values that can be specified for the locale differ according to the operating system of the database server. - If the locale is omitted, it is necessary to use set_nls_sort to set the locale in advance. To set the locale using set_nls_sort, execute a SELECT statement. **Example of setting set_nls_sort using a SELECT statement** ~~~ SELECT set_nls_sort('en_US.UTF8'); ~~~ - The data type of the return value is BYTEA. **Note** ---- If specifying locale encoding, ensure it matches the database encoding. ---- **See** ---- Refer to "Server Administration" > "Localization" > "Locale Support" in the PostgreSQL Documentation for information on the locales that can be specified. ---- **Example** ---- [Composition of table (t3)] |col1 | col2| |:--- |:--- | |1001 |aabcababc| |2001 |abcdef| |3001 |aacbaab| In the following example, the result of sorting column col2 in table t3 by "da_DK.UTF8" is returned. ~~~ SELECT col1,col2 FROM t3 ORDER BY NLSSORT(col2,'da_DK.UTF8'); col1 | col2 ------+------------ 2001 | abcdef 1001 | aabcababc 3001 | aacbaab (3 row) ~~~ ---- #### 5.2.8 RPAD **Description** Right-pads a string to a specified length with a sequence of characters. **Syntax** ![RPAD]( gif/RPAD.gif) **General rules** - RPAD returns the result after repeatedly padding the end of string *str* with padding characters *paddingStr* until the string reaches length *len*. - If the string is CHAR type, the padding characters are added to the string without removing trailing spaces. - In the resultant string, fullwidth characters are recognized as having a length of 2, and halfwidth characters having a length of 1. If a fullwidth character cannot be included in the resultant string because there is only space available for one halfwidth character, the string is padded with a single-byte space. - The data type of the return value is TEXT. **Note** ---- The RPAD specification above uses orafce for its behavior, which is different to that of RPAD of PostgreSQL. The search_path parameter must be modified for it to behave according to the orafce specification. ---- **Information** ---- The general rules for RPAD of PostgreSQL are as follows: - If the string is CHAR type, trailing spaces are removed and then the padding characters are added to the string. - The result length is the number of characters. ---- **See** ---- - Refer to "Notes on Using orafce" for information on how to edit search_path. - Refer to "The SQL Language" > "Functions and Operators" > "String Functions and Operators" in the PostgreSQL Documentation for information on RPAD. ---- **Example** ---- In the following example, a 10-character string that has been formed by right-padding the string "abc" with "a" is returned. ~~~ SELECT RPAD('abc',10,'a') FROM DUAL; rpad ------------ abcaaaaaaa (1 row) ~~~ ---- #### 5.2.9 RTRIM **Description** Removes the specified characters from the end of a string. **Syntax** ![RTRIM]( gif/RTRIM.gif) **General rules** - RTRIM returns a string with *trimChars* removed from the end of string *str*. - If multiple trim characters are specified, all characters matching the trim characters are removed. If *trimChars* is omitted, all trailing halfwidth spaces are removed. - The data type of the return value is TEXT. **Note** ---- The RTRIM specification above uses orafce for its behavior, which is different to that of RTRIM of PostgreSQL. The search_path parameter must be modified for it to behave the same as the orafce specification. ---- **Information** ---- The general rule for RTRIM of PostgreSQL is as follows: - If the string is CHAR type, trailing spaces are removed and then the trim characters are removed. ---- **See** ---- - Refer to "Notes on Using orafce" for information on how to edit search_path. - Refer to "The SQL Language" > "Functions and Operators" > "String Functions and Operators" in the PostgreSQL Documentation for information on RTRIM. ---- **Example** ---- In the following example, a string that has had "ab" removed from the end of "aabcab" is returned. ~~~ SELECT RTRIM('aabcab','ab') FROM DUAL; rtrim ------- aabc (1 row) ~~~ ---- #### 5.2.10 SUBSTR **Description** Extracts part of a string using characters to specify position and length. **Syntax** ![SUBSTR]( gif/SUBSTR.gif) **General rules** - SUBSTR extracts and returns a substring of string *str*, beginning at position *startPos*, for number of characters *len*. - When *startPos* is positive, it will be the number of characters from the beginning of the string. - When *startPos* is 0, it will be treated as 1. - When *startPos* is negative, it will be the number of characters from the end of the string. - When *len* is not specified, all characters to the end of the string are returned. NULL is returned when *len* is less than 1. - For *startPos* and *len*, specify an integer or NUMERIC type. If numbers including decimal places are specified, they are truncated to integers. - The data type of the return value is TEXT. **Note** ---- - There are two types of SUBSTR. One that behaves as described above and one that behaves the same as SUBSTRING. The search_path parameter must be modified for it to behave the same as the specification described above. - If the change has not been implemented, SUBSTR is the same as SUBSTRING. ---- **Information** ---- The general rules for SUBSTRING are as follows: - The start position will be from the beginning of the string, whether the start position is positive, 0, or negative. - When *len* is not specified, all characters to the end of the string are returned. - An empty string is returned if no string is extracted or *len* is less than 1. ---- **See** ---- Refer to "The SQL Language" > "Functions and Operators" > "String Functions and Operators" in the PostgreSQL Documentation for information on SUBSTRING. ---- **Example** ---- In the following example, part of the string "ABCDEFG" is extracted. ~~~ SELECT SUBSTR('ABCDEFG',3,4) "Substring" FROM DUAL; Substring ----------- CDEF (1 row) SELECT SUBSTR('ABCDEFG',-5,4) "Substring" FROM DUAL; Substring ----------- CDEF (1 row) ~~~ ---- #### 5.2.11 SUBSTRB **Description** Extracts part of a string using bytes to specify position and length. **Syntax** ![SUBSTRB]( gif/SUBSTRB.gif) **General rules** - SUBSTRB extracts and returns a substring of string *str*, beginning at byte position *startPos*, for number of bytes *len*. - When *startPos* is 0 or negative, extraction starts at the position found by subtracting 1 from the start position and shifting by that number of positions to the left. - When *len* is not specified, all bytes to the end of the string are returned. - An empty string is returned if no string is extracted or *len* is less than 1. - For *startPos* and *len*, specify a SMALLINT or INTEGER type. - The data type of the return value is VARCHAR2. **Note** ---- The external specification of SUBSTRB is different to that of SUBSTR added by orafce, conforming with SUBSTRING of PostgreSQL. ---- **Example** ---- In the following example, part of the string "aaabbbccc" is extracted. ~~~ SELECT SUBSTRB('aaabbbccc',4,3) FROM DUAL; substrb ----------- bbb (1 row) SELECT SUBSTRB('aaabbbccc',-2,6) FROM DUAL; substrb ----------- aaa (1 row) ~~~ ---- ### 5.3 Date/time Functions The following date/time functions are supported: - ADD_MONTHS - DBTIMEZONE - LAST_DAY - MONTHS_BETWEEN - NEXT_DAY - ROUND - SESSIONTIMEZONE - SYSDATE - TRUNC **Note** ---- If the DATE type only is shown in the date/time functions, these functions can be used in both orafce and PostgreSQL. ---- #### 5.3.1 ADD_MONTHS **Description** Adds months to a date. **Syntax** ![ADD_MONTHS]( gif/ADD_MONTHS.gif) **General rules** - ADD_MONTHS returns *date* plus *months*. - For *date*, specify a DATE type. - For *months*, specify a SMALLINT or INTEGER type. - If a negative value is specified for *months*, the number of months is subtracted from the date. - The data type of the return value is DATE. **Note** ---- If using the DATE type of orafce, it is necessary to specify "oracle" for search_path in advance. ---- **See** ---- Refer to "Notes on Using orafce" for information on how to edit search_path. ---- **Example** ---- The example below shows the result of adding 3 months to the date May 1, 2016. ~~~ SELECT ADD_MONTHS(DATE'2016/05/01',3) FROM DUAL; add_months --------------------- 2016-08-01 00:00:00 (1 row) ~~~ ---- #### 5.3.2 DBTIMEZONE **Description** Returns the value of the database time zone. **Syntax** ![DBTIMEZONE]( gif/DBTIMEZONE.gif) **General rules** - DBTIMEZONE returns the time zone value of the database. - The data type of the return value is TEXT. **Note** ---- - If using DBTIMEZONE, it is necessary to specify "oracle" for search_path in advance. - The time zone of the database is set to "GMT" by default. To change the time zone, change the "orafce.timezone" parameter. An example using the SET statement is shown below. Setting example of orafce.timezone using a SET statement ~~~ SET orafce.timezone = 'Japan'; ~~~ - The orafce.timezone settings can be set using any of the methods for setting server parameters. - If the SQL statement is executed with orafce.timezone set, the following message may be displayed, however, the parameter settings are enabled, so you can ignore this. ~~~ WARNING: unrecognized configuration parameter "orafce.timezone" ~~~ - The time zones that can be set in "orafce.timezone" are the same as for the "TimeZone" server parameter. ---- **See** ---- - Refer to "Notes on Using orafce" for information on how to edit search_path. - Refer to "The SQL Language" > "Data Types" > "Date/Time Types" in the PostgreSQL Documentation for information on the time zone. ---- **Example** ---- In the following example, the DBTIMEZONE result is returned. ~~~ SELECT DBTIMEZONE() FROM DUAL; dbtimezone ------------ GMT (1 row) ~~~ ---- #### 5.3.3 LAST_DAY **Description** Returns the last day of the month in which the specified date falls. **Syntax** ![LAST_DAY]( gif/LAST_DAY.gif) **General rules** - LAST_DAY returns the last day of the month in which the specified date falls. - For *date*, specify a DATE type. - The data type of the return value is DATE. **Note** ---- If using the DATE type of orafce, it is necessary to specify "oracle" for search_path in advance. ---- **See** ---- Refer to "Notes on Using orafce" for information on how to edit search_path. ---- **Example** ---- In the example below, the last date of "February 01, 2016" is returned. ~~~ SELECT LAST_DAY(DATE'2016/02/01') FROM DUAL; last_day --------------------- 2016-02-29 00:00:00 (1 row) ~~~ ---- #### 5.3.4 MONTHS_BETWEEN **Description** Returns the number of months between two dates. **Syntax** ![MONTHS_BETWEEN]( gif/MONTHS_BETWEEN.gif) **General rules** - MONTHS_BETWEEN returns the difference in the number of months between *date1* and *date2*. - For *date1* and *date2*, specify a DATE type. - If *date2* is earlier than *date1*, the return value will be negative. - If two dates fall on the same day, or each of the two dates are the last day of the month to which they belong, an integer is returned. If the days are different, one month is considered to be 31 days, and a value with the difference in the number of days divided by 31 added is returned. - The data type of the return value is NUMERIC. **Note** ---- If using the DATE type of orafce, it is necessary to specify "oracle" for search_path in advance. ---- **See** ---- Refer to "Notes on Using orafce" for information on how to edit search_path. ---- **Example** ---- In the following example, the difference between the months of March 15, 2016 and November 15, 2015 is returned. ~~~ SELECT MONTHS_BETWEEN(DATE'2016/03/15', DATE'2015/11/15') FROM DUAL; months_between ---------------- 4 (1 row) ~~~ ---- #### 5.3.5 NEXT_DAY **Description** Returns the date of the first instance of a particular day of the week that follows the specified date. **Syntax** ![NEXT_DAY]( gif/NEXT_DAY.gif) **General rules** - NEXT_DAY returns the date matching the first instance of *dayOfWk* that follows *date*. - For *date*, specify a DATE type. - Specify a numeric value or string indicating the day of the week. **Values that can be specified for the day** |Setting example|Overview| |:---|:---| |1|1 (Sunday) to 7 (Saturday) can be specified| |'Sun', or 'Sunday'|English display of the day| |'*'|Japanese display of the day| - The data type of the return value is DATE. **Note** ---- - If using the DATE type of orafce, it is necessary to specify "oracle" for search_path in advance. - The ability to use Japanese for entering days is provided by the orafce proprietary specification. Japanese cannot be used for entering days when using date/time functions other than NEXT_DAY (such as TO_DATE). ---- **See** ---- Refer to "Notes on Using orafce" for information on how to edit search_path. ---- **Example** ---- In the example below, the date of the first Friday on or after "May 1, 2016" is returned. ~~~ SELECT NEXT_DAY(DATE'2016/05/01', 'Friday') FROM DUAL; next_day --------------------- 2016-05-06 00:00:00 (1 row) ~~~ ---- #### 5.3.6 ROUND **Description** Rounds a date. **Syntax** ![ROUND]( gif/ROUND.gif) **General rules** - ROUND returns a date rounded to the unit specified by format model *fmt*. - For *date*, specify a DATE or TIMESTAMP type. - Specify the format model as a string. **Values that can be specified for the format model** |Format model|Rounding unit| |:---|:---| |Y,YY,YYY,YYYY,
SYYYY,YEAR,SYEAR|Year| |I,IY,IYY,IYYY|Year (values including calendar weeks, in compliance with the ISO standard)| |Q|Quarter| |WW|Week (first day of the year)| |IW|Week (Monday of that week)| |W|Week (first weekday on which the first day of the month falls)| |DAY,DY,D|Week (Sunday of that week)| |MONTH,MON,MM,RM|Month| |CC,SCC|Century| |DDD,DD,J|Day| |HH,HH12,HH24|Hour| |MI|Minute| - If decimal places are rounded: for year, the boundary for rounding is July 1; for month, the day is 16; and for week, the weekday is Thursday. - If *fmt* is omitted, the date is rounded by day. - If the DATE type of PostgreSQL is specified for the date, that DATE type will be the data type of the return value. If the TIMESTAMP type is specified for the date, the data type will be TIMESTAMP WITH TIME ZONE, irrespective of whether a time zone is used. **Example** ---- In the example below, the result of "June 20, 2016 18:00:00" rounded by Sunday of the week is returned. ~~~ SELECT ROUND(TIMESTAMP'2016/06/20 18:00:00','DAY') FROM DUAL; round ------------------------ 2016-06-19 00:00:00+09 (1 row) ~~~ ---- #### 5.3.7 SESSIONTIMEZONE **Description** Returns the time zone of the session. **Syntax** ![SESSIONTIMEZONE]( gif/SESSIONTIMEZONE.gif) **General rules** - SESSIONTIMEZONE returns the time zone value between sessions. - The data type of the return value is TEXT. **Note** ---- - If using SESSIONTIMEZONE, it is necessary to specify "oracle" for search_path in advance. - The value returned by SESSIONTIMEZONE becomes the value set in the "TimeZone" server parameter. ---- **See** ---- Refer to "Notes on Using orafce" for information on how to edit search_path. ---- **Example** ---- In the following example, the time zone of the session is returned. ~~~ SELECT SESSIONTIMEZONE() FROM DUAL; sessiontimezone ----------------- Japan (1 row) ~~~ ---- #### 5.3.8 SYSDATE **Description** Returns the system date. **Syntax** ![SYSDATE]( gif/SYSDATE.gif) **General rules** - SYSDATE returns the system date. - The data type of the return value is the DATE type of orafce. **Note** ---- - If using SYSDATE, it is necessary to specify "oracle" for search_path in advance. - The date returned by SYSDATE depends on the time zone value of the orafce database. ---- **See** ---- - Refer to "Notes on Using orafce" for information on how to edit search_path. - Refer to "DBTIMEZONE" for information on the time zone values of the database. - Refer to "The SQL Language" > "Data Types" > "Date/Time Types" in the PostgreSQL Documentation for information on the time zone. ---- **Example** ---- In the following example, the system date is returned. ~~~ SELECT SYSDATE() FROM DUAL; sysdate --------------------- 2016-06-22 08:06:51 (1 row) ~~~ ---- #### 5.3.9 TRUNC **Description** Truncates a date. **Syntax** ![TRUNC]( gif/TRUNC.gif) **General rules** - TRUNC returns a date truncated to the unit specified by format model *fmt*. - For *date*, specify a DATE or TIMESTAMP type. - Specify the format model as a string. The values that can be specified are the same as for ROUND. - If *fmt* is omitted, the date is truncated by day. - If the DATE type of PostgreSQL is specified for the date, that DATE type will be the data type of the return value. If the TIMESTAMP type is specified for the date, the data type will be TIMESTAMP WITH TIME ZONE, irrespective of whether a time zone is used. **See** ---- Refer to "ROUND" for information on the values that can be specified for the format model. ---- **Example** ---- In the example below, the result of "August 10, 2016 15:30:00" truncated by the day is returned. ~~~ SELECT TRUNC(TIMESTAMP'2016/08/10 15:30:00','DDD') FROM DUAL; trunc ------------------------ 2016-08-10 00:00:00+09 (1 row) ~~~ ---- ### 5.4 Data Type Formatting Functions The following data type formatting functions are supported: - TO_CHAR - TO_DATE - TO_MULTI_BYTE - TO_NUMBER - TO_SINGLE_BYTE #### 5.4.1 TO_CHAR **Description** Converts a value to a string. **Syntax** ![TO_CHAR]( gif/TO_CHAR.gif) **General rules** - TO_CHAR converts the specified number or date/time value to a string. - For *num*, specify a numeric data type. - For *date*, specify a DATE or TIMESTAMP type. Also, you must set a date/time format for the orafce.nls_date_format variable in advance. A setting example using the SET statement is shown below. Setting example of orafce.nls_date_format using a SET statement ~~~ SET orafce.nls_date_format = 'YYYY/MM/DD HH24:MI:SS'; ~~~ - The data type of the return value is TEXT. **Note** ---- - If using TO_CHAR for specifying date/time values, it is necessary to specify "oracle" for search_path in advance. - The orafce.nls_date_format settings can be set using any of the methods for setting server parameters. - If orafce.nls_date_format is set, the following message may be displayed when an SQL statement is executed, however, the parameter settings are enabled, so you can ignore this. ~~~ WARNING: unrecognized configuration parameter "orafce.nls_date_format" ~~~ ---- **See** ---- - Refer to "Notes on Using orafce" for information on how to edit search_path. - Refer to "Server Administration" > "Server Configuration" > "Setting Parameters" in the PostgreSQL Documentation for information on how to set the server parameters. ---- **Example** ---- In the following example, the numeric value "123.45" is returned as a string. ~~~ SELECT TO_CHAR(123.45) FROM DUAL; to_char --------- 123.45 (1 row) ~~~ ---- #### 5.4.2 TO_DATE **Description** Converts a string to a date in accordance with the specified format. **Syntax** ![TO_DATE]( gif/TO_DATE.gif) **General rules** - TO_DATE converts string *str* to a date in accordance with the specified format *fmt*. - Specify a string indicating the date/time. - Specify the required date/time format. If omitted, the format specified in the oracle.nls_date_format variable is used. If the oracle.nls_date_format variable has not been set, the existing date/time input interpretation is used. A setting example using the SET statement is shown below. **Setting example of orafce.nls_date_format using a SET statement** ~~~ SET orafce.nls_date_format = 'YYYY/MM/DD HH24:MI:SS'; ~~~ - The data type of the return value is TIMESTAMP. **Note** ---- - The above TO_DATE specification uses orafce for its behavior, which is different to that of TO_DATE of PostgreSQL. The search_path parameter must be modified for it to behave according to the orafce specification. - The orafce.nls_date_format settings can be set using any of the methods for setting server parameters. - If orafce.nls_date_format is set, the following message may be displayed when an SQL statement is executed, however, the parameter settings are enabled, so you can ignore this. ~~~ WARNING: unrecognized configuration parameter "orafce.nls_date_format" ~~~ ---- **Information** ---- The general rule for TO_DATE for specifying the data type format of PostgreSQL is as follows: - The data type of the return value is the DATE type of PostgreSQL. ---- **See** ---- - Refer to "Notes on Using orafce" for information on how to edit search_path. - Refer to "The SQL Language" > "Functions and Operators" > "Data Type Formatting Functions" in the PostgreSQL Documentation for information on TO_DATE of PostgreSQL. - Refer to "Server Administration" > "Server Configuration" > "Setting Parameters" in the PostgreSQL Documentation for information on how to set the server parameters. - Refer to "Date/Time Support" > "Date/Time Input Interpretation" in the PostgreSQL Documentation for information on the interpretation of existing date/time input. ---- **Example** ---- In the following example, the string "2016/12/31" is converted to a date and returned. ~~~ SELECT TO_DATE('2016/12/31','YYYY/MM/DD') FROM DUAL; to_date --------------------- 2016-12-31 00:00:00 (1 row) ~~~ ---- #### 5.4.3 TO_MULTI_BYTE **Description** Converts a single-byte string to a multibyte string. **Syntax** ![TO_MULTI_BYTE]( gif/TO_MULTI_BYTE.gif) **General rules** - TO_MULTI_BYTE converts halfwidth characters in string *str* to fullwidth characters, and returns the converted string. - Only halfwidth alphanumeric characters, spaces and symbols can be converted. - The data type of the return value is TEXT. **Example** ---- In the following example, "abc123" is converted to fullwidth characters and returned. ~~~ SELECT TO_MULTI_BYTE('abc123') FROM DUAL; to_multi_byte --------------- ****** (1 row) ~~~ "\*\*\*\*\*\*" is multibyte "abc123". ---- #### 5.4.4 TO_NUMBER **Description** Converts a value to a number in accordance with the specified format. **Syntax** ![TO_NUMBER]( gif/TO_NUMBER.gif) **General rules** - TO_NUMBER converts the specified value to a numeric value in accordance with the specified format *fmt*. - For *num*, specify a numeric data type. - For *str*, specify a string indicating the numeric value. Numeric values must comprise only of convertible characters. - Specify the required numeric data format. The specified numeric value is handled as is as a data type expression. - The data type of the return value is NUMERIC. **See** ---- Refer to "The SQL Language" > "Functions and Operators" > "Data Type Formatting Functions" in the PostgreSQL Documentation for information on numeric value formats. ---- **Example** ---- In the following example, the numeric literal "-130.5" is converted to a numeric value and returned. ~~~ SELECT TO_NUMBER(-130.5) FROM DUAL; to_number ----------- -130.5 (1 row) ~~~ ---- #### 5.4.5 TO_SINGLE_BYTE **Description** Converts a multibyte string to a single-byte string. **Syntax** ![TO_SINGLE_BYTE]( gif/TO_SINGLE_BYTE.gif) **General rules** - TO_SINGLE_BYTE converts fullwidth characters in string *str* to halfwidth characters, and returns the converted string. - Only fullwidth alphanumeric characters, spaces and symbols that can be displayed in halfwidth can be converted. - The data type of the return value is TEXT. **Example** ---- In the following example, "\*\*\*\*\*\*" is converted to halfwidth characters and returned. "\*\*\*\*\*\*" is multibyte "xyz999". ~~~ SELECT TO_SINGLE_BYTE('******') FROM DUAL; to_single_byte ---------------- xyz999 (1 row) ~~~ ---- ### 5.5 Conditional Expressions The following functions for making comparisons are supported: - DECODE - LNNVL - NANVL - NVL - NVL2 #### 5.5.1 DECODE **Description** Compares values and if they match, returns a corresponding value. **Syntax** ![DECODE]( gif/DECODE.gif) **General rules** - DECODE compares values of the value expression to be converted and the search values one by one. If the values match, a corresponding result value is returned. If no values match, the default value is returned if it has been specified. A NULL value is returned if a default value has not been specified. - If the same search value is specified more than once, then the result value returned is the one listed for the first occurrence of the search value. - The following data types can be used in result values and in the default value: - CHAR - VARCHAR - VARCHAR2 - NCHAR - NCHAR VARYING - NVARCHAR2 - TEXT - INTEGER - BIGINT - NUMERIC - DATE - TIME WITHOUT TIME ZONE - TIMESTAMP WITHOUT TIME ZONE - TIMESTAMP WITH TIME ZONE - The same data type must be specified for the values to be converted and the search values. However, note that different data types may also be specified if a literal is specified in the search value, and the value expression to be converted contains data types that can be converted. - If the result values and default value are all literals, the data types for these values will be as shown below: - If all values are string literals, all will become character types. - If there is one or more numeric literal, all will become numeric types. - If there is one or more literal cast to the datetime/time types, all will become datetime/time types. - If the result values and default value contain a mixture of literals and non-literals, the literals will be converted to the data types of the non-literals. - The same data type must be specified for all result values and for the default value. However, different data types can be specified if the data type of any of the result values or default value can be converted - these data types are listed below: **Data type combinations that can be converted by DECODE (summary)**
Other result values or default value
Numeric type Character type Date/time type
Result value (any) Numeric type Y N N
Character type N Y N
Date/time type N N S(*1)
Y: Can be converted S: Some data types can be converted N: Cannot be converted *1: The data types that can be converted for date/time types are listed below: **Result value and default value date/time data types that can be converted by DECODE**
Other result values or default value
DATE TIME
WITHOUT TIME ZONE
TIMESTAMP
WITHOUT TIME ZONE
TIMESTAMP
WITH TIME ZONE
Result value (any) DATE Y N Y Y
TIME
WITHOUT TIME ZONE
N Y N N
TIMESTAMP
WITHOUT TIME ZONE
Y N Y Y
TIMESTAMP
WITH TIME ZONE
Y N Y Y
Y: Can be converted N: Cannot be converted - The data type of the return value will be the data type within the result or default value that is longest and has the highest precision. **Example** ---- In the following example, the value of col3 in table t1 is compared and converted to a different value. If the col3 value matches search value 1, the result value returned is "one". If the col3 value does not match any of search values 1, 2, or 3, the default value "other number" is returned. ~~~ SELECT col1, DECODE(col3, 1, 'one', 2, 'two', 3, 'three', 'other number') "num-word" FROM t1; col1 | num-word ------+---------- 1001 | one 1002 | two 1003 | three (3 rows) ~~~ ---- #### 5.5.2 LNNVL **Description** Determines if a value is TRUE or FALSE for the specified condition. **Syntax** ![LNNVL]( gif/LNNVL.gif) **General rules** - LNNVL determines if a value is TRUE or FALSE for the specified condition. If the result of the condition is FALSE or NULL, TRUE is returned. If the result of the condition is TRUE, FALSE is returned. - The expression for returning TRUE or FALSE is specified in the condition. - The data type of the return value is BOOLEAN. **Example** ---- In the following example, col1 and col3 of table t1 are returned when col3 has a value of 2000 or less, or null values. ~~~ SELECT col1,col3 FROM t1 WHERE LNNVL( col3 > 2000 ); col1 | col3 ------+------ 1001 | 1000 1002 | 2000 2002 | (3 row) ~~~ ---- #### 5.5.3 NANVL **Description** Returns a substitute value when a value is not a number (NaN). **Syntax** ![NANVL]( gif/NANVL.gif) **General rules** - NANVL returns a substitute value when the specified value is not a number (NaN). The substitute value can be either a number or a string that can be converted to a number. - For *expr* and *substituteNum*, specify a numeric data type. If *expr* and *substituteNum* have different data types, they will be converted to the data type with greater length or precision, and that is the data type that will be returned. - For *substituteNum*, you can also specify a string indicating the numeric value. - The data type used for the return value if a string is specified for the substitute value will be the same as the data type of *expr*. **Example** ---- In the following example, "0" is returned if the value of col1 in table t1 is a NaN value. ~~~ SELECT col1, NANVL(col3,0) FROM t1; col1 | nanvl ------+------- 2001 | 0 (1 row) ~~~ ---- #### 5.5.4 NVL **Description** Returns a substitute value when a value is NULL. **Syntax** ![NVL]( gif/NVL.gif) **General rules** - NVL returns a substitute value when the specified value is NULL. When *expr1* is NULL, *expr2* is returned. When *expr1* is not NULL, *expr1* is returned. - Specify the same data types for *expr1* and *expr2*. However, if a constant is specified in *expr2*, and the data type can also be converted by *expr1*, different data types can be specified. When this happens, the conversion by *expr2* is done to suit the data type in *expr1*, so the value of *expr2* returned when *expr1* is a NULL value will be the value converted in the data type of *expr1*. This is not necessary for types (numeric, int) and (bigint, int). **Example** ---- In the following example, "IS NULL" is returned if the value of col1 in table t1 is a NULL value. ~~~ SELECT col2, NVL(col1,'IS NULL') "nvl" FROM t1; col2 | nvl ------+--------- aaa | IS NULL (1 row) ~~~ ---- #### 5.5.5 NVL2 **Description** Returns a substitute value based on whether a value is NULL or not NULL. **Syntax** ![NVL2]( gif/NVL2.gif) **General rules** - NVL2 returns a substitute value based on whether the specified value is NULL or not NULL. When *expr* is NULL, *substitute2* is returned. When it is not NULL, *substitute1* is returned. - Specify the same data types for *expr*, *substitute1*, and *substitute2*. However, if a literal is specified in *substitute1* or *substitute2*, and the data type can also be converted by *expr*, different data types can be specified. When this happens, *substitute1* or *substitute2* is converted to suit the data type in *expr*, so the value of *substitute2* returned when *expr* is a NULL value will be the value converted to the data type of *expr*. **Example** ---- In the following example, if a value in column col1 in table t1 is NULL, "IS NULL" is returned, and if not NULL, "IS NOT NULL" is returned. ~~~ SELECT col2, NVL2(col1,'IS NOT NULL','IS NULL') FROM t1; col2 | nvl2 ------+--------- aaa | IS NULL bbb | IS NOT NULL (2 row) ~~~ ---- ### 5.6 Aggregate Functions The following aggregation functions are supported: - LISTAGG - MEDIAN #### 5.6.1 LISTAGG **Description** Returns a concatenated, delimited list of string values. **Syntax** ![LISTAGG]( gif/LISTAGG.gif) **General rules** - LISTAGG concatenates and delimits a set of string values and returns the result. - For *delimiter*, specify a string. If the delimiter is omitted, a list of strings without a delimiter is returned. - The data type of the return value is TEXT. **Example** ---- In the following example, the result with values of column col2 in table t1 delimited by ':' is returned. ~~~ SELECT LISTAGG(col2,':') FROM t1; listagg ------------------- AAAAA:BBBBB:CCCCC (1 row) ~~~ ---- #### 5.6.2 MEDIAN **Description** Calculates the median of a set of numbers. **Syntax** ![MEDIAN]( gif/MEDIAN.gif) **General rules** - MEDIAN returns the median of a set of numbers. - The numbers must be numeric data type. - The data type of the return value will be REAL if the numbers are REAL type, or DOUBLE PRECISION if any other type is specified. **Example** ---- In the following example, the median of column col3 in table t1 is returned. ~~~ SELECT MEDIAN(col3) FROM t1; median -------- 2000 (1 row) ~~~ ---- ### 5.7 Functions That Return Internal Information The following functions that return internal information are supported: - DUMP #### 5.7.1 DUMP **Description** Returns internal information of a value. **Syntax** ![DUMP]( gif/DUMP.gif) **General rules** - DUMP returns the internal information of the values specified in expressions in a display format that is in accordance with the output format. - The internal code (Typ) of the data type, the data length (Len) and the internal expression of the data are output as internal information. - Any data type can be specified for the expressions. - The display format (base *n* ) of the internal expression of the data is specified for the output format. The base numbers that can be specified are 8, 10, and 16. If omitted, 10 is used as the default. - The data type of the return value is VARCHAR. **Note** ---- The information output by DUMP will be the complete internal information. Therefore, the values may change due to product updates, and so on. ---- **Example** ---- In the following example, the internal information of column col1 in table t1 is returned. ~~~ SELECT col1, DUMP(col1) FROM t1; col1 | dump ------+------------------------------------ 1001 | Typ=25 Len=8: 32,0,0,0,49,48,48,49 1002 | Typ=25 Len=8: 32,0,0,0,49,48,48,50 1003 | Typ=25 Len=8: 32,0,0,0,49,48,48,51 (3 row) ~~~ ---- #### 5.8 Datetime Operator The following datetime operators are supported for the DATE type of orafce. **Datetime operator** |Operation|Example|Result| |:---:|:---|:---| |+|DATE'2016/01/01' + 10|2016-01-11 00:00:00| |-|DATE'2016/03/20' - 35|2016-02-14 00:00:00| |-|DATE'2016/09/01' - DATE'2015/12/31'|245| **Note** ---- If using datetime operators for the DATE type of orafce, it is necessary to specify "oracle" for search_path in advance. ---- **See** ---- Refer to "Notes on Using orafce" for information on how to edit search_path. ---- orafce-VERSION_3_9_0/doc/orafce_documentation/Orafce_Documentation_06.md000066400000000000000000001434011362147214200262120ustar00rootroot00000000000000Chapter 6 Package Reference --- A "package" is a group of features, brought together by schemas, that have a single functionality, and are used by calling from PL/pgSQL. The following packages are supported: - DBMS_ALERT - DBMS_ASSERT - DBMS_OUTPUT - DBMS_PIPE - DBMS_RANDOM - DBMS_UTILITY - UTL_FILE To call the different functionalities from PL/pgSQL, use the PERFORM statement or SELECT statement, using the package name to qualify the name of the functionality. Refer to the explanations for each of the package functionalities for information on the format for calling. ### 6.1 DBMS_ALERT **Overview** The DBMS_ALERT package sends alerts from a PL/pgSQL session to multiple other PL/pgSQL sessions. This package can be used when processing 1:N, such as when notifying alerts from a given PL/pgSQL session to another PL/pgSQL session at the same time. **Features** | Feature | Description | |:--- |:--- | |REGISTER | Registers the specified alert.| |REMOVE | Removes the specified alert.| |REMOVEALL | Removes all alerts from a session.| |SIGNAL|Notifies alerts.| |WAITANY|Waits for notification of any alerts for which a session is registered.| |WAITONE|Waits for notification of a specific alert for which a session is registered.| **Syntax** ![DBMS_ALERT](gif/DBMS_ALERT.gif) #### 6.1.1 Description of Features This section explains each feature of DBMS_ALERT. **REGISTER** - REGISTER registers the specified alert to a session. By registering alerts to a session, SIGNAL notifications can be received. - Specify the name of the alert. - Alerts are case-sensitive. - Multiple alerts can be registered within a single session. If registering multiple alerts, call REGISTER for each alert. **Example** ---- ~~~ PERFORM DBMS_ALERT.REGISTER('sample_alert'); ~~~ ---- **REMOVE** - REMOVE removes the specified alert from a session. - Specify the name of the alert. - Alerts are case-sensitive. - The message left by the alert will be removed. **Example** ---- ~~~ PERFORM DBMS_ALERT.REMOVE('sample_alert'); ~~~ ---- **REMOVEALL** - REMOVEALL removes all alerts registered within a session. - All messages left by the alerts will be removed. **Example** ---- ~~~ PERFORM DBMS_ALERT.REMOVEALL(); ~~~ ---- **SIGNAL** - SIGNAL sends a message notification for the specified alert. - Specify the name of the alert for which message notifications are sent. - Alerts are case-sensitive. - In the message, specify the alert message for notifications. - Message notifications are not complete at the stage when SIGNAL is executed. Message notifications are sent upon committing the transaction. Message notifications are discarded if a rollback is performed after SIGNAL is executed. - If message notifications are sent for the same alert from multiple sessions, the messages will be accumulated without being removed. **Example** ---- ~~~ PERFORM DBMS_ALERT.SIGNAL('ALERT001','message001'); ~~~ ---- **Note** ---- If SIGNAL is issued continuously and the accumulated messages exceed a certain amount, an insufficient memory error may be output. If the memory becomes insufficient, call AITANY or WAITONE to receive an alert, and reduce the accumulated messages. ---- **WAITANY** - WAITANY waits for notification of any alerts registered for a session. - Specify the maximum wait time *timeout* in seconds to wait for an alert. - Use a SELECT statement to obtain the notified information, which is stored in the name, message and status columns. - The name column stores the alert names. The data type of name is TEXT. - The message column stores the messages of notified alerts. The data type of message is TEXT. - The status column stores the status code returned by the operation: 0-an alert occurred; 1-a timeout occurred. The data type of status is INTEGER. **Example** ---- ~~~ DECLARE alert_name TEXT := 'sample_alert'; alert_message TEXT; alert_status INTEGER; BEGIN SELECT name,message,status INTO alert_name,alert_message,alert_status FROM DBMS_ALERT.WAITANY(60); ~~~ ---- **WAITONE** - WAITONE waits for notification of the specified alert. - Specify the name of the alert to wait for. - Alerts are case-sensitive. - Specify the maximum wait time *timeout* in seconds to wait for the alert. - Use a SELECT statement to obtain the notified information, which is stored in the message and status columns. - The message column stores the messages of notified alerts. The data type of message is TEXT. - The status column stores the status code returned by the operation: 0-an alert occurred; 1-a timeout occurred. The data type of status is INTEGER. **Example** ---- ~~~ DECLARE alert_message TEXT; alert_status INTEGER; BEGIN SELECT message,status INTO alert_message,alert_status FROM DBMS_ALERT.WAITONE('sample_alert', 60); ~~~ ---- #### 6.1.2 Usage Example Below is a usage example of the processing flow of DBMS_ALERT. **DBMS_ALERT flow** ![DBMS_ALERT_flow](gif/DBMS_ALERT_flow.gif) **Note** ---- - The target of message notifications by SIGNAL is sessions for which REGISTER is executed at the time of executing SIGNAL. - On the receiving side, always ensure that REMOVE or REMOVEALL is used to remove alerts as soon as the alerts are no longer needed. If a session is closed without removing the alerts, it may no longer be possible to receive a SIGNAL for alerts of the same name in another session. - DBMS_ALERT and DBMS_PIPE use the same memory environment. Therefore, when insufficient memory is detected for DBMS_PIPE, it is possible that insufficient memory will also be detected for DBMS_ALERT. ---- **Usage example** - Sending side ~~~ CREATE FUNCTION send_dbms_alert_exe() RETURNS VOID AS $$ BEGIN PERFORM DBMS_ALERT.SIGNAL('sample_alert','SIGNAL ALERT'); END; $$ LANGUAGE plpgsql; SELECT send_dbms_alert_exe(); DROP FUNCTION send_dbms_alert_exe(); ~~~ - Receiving side ~~~ CREATE FUNCTION receive_dbms_alert_exe() RETURNS VOID AS $$ DECLARE alert_name TEXT := 'sample_alert'; alert_message TEXT; alert_status INTEGER; BEGIN PERFORM DBMS_ALERT.REGISTER(alert_name); SELECT message,status INTO alert_message,alert_status FROM DBMS_ALERT.WAITONE(alert_name,300); RAISE NOTICE 'Message : %', alert_message; RAISE NOTICE 'Status : %', alert_status; PERFORM DBMS_ALERT.REMOVE(alert_name); END; $$ LANGUAGE plpgsql; SELECT receive_dbms_alert_exe(); DROP FUNCTION receive_dbms_alert_exe(); ~~~ ### 6.2 DBMS_ASSERT **Overview** Performs verification of the properties of input values in PL/pgSQL. **Features** |Feature|Description| |:---|:---| |ENQUOTE_LITERAL|Returns the specified string enclosed in single quotation marks.| |ENQUOTE_NAME|Returns the specified string enclosed in double quotation marks.| |NOOP|Returns the specified string as is.| |OBJECT_NAME|Verifies if the specified string is a defined identifier.| |QUALIFIED_SQL_NAME|Verifies if the specified string is in the appropriate format as an identifier.| |SCHEMA_NAME|Verifies if the specified string is a defined schema.| |SIMPLE_SQL_NAME|Verifies if the specified string is in the appropriate format as a single identifier.| **Syntax** ![DBMS_ASSERT](gif/DBMS_ASSERT.gif) #### 6.2.1 Description of Features This section explains each feature of DBMS_ASSERT. **ENQUOTE_LITERAL** - ENQUOTE_LITERAL returns the specified string enclosed in single quotation marks. - Specify a string enclosed in single quotation marks. - The data type of the return value is VARCHAR. **Example** ---- ~~~ DECLARE q_literal VARCHAR(256); BEGIN q_literal := DBMS_ASSERT.ENQUOTE_LITERAL('literal_word'); ~~~ ---- **ENQUOTE_NAME** - ENQUOTE_NAME returns the specified string enclosed in double quotation marks. - Specify a string enclosed in double quotation marks. - For lowercase conversion, specify TRUE or FALSE. Specify TRUE to convert uppercase characters in the string to lowercase. If FALSE is specified, conversion to lowercase will not take place. The default is TRUE. - If all the characters in the string are lowercase, they will not be enclosed in double quotation marks. - The data type of the return value is VARCHAR. **See** ---- Refer to "The SQL Language" > "Data Types" > "Boolean Type" in the PostgreSQL Documentation for information on boolean type (TRUE/FALSE) values. ---- **Example** ---- ~~~ DECLARE dq_literal VARCHAR(256); BEGIN dq_literal := DBMS_ASSERT.ENQUOTE_NAME('TBL001'); ~~~ ---- **NOOP** - NOOP returns the specified string as is. - Specify a string. - The data type of the return value is VARCHAR. **Example** ---- ~~~ DECLARE literal VARCHAR(256); BEGIN literal := DBMS_ASSERT.NOOP('NOOP_WORD'); ~~~ ---- **OBJECT_NAME** - OBJECT_NAME verifies if the specified string is a defined identifier. - Specify the identifier for verification. If the identifier has been defined, the specified identifier will be returned. Otherwise, the following error will occur. ~~~ ERROR: invalid object name ~~~ - The data type of the return value is VARCHAR. **Example** ---- ~~~ DECLARE object_name VARCHAR(256); BEGIN object_name := DBMS_ASSERT.OBJECT_NAME('SCM001.TBL001'); ~~~ ---- **QUALIFIED_SQL_NAME** - QUALIFIED_SQL_NAME verifies if the specified string is in the appropriate format as an identifier. - Specify the identifier for verification. If the string can be used as an identifier, the specified identifier will be returned. Otherwise, the following error will occur. ~~~ ERROR: string is not qualified SQL name ~~~ - The data type of the return value is VARCHAR. **See** ---- Refer to "The SQL Language" > "Lexical Structure" > "Identifiers and Key Words" in the PostgreSQL Documentation for information on the formats that can be used as identifiers. ---- **Example** ---- ~~~ DECLARE object_name VARCHAR(256); BEGIN object_name := DBMS_ASSERT.QUALIFIED_SQL_NAME('SCM002.TBL001'); ~~~ ---- **SCHEMA_NAME** - SCHEMA_NAME verifies if the specified string is a defined schema. - Specify a schema name for verification. If the schema has been defined, the specified schema name will be returned. Otherwise, the following error will occur. ~~~ ERROR: invalid schema name ~~~ - The data type of the return value is VARCHAR. **Example** ---- ~~~ DECLARE schema_name VARCHAR(256); BEGIN schema_name := DBMS_ASSERT.SCHEMA_NAME('SCM001'); ~~~ ---- **SIMPLE_SQL_NAME** - SIMPLE_SQL_NAME verifies if the specified string is in the appropriate format as a single identifier. - Specify an identifier for verification. If the specified string can be used as an identifier, the specified identifier will be returned. Otherwise, the following error will occur. ~~~ ERROR: string is not qualified SQL name ~~~ - The data type of the return value is VARCHAR. **See** ---- Refer to "The SQL Language" > "Lexical Structure" > "Identifiers and Key Words" in the PostgreSQL Documentation for information on the formats that can be used as identifiers. Note that an error will occur if an identifier using fullwidth characters is specified. If fullwidth characters are included, specify a quoted identifier. ---- **Example** ---- ~~~ DECLARE simple_name VARCHAR(256); BEGIN simple_name := DBMS_ASSERT.SIMPLE_SQL_NAME('COL01'); ~~~ ---- #### 6.2.2 Usage Example A usage example of DBMS_ASSERT is shown below. ~~~ CREATE FUNCTION dbms_assert_exe() RETURNS VOID AS $$ DECLARE w_schema VARCHAR(20) := 'public'; w_table VARCHAR(20) := 'T1'; w_object VARCHAR(40); BEGIN PERFORM DBMS_ASSERT.NOOP(w_schema); PERFORM DBMS_ASSERT.SIMPLE_SQL_NAME(w_table); PERFORM DBMS_ASSERT.SCHEMA_NAME(w_schema); w_object := w_schema || '.' || w_table; PERFORM DBMS_ASSERT.QUALIFIED_SQL_NAME(w_object); PERFORM DBMS_ASSERT.OBJECT_NAME(w_object); RAISE NOTICE 'OBJECT : %', DBMS_ASSERT.ENQUOTE_LITERAL(w_object); RAISE NOTICE 'TABLE_NAME : %', DBMS_ASSERT.ENQUOTE_NAME(w_table); END; $$ LANGUAGE plpgsql; SELECT dbms_assert_exe(); DROP FUNCTION dbms_assert_exe(); ~~~ ### 6.3 DBMS_OUTPUT **Overview** Sends messages to clients such as psql from PL/pgSQL. **Features** |Feature|Description| |:---|:---| |ENABLE|Enables features of this package.| |DISABLE|Disables features of this package.| |SERVEROUTPUT|Controls whether messages are sent.| |PUT|Sends messages.| |PUT_LINE|Sends messages with a newline character appended.| |NEW_LINE|Sends a newline character.| |GET_LINE|Retrieves a line from the message buffer.| |GET_LINES|Retrieves multiple lines from the message buffer.| **Syntax** ![DBMS_OUTPUT](gif/DBMS_OUTPUT.gif) #### 6.3.1 Description This section explains each feature of DBMS_OUTPUT. **ENABLE** - ENABLE enables the use of PUT, PUT_LINE, NEW_LINE, GET_LINE, and GET_LINES. - With multiple executions of ENABLE, the value specified last is the buffer size (in bytes). Specify a buffer size from 2000 to 1000000. - The default value of the buffer size is 20000. If NULL is specified as the buffer size, 1000000 will be used. - If ENABLE has not been executed, PUT, PUT_LINE, NEW_LINE, GET_LINE, and GET_LINES are ignored even if they are executed. **Example** ---- ~~~ PERFORM DBMS_OUTPUT.ENABLE(20000); ~~~ ---- **DISABLE** - DISABLE disables the use of PUT, PUT_LINE, NEW_LINE, GET_LINE, and GET_LINES. - Remaining buffer information is discarded. **Example** ---- ~~~ PERFORM DBMS_OUTPUT.DISABLE(); ~~~ ---- **SERVEROUTPUT** - SERVEROUTPUT controls whether messages are sent. - Specify TRUE or FALSE for *sendMsgs*. - If TRUE is specified, when PUT, PUT_LINE, or NEW_LINE is executed, the message is sent to a client such as psql and not stored in the buffer. - If FALSE is specified, when PUT, PUT_LINE, or NEW_LINE is executed, the message is stored in the buffer and not sent to a client such as psql. **See** ---- Refer to "The SQL Language" > "Data Types" > "Boolean Type" in the PostgreSQL Documentation for information on boolean type (TRUE/FALSE) values. ---- **Example** ---- ~~~ PERFORM DBMS_OUTPUT.SERVEROUTPUT(TRUE); ~~~ ---- **PUT** - PUT sets the message to be sent. - The string is the message to be sent. - When TRUE is specified for SERVEROUTPUT, the messages are sent to clients such as psql. - When FALSE is specified for SERVEROUTPUT, the messages are retained in the buffer. - PUT does not append a newline character. To append a newline character, execute NEW_LINE. - If a string longer than the buffer size specified in ENABLE is sent, an error occurs. **Example** ---- ~~~ PERFORM DBMS_OUTPUT.PUT('abc'); ~~~ ---- **PUT_LINE** - PUT_LINE sets the message to be sent appended with a newline character. - The string is the message to be sent. - When TRUE is specified for SERVEROUTPUT, the messages are sent to clients such as psql. - When FALSE is specified for SERVEROUTPUT, the messages are retained in the buffer. - If a string longer than the buffer size specified in ENABLE is sent, an error occurs. **Example** ---- ~~~ PERFORM DBMS_OUTPUT.PUT_LINE('abc'); ~~~ ---- **NEW_LINE** - NEW_LINE appends a newline character to the message created with PUT. - When TRUE is specified for SERVEROUTPUT, the messages are sent to clients such as psql. - When FALSE is specified for SERVEROUTPUT, the messages are retained in the buffer. **Example** ---- ~~~ PERFORM DBMS_OUTPUT.NEW_LINE(); ~~~ ---- **GET_LINE** - GET_LINE retrieves a line from the message buffer. - Use a SELECT statement to obtain the retrieved line and status code returned by the operation, which are stored in the line and status columns. - The line column stores the line retrieved from the buffer. The data type of line is TEXT. - The status column stores the status code returned by the operation: 0-completed successfully; 1-failed because there are no more lines in the buffer. The data type of status is INTEGER. - If GET_LINE or GET_LINES is executed and then PUT, PUT_LINE or PUT_LINES is executed while messages that have not been retrieved from the buffer still exist, the messages not retrieved from the buffer will be discarded. **Example** ---- ~~~ DECLARE buff1 VARCHAR(20); stts1 INTEGER; BEGIN SELECT line,status INTO buff1,stts1 FROM DBMS_OUTPUT.GET_LINE(); ~~~ ---- **GET_LINES** - GET_LINES retrieves multiple lines from the message buffer. - Specify the number of lines to retrieve from the buffer. - Use a SELECT statement to obtain the retrieved lines and the number of lines retrieved, which are stored in the lines and numlines columns. - The lines column stores the lines retrieved from the buffer. The data type of lines is TEXT. - The numlines column stores the number of lines retrieved from the buffer. If this number is less than the number of lines requested, then there are no more lines in the buffer. The data type of numlines is INTEGER. - If GET_LINE or GET_LINES is executed and then PUT, PUT_LINE, or NEW_LINE is executed while messages that have not been retrieved from the buffer still exist, the messages not retrieved from the buffer will be discarded. **Example** ---- ~~~ DECLARE buff VARCHAR(20)[10]; stts INTEGER := 10; BEGIN SELECT lines, numlines INTO buff,stts FROM DBMS_OUTPUT.GET_LINES(stts); ~~~ ---- #### 6.3.2 Usage Example A usage example of DBMS_OUTPUT is shown below. ~~~ CREATE FUNCTION dbms_output_exe() RETURNS VOID AS $$ DECLARE buff1 VARCHAR(20); buff2 VARCHAR(20); stts1 INTEGER; stts2 INTEGER; BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT(FALSE); PERFORM DBMS_OUTPUT.PUT('DBMS_OUTPUT TEST 1'); PERFORM DBMS_OUTPUT.NEW_LINE(); PERFORM DBMS_OUTPUT.PUT_LINE('DBMS_OUTPUT TEST 2'); SELECT line,status INTO buff1,stts1 FROM DBMS_OUTPUT.GET_LINE(); SELECT line,status INTO buff2,stts2 FROM DBMS_OUTPUT.GET_LINE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT(TRUE); PERFORM DBMS_OUTPUT.PUT_LINE(buff1); PERFORM DBMS_OUTPUT.PUT_LINE(buff2); END; $$ LANGUAGE plpgsql; SELECT dbms_output_exe(); DROP FUNCTION dbms_output_exe(); ~~~ ### 6.4 DBMS_PIPE **Overview** Performs communication between sessions that execute PL/pgSQL. This package can be used for 1:1 communication, such as when data is being exchanged between sessions executing PL/pgSQL. For pipes, there are explicit pipes and implicit pipes, and furthermore, for explicit pipes, you can select public pipes and private pipes. The characteristics of each type are as follows: **Types of pipes** |Type|Characteristics| |:---|:---| |Explicit pipe|- CREATE_PIPE is used to create a pipe explicitly.
- While creating a pipe,
you can select between a public pipe and private pipe.
- It is necessary to use REMOVE_PIPE to explicitly remove a pipe.| |Implicit pipe|- Created automatically when SEND_MESSAGE and RECEIVE_MESSAGE are used.
- The pipe that is created becomes a public pipe.
- When messages are received using RECEIVE_MESSAGE,
if there are no additional messages remaining in the pipe,
the pipe will be removed automatically.| |Public pipe|- Can be created as an explicit pipe or implicit pipe.
- Can also be used by users other than the creator.| |Private pipe|- Can only be created as an explicit pipe.
- Can only be used by its creator.| **Note** ---- - Up to 50 pipes can be used concurrently by a single instance. - In cases where pipes are frequently created and removed repetitively, use public pipes. If you create a private pipe, internal information (the creator of the private pipe) will remain even after the pipe is removed. Thus, repeatedly creating and removing pipes may ultimately cause memory to run out. - If a timeout occurs without receiving a message when an implicit pipe is created by RECEIVE_MESSAGE, the pipe will not be removed. ---- **Features** |Feature|Description| |:---|:---| |CREATE_PIPE|Creates a public or private pipe.| |NEXT_ITEM_TYPE|Determines the data type of the next item in the local buffer, and returns that type.| |PACK_MESSAGE|Sets a message in the local buffer.| |PURGE|Empties the contents of the specified pipe.| |RECEIVE_MESSAGE|Sets a received message in the local buffer.| |REMOVE_PIPE|Removes the specified pipe.| |RESET_BUFFER|Resets the set position of the local buffer.| |SEND_MESSAGE|Sends the contents of the local buffer.| |UNIQUE_SESSION_NAME|Returns a unique session name.| |UNPACK_MESSAGE_BYTEA|Receives a message in the local buffer in BYTEA type.| |UNPACK_MESSAGE_DATE|Receives a message in the local buffer in DATE type.| |UNPACK_MESSAGE_NUMBER|Receives a message in the local buffer in NUMERIC type.| |UNPACK_MESSAGE_RECORD|Receives a message in the local buffer in RECORD type.| |UNPACK_MESSAGE_TEXT|Receives a message in the local buffer in TEXT type.| |UNPACK_MESSAGE_TIMESTAMP|Receives a message in the local buffer in TIMESTAMP type.| **Syntax** ![DBMS_PIPE](gif/DBMS_PIPE.gif) #### 6.4.1 Description of Features This section explains each feature of DBMS_PIPE. **CREATE_PIPE** - CREATE_PIPE explicitly creates a pipe environment for data communication. - Specify the name of the pipe to be created. - Pipe names are case-sensitive. - Specify the maximum number of messages that can be sent or received. If omitted, 0 (cannot send messages) will be used. Specify from 1 to 32767. - Specify TRUE or FALSE for *private*. If TRUE is specified, a private pipe will be created. If FALSE is specified, a public pipe will be created. The default is FALSE. - An error will occur if a pipe of the same name has already been created. **See** ---- Refer to "The SQL Language" > "Data Types" > "Boolean Type" in the PostgreSQL Documentation for information on boolean type (TRUE/FALSE) values. --- **Example** ---- ~~~ PERFORM DBMS_PIPE.CREATE_PIPE('P01', 100, FALSE); ~~~ ---- **NEXT_ITEM_TYPE** - NEXT_ITEM_TYPE returns the next data type in the local buffer. - The data type of the return value is INTEGER. One of the following values is returned: **Values returned by NEXT_ITEM_TYPE** |Return value|Data type| |:---|:---| |9|NUMERIC type| |11|TEXT type| |12|DATE type| |13|TIMESTAMP type| |23|BYTEA type| |24|RECORD type| |0|No data in the buffer| **Example** ---- ~~~ DECLARE i_iType INTEGER; BEGIN i_iType := DBMS_PIPE.NEXT_ITEM_TYPE(); ~~~ ---- **PACK_MESSAGE** - PACK_MESSAGE sets the specified message in the local buffer. - Specify the data to be set in the local buffer. The following data types can be used: - Character type (\*1) - Integer type (\*2) - NUMERIC type - DATE type - TIMESTAMP type (\*3) - BYTEA type - RECORD type \*1: The character type is converted internally to TEXT type. \*2: The integer type is converted internally to NUMERIC type. \*3: The TIMESTAMP type is converted internally to TIMESTAMP WITH TIME ZONE type. - Each time PACK_MESSAGE is called, a new message is added to the local buffer. - The size of the local buffer is approximately 8 KB. However, each message has overhead, so the total size that can be stored is actually less than 8 KB. To clear the local buffer, send a message (SEND_MESSAGE), or reset the buffer (RESET_BUFFER) to its initial state. **Example** ---- ~~~ PERFORM DBMS_PIPE.PACK_MESSAGE('Message Test001'); ~~~ ---- **PURGE** - PURGE removes the messages in the pipe. - Specify the name of the pipe for which the messages are to be removed. - Pipe names are case-sensitive. **Example** ---- ~~~ PERFORM DBMS_PIPE.PURGE('P01'); ~~~ ---- **Note** ---- When PURGE is executed, the local buffer is used to remove the messages in the pipe. Therefore, if there are any messages remaining in the pipe, the local buffer will be overwritten by PURGE. ---- **RECEIVE_MESSAGE** - RECEIVE_MESSAGE receives messages that exist in the specified pipe, and sets those messages in the local buffer. - Messages are received in the units in which they are sent to the pipe by SEND_MESSAGE. Received messages are removed from the pipe after being set in the local buffer. - Specify the name of the pipe for which the messages are to be received. - Pipe names are case-sensitive. - Specify the maximum wait time *timeout* in seconds to wait for a message. If omitted, the default is 31536000 seconds (1 year). - The data type of the return value is INTEGER. If a message is received successfully, 0 is returned. If a timeout occurs, 1 is returned. **Example** ---- ~~~ DECLARE i_Ret INTEGER; BEGIN i_Ret := DBMS_PIPE.RECEIVE_MESSAGE('P01', 60); ~~~ ---- **REMOVE_PIPE** - REMOVE_PIPE removes the specified pipe. - Specify the name of the pipe to be removed. - Pipe names are case-sensitive. **Example** ---- ~~~ PERFORM DBMS_PIPE.REMOVE_PIPE('P01'); ~~~ ---- **RESET_BUFFER** - RESET_BUFFER resets the set position of the local buffer. Any unnecessary data remaining in the local buffer can be discarded using this operation. **Example** ---- ~~~ PERFORM DBMS_PIPE.RESET_BUFFER(); ~~~ ---- **SEND_MESSAGE** - SEND_MESSAGE sends data stored in the local buffer to the specified pipe. - Specify the name of the pipe that the data is to be sent to. - Pipe names are case-sensitive. - Specify the maximum wait time *timeout* in seconds for sending data stored in the local buffer. If omitted, the default is 31536000 seconds (1 year). - Specify the maximum number of messages that can be sent or received. If omitted, the maximum number of messages set in CREATE_PIPE is used. If omitted in the implicit pipe, the number of messages will be unlimited. Specify from 1 to 32767. - If the maximum number of messages is specified in both SEND_MESSAGE and CREATE_PIPE, the larger of the values will be used. - The data type of the return value is INTEGER. If a message is received successfully, 0 is returned. If a timeout occurs, 1 is returned. **Example** ---- ~~~ DECLARE i_Ret INTEGER; BEGIN i_Ret := DBMS_PIPE.SEND_MESSAGE('P01', 10, 20); ~~~ ---- **Note** ---- A timeout will occur during sending if the maximum number of messages is reached, or if the message being sent is too large. If a timeout occurs, use RECEIVE_MESSAGE to receive any messages that are in the pipe. ---- **UNIQUE_SESSION_NAME** - UNIQUE_SESSION_NAME returns a name that is unique among all the sessions. This name can be used as the pipe name. - Multiple calls from the same session always return the same name. - The data type of the return value is VARCHAR. Returns a string of up to 30 characters. **Example** ---- ~~~ DECLARE p_Name VARCHAR(30); BEGIN p_Name := DBMS_PIPE.UNIQUE_SESSION_NAME(); ~~~ ---- **UNPACK_MESSAGE_BYTEA** - NPACK_MESSAGE_BYTEA receives BTYEA type messages in the local buffer. - Messages are received in the unit set in the local buffer by PACK_MESSAGE. Received messages are removed from the local buffer. - The data type of the return value is BYTEA. - If no messages exist in the local buffer, a NULL value is returned. - For the data type, it is necessary to align with the data type set by PACK_MESSAGE. If the data type is different, the following error will occur. ~~~ ERROR: datatype mismatch DETAIL: unpack unexpected type: xx ~~~ **Example** ---- ~~~ DECLARE g_Bytea BYTEA; BEGIN g_Bytea := DBMS_PIPE.UNPACK_MESSAGE_BYTEA(); ~~~ ---- **UNPACK_MESSAGE_DATE** - UNPACK_MESSAGE_DATE receives DATE type messages in the local buffer. - Messages are received in the unit set in the local buffer by PACK_MESSAGE. Received messages are removed from the local buffer. - The data type of the return value is DATE. - If no messages exist in the local buffer, a NULL value is returned. - For the data type, it is necessary to align with the data type set by PACK_MESSAGE. If the data type is different, the following error will occur. ~~~ ERROR: datatype mismatch DETAIL: unpack unexpected type: xx ~~~ **Example** ---- ~~~ DECLARE g_Date DATE; BEGIN g_Date := DBMS_PIPE.UNPACK_MESSAGE_DATE(); ~~~ ---- **Note** ---- If the "oracle" schema is set in search_path, the DATE type of orafce will be used, so for receiving data, use UNPACK_MESSAGE_TIMESTAMP. UNPACK_MESSAGE_DATE is the interface for the DATE type of PostgreSQL. ---- **UNPACK_MESSAGE_NUMBER** - UNPACK_MESSAGE_NUMBER receives NUMERIC type messages in the local buffer. - Messages are received in the unit set in the local buffer by PACK_MESSAGE. Received messages are removed from the local buffer. - The data type of the return value is NUMERIC. - If no messages exist in the local buffer, a NULL value is returned. - For the data type, it is necessary to align with the data type set by PACK_MESSAGE. If the data type is different, the following error will occur. ~~~ ERROR: datatype mismatch DETAIL: unpack unexpected type: xx ~~~ **Example** ---- ~~~ DECLARE g_Number NUMERIC; BEGIN g_Number := DBMS_PIPE.UNPACK_MESSAGE_NUMBER(); ~~~ ---- **UNPACK_MESSAGE_RECORD** - UNPACK_MESSAGE_RECORD receives RECORD type messages in the local buffer. - Messages are received in the unit set in the local buffer by PACK_MESSAGE. Received messages are removed from the local buffer. - The data type of the return value is RECORD. - If no messages exist in the local buffer, a NULL value is returned. - For the data type, it is necessary to align with the data type set by PACK_MESSAGE. If the data type is different, the following error will occur. ~~~ ERROR: datatype mismatch DETAIL: unpack unexpected type: xx ~~~ **Example** ---- ~~~ DECLARE msg1 TEXT; status NUMERIC; BEGIN SELECT col1, col2 INTO msg1, status FROM DBMS_PIPE.UNPACK_MESSAGE_RECORD(); ~~~ ---- **UNPACK_MESSAGE_TEXT** - UNPACK_MESSAGE_TEXT receives TEXT type messages in the local buffer. - Messages are received in the unit set in the local buffer by PACK_MESSAGE. Received messages are removed from the local buffer. - The data type of the return value is TEXT. - If no messages exist in the local buffer, a NULL value is returned. - For the data type, it is necessary to align with the data type set by PACK_MESSAGE. If the data type is different, the following error will occur. ~~~ ERROR: datatype mismatch DETAIL: unpack unexpected type: xx ~~~ **Example** ---- ~~~ DECLARE g_Text TEXT; BEGIN g_Text := DBMS_PIPE.UNPACK_MESSAGE_TEXT(); ~~~ ---- **UNPACK_MESSAGE_TIMESTAMP** - UNPACK_MESSAGE_TIMESTAMP receives TIMESTAMP WITH TIME ZONE type messages in the local buffer. - Messages are received in the unit set in the local buffer by PACK_MESSAGE. Received messages are removed from the local buffer. - The data type of the return value is TIMESTAMP WITH TIME ZONE. - If no messages exist in the local buffer, a NULL value is returned. - For the data type, it is necessary to align with the data type set by PACK_MESSAGE. If the data type is different, the following error will occur. ~~~ ERROR: datatype mismatch DETAIL: unpack unexpected type: xx ~~~ **Example** ---- ~~~ DECLARE g_Timestamptz TIMESTAMP WITH TIME ZONE; BEGIN g_Timestamptz := DBMS_PIPE.UNPACK_MESSAGE_TIMESTAMP(); ~~~ ---- #### 6.4.2 Usage Example Below is a usage example of the processing flow of DBMS_PIPE. **Flow of DBMS_PIPE** ![DBMS_PIPE_flow](gif/DBMS_PIPE_flow.gif) **Note** ---- - When CREATE_PIPE is used to explicitly create a pipe, ensure to use REMOVE_PIPE to remove the pipe. If a pipe is not removed explicitly, once created, it will remain until the instance is stopped. - In the flow diagram, CREATE_PIPE and REMOVE_PIPE are described on the receiving side, however, these can be executed on the sending side. In order to maintain consistency, it is recommended to create and remove pipes on one side. - An error will occur for CREATE_PIPE if a pipe of the same name already exists. Implicitly created pipes are also the target of SEND_MESSAGE and RECEIVE_MESSAGE, so when executing CREATE_PIPE, ensure that SEND_MESSAGE and RECEIVE_MESSAGE are not called beforehand. - DBMS_ALERT and DBMS_PIPE use the same memory environment. Therefore, when insufficient memory is detected for DBMS_ALERT, it is possible that insufficient memory will also be detected for DBMS_PIPE. ---- **Information** ---- The information of pipes that are in use can be viewed in the DBMS_PIPE.DB_PIPES view. ~~~ SELECT * from dbms_pipe.db_pipes; name | items | size | limit | private | owner ------+-------+------+-------+---------+------- P01 | 1 | 18 | 100 | f | (1 row) ~~~ ---- **Usage example** - Sending side ~~~ CREATE FUNCTION send_dbms_pipe_exe(IN pipe_mess text) RETURNS void AS $$ DECLARE pipe_name text := 'sample_pipe'; pipe_time timestamp := current_timestamp; pipe_stat int; BEGIN PERFORM DBMS_PIPE.RESET_BUFFER(); PERFORM DBMS_PIPE.PACK_MESSAGE(pipe_mess); PERFORM DBMS_PIPE.PACK_MESSAGE(pipe_time); pipe_stat := DBMS_PIPE.SEND_MESSAGE(pipe_name); RAISE NOTICE 'PIPE_NAME: % SEND Return Value =%', pipe_name, pipe_stat; END; $$ LANGUAGE plpgsql; SELECT send_dbms_pipe_exe('Sample Message.'); DROP FUNCTION send_dbms_pipe_exe(text); ~~~ - Receiving side ~~~ CREATE FUNCTION receive_dbms_pipe_exe() RETURNS void AS $$ DECLARE pipe_name text := 'sample_pipe'; pipe_text text; pipe_nume numeric; pipe_date date; pipe_time timestamp with time zone; pipe_byte bytea; pipe_reco record; pipe_item int; pipe_stat int; BEGIN pipe_stat := DBMS_PIPE.RECEIVE_MESSAGE(pipe_name,300); RAISE NOTICE 'Return Value = %', pipe_stat; LOOP pipe_item := DBMS_PIPE.NEXT_ITEM_TYPE(); RAISE NOTICE 'Next Item : %', pipe_item; IF (pipe_item = 9) THEN pipe_nume := DBMS_PIPE.UNPACK_MESSAGE_NUMBER(); RAISE NOTICE 'Get Message : %' ,pipe_nume; ELSIF (pipe_item =11) THEN pipe_text := DBMS_PIPE.UNPACK_MESSAGE_TEXT(); RAISE NOTICE 'Get Message : %' ,pipe_text; ELSIF (pipe_item = 12) THEN pipe_date := DBMS_PIPE.UNPACK_MESSAGE_DATE(); RAISE NOTICE 'Get Message : %' ,pipe_date; ELSIF (pipe_item = 13) THEN pipe_time := DBMS_PIPE.UNPACK_MESSAGE_TIMESTAMP(); RAISE NOTICE 'Get Message : %' ,pipe_time; ELSIF (pipe_item = 23) THEN pipe_byte := DBMS_PIPE.UNPACK_MESSAGE_BYTEA(); RAISE NOTICE 'Get Message : %' ,pipe_byte; ELSIF (pipe_item = 24) THEN pipe_reco := DBMS_PIPE.UNPACK_MESSAGE_RECORD(); RAISE NOTICE 'Get Message : %' ,pipe_reco; ELSE EXIT; END IF; END LOOP; PERFORM DBMS_PIPE.REMOVE_PIPE(pipe_name); END; $$ LANGUAGE plpgsql; SELECT receive_dbms_pipe_exe(); DROP FUNCTION receive_dbms_pipe_exe(); ~~~ ### 6.5 DBMS_RANDOM **Overview** Generates random numbers in PL/pgSQL. **Features** |Feature|Description| |:---|:---| |INITIALIZE|Initializes the generation of random numbers.| |NORMAL|Returns a normally distributed random number.| |RANDOM|Generates a random number.| |SEED|Resets the seed value.| |STRING|Generates a random string.| |TERMINATE|Terminates generation of random numbers.| |VALUE|Generates a random decimal number between 0 and 1, or between specified values.| **Syntax** ![DBMS_RANDOM](gif/DBMS_RANDOM.gif) #### 6.5.1 Description of Features This section explains each feature of DBMS_RANDOM. **INITIALIZE** - INITIALIZE initializes the generation of random numbers using the specified seed value. - For *seedVal*, specify a SMALLINT or INTEGER type. **Example** ---- ~~~ PERFORM DBMS_RANDOM.INITIALIZE(999); ~~~ ---- **NORMAL** - NORMAL generates and returns a normally distributed random number. - The return value type is DOUBLE PRECISION. **Example** ---- ~~~ DECLARE d_RunNum DOUBLE PRECISION; BEGIN d_RunNum := DBMS_RANDOM.NORMAL(); ~~~ ---- **RANDOM** - RANDOM generates and returns a random number. - The data type of the return value is INTEGER. **Example** ---- ~~~ DECLARE d_RunInt INTEGER; BEGIN d_RunInt := DBMS_RANDOM.RANDOM(); ~~~ ---- **SEED** - SEED initializes the generation of a random number using the specified seed value or seed string. - For *seedVal*, specify a SMALLINT or INTEGER type. - Any string can be specified for the seed string. **Example** ---- ~~~ PERFORM DBMS_RANDOM.SEED('123'); ~~~ ---- **STRING** - STRING generates and returns a random string in accordance with the specified display format and string length. - For the display format *fmt*, specify any of the following values. An error will occur if any other value is specified. **Values that can be specified for the display format** |Setting value|Generated string| |:---|:---| |'u', 'U'|Uppercase letters only| |'l', 'L'|Lowercase letters only| |'a', 'A'|Mixture of uppercase and lowercase letters| |'x', 'X'|Uppercase letters and numbers| |'p', 'P'|Any displayable character| - Specify the length of the string to be generated. Specify a SMALLINT or INTEGER type. - The data type of the return value is TEXT. **Example** ---- ~~~ DECLARE d_RunStr TEXT; BEGIN d_RunStr := DBMS_RANDOM.STRING('a', 20); ~~~ ---- **TERMINATE** - Call TERMINATE to terminate generation of random numbers. **Information** TERMINATE does not do anything, but has been included for compatibility with Oracle databases. **Example** ---- ~~~ PERFORM DBMS_RANDOM.TERMINATE(); ~~~ ---- **VALUE** - VALUE generates and returns a random number within the specified range. - For *min* and *max*, specify a numeric data type. A random number between and inclusive of the minimum value and maximum value is generated. - If the minimum value and maximum value are omitted, a random decimal number between 0 and 1 will be generated. - The data type of the return value is DOUBLE PRECISION. **Example** ---- ~~~ DECLARE d_RunDbl DOUBLE PRECISION; BEGIN d_RunDbl := DBMS_RANDOM.VALUE(); ~~~ ---- #### 6.5.2 Usage Example A usage example of DBMS_RANDOM is shown below. ~~~ CREATE FUNCTION dbms_random_exe() RETURNS VOID AS $$ DECLARE w_rkey VARCHAR(10) := 'rnd111'; i_rkey INTEGER := 97310; BEGIN PERFORM DBMS_RANDOM.INITIALIZE(i_rkey); RAISE NOTICE 'RANDOM -> NORMAL : %', DBMS_RANDOM.NORMAL(); RAISE NOTICE 'RANDOM -> RANDOM : %', DBMS_RANDOM.RANDOM(); RAISE NOTICE 'RANDOM -> STRING : %', DBMS_RANDOM.STRING('a',10); RAISE NOTICE 'RANDOM -> VALUE : %', DBMS_RANDOM.VALUE(); PERFORM DBMS_RANDOM.SEED(w_rkey); RAISE NOTICE 'RANDOM -> NORMAL : %', DBMS_RANDOM.NORMAL(); RAISE NOTICE 'RANDOM -> RANDOM : %', DBMS_RANDOM.RANDOM(); RAISE NOTICE 'RANDOM -> STRING : %', DBMS_RANDOM.STRING('p',10); RAISE NOTICE 'RANDOM -> VALUE : %', DBMS_RANDOM.VALUE(1,100); PERFORM DBMS_RANDOM.TERMINATE(); END; $$ LANGUAGE plpgsql; SELECT dbms_random_exe(); DROP FUNCTION dbms_random_exe(); ~~~ ### 6.6 DBMS_UTILITY **Overview** Provides utilities of PL/pgSQL. **Features** |Feature|Description| |:---|:---| |FORMAT_CALL_STACK|Returns the current call stack.| **Syntax** ![DBMS_UTILITY](gif/DBMS_UTILITY.gif) #### 6.6.1 Description of Features This section explains each feature of DBMS_UTILITY. **FORMAT_CALL_STACK** - FORMAT_CALL_STACK returns the current call stack of PL/pgSQL. - For the display format fmt, specify any of the following values. An error will occur if any other value is specified. **Values that can be specified for the display format** |Setting value|Displayed content| |:---:|:---| |'o'|Standard-format call stack display (with header)| |'s'|Standard-format call stack display (without header)| |'p'|Comma-delimited call stack display (without header)| - If the display format is omitted, display format 'o' will be used. - The data type of the return value is TEXT. **Example** ---- ~~~ DECLARE s_StackTrace TEXT BEGIN s_StackTrace := DBMS_UTILITY.FORMAT_CALL_STACK(); ~~~ ---- **Note** ---- If a locale other than English is specified for the message locale, the call stack result may not be retrieved correctly. To correctly retrieve the call stack result, specify English as the message locale. ---- #### 6.6.2 Usage Example A usage example of DBMS_UTILITY is shown below. ~~~ CREATE FUNCTION dbms_utility1_exe() RETURNS VOID AS $$ DECLARE s_StackTrace TEXT; BEGIN s_StackTrace := DBMS_UTILITY.FORMAT_CALL_STACK(); RAISE NOTICE '%', s_StackTrace; END; $$ LANGUAGE plpgsql; CREATE FUNCTION dbms_utility2_exe() RETURNS VOID AS $$ BEGIN PERFORM dbms_utility1_exe(); END; $$ LANGUAGE plpgsql; SELECT dbms_utility2_exe(); DROP FUNCTION dbms_utility2_exe(); DROP FUNCTION dbms_utility1_exe(); ~~~ ### 6.7 UTL_FILE **Overview** Text files can be written and read using PL/pgSQL. To perform these file operations, the directory for the operation target must be registered in the UTL_FILE.UTL_FILE_DIR table beforehand. Use the INSERT statement as the database administrator or a user who has INSERT privileges to register the directory. Also, if the directory is no longer necessary, delete it from the same table. Refer to "Registering and Deleting Directories" for information on the how to register and delete the directory. Declare the file handler explained hereafter as follows in PL/pgSQL: ~~~ DECLARE f UTL_FILE.FILE_TYPE; ~~~ **Features** |Feature|Description| |:---|:---| |FCLOSE|Closes a file.| |FCLOSE_ALL|Closes all files open in a session.| |FCOPY|Copies a whole file or a contiguous portion thereof.| |FFLUSH|Flushes the buffer.| |FGETATTR|Retrieves the attributes of a file.| |FOPEN|Opens a file.| |FREMOVE|Deletes a file.| |FRENAME|Renames a file.| |GET_LINE|Reads a line from a text file.| |IS_OPEN|Checks if a file is open.| |NEW_LINE|Writes newline characters.| |PUT|Writes a string.| |PUT_LINE|Appends a newline character to a string and writes the string.| |PUTF|Writes a formatted string.| **Syntax** ![UTL_FILE](gif/UTL_FILE.gif) #### 6.7.1 Registering and Deleting Directories Registering the directory 1 . Check if the directory is already registered (if it is, then step 2 is not necessary). ~~~ SELECT * FROM UTL_FILE.UTL_FILE_DIR WHERE dir='/home/pgsql'; ~~~ 2 . Register the directory. ~~~ INSERT INTO UTL_FILE.UTL_FILE_DIR VALUES('/home/pgsql'); ~~~ **Deleting the directory** ~~~ DELETE FROM UTL_FILE.UTL_FILE_DIR WHERE dir='/home/pgsql'; ~~~ #### 6.7.2 Description This section explains each feature of UTL_FILE. **FCLOSE** - FCLOSE closes a file that is open. - Specify an open file handle. - The value returned is a NULL value. **Example** ---- ~~~ f := UTL_FILE.FCLOSE(f); ~~~ ---- **FCLOSE_ALL** - FCLOSE_ALL closes all files open in a session. - Files closed with FCLOSE_ALL can no longer be read or written. **Example** ---- ~~~ PERFORM UTL_FILE.FCLOSE_ALL(); ~~~ ---- **FCOPY** - FCOPY copies a whole file or a contiguous portion thereof. The whole file is copied if *startLine* and *endLine* are not specified. - Specify the directory location of the source file. - Specify the source file. - Specify the directory where the destination file will be created. - Specify the name of the destination file. - Specify the line number at which to begin copying. Specify a value greater than 0. If not specified, 1 is used. - Specify the line number at which to stop copying. If not specified, the last line number of the file is used. **Example** ---- ~~~ PERFORM UTL_FILE.FCOPY('/home/pgsql', 'regress_pgsql.txt', '/home/pgsql', 'regress_pgsql2.txt'); ~~~ ---- **FFLUSH** - FFLUSH forcibly writes the buffer data to a file. - Specify an open file handle. **Example** ---- ~~~ PERFORM UTL_FILE.FFLUSH(f); ~~~ ---- **FGETATTR** - FGETATTR retrieves file attributes: file existence, file size, and information about the block size of the file. - Specify the directory where the file exists. - Specify the relevant file name. - Use a SELECT statement to obtain the file attributes, which are stored in the fexists, file_length, and blocksize columns. - The fexists column stores a boolean (TRUE/FALSE) value. If the file exists, fexists is set to TRUE. If the file does not exist, fexists is set to FALSE. The data type of fexists is BOOLEAN. - The file_length column stores the length of the file in bytes. If the file does not exist, file_length is NULL. The data type of file_length is INTEGER. - The blocksize column stores the block size of the file in bytes. If the file does not exist, blocksize is NULL. The data type of blocksize is INTEGER. **Example** ---- ~~~ SELECT fexists, file_length, blocksize INTO file_flag, file_len, size FROM UTL_FILE.FGETATTR('/home/pgsql', 'regress_pgsql.txt'); ~~~ ---- **FOPEN** - FOPEN opens a file. - Specify the directory where the file exists. - Specify the file name. - Specify the mode for opening the file: r: Read w: Write a: Add - Specify the maximum string length (in bytes) that can be processed with one operation. If omitted, the default is 1024. Specify a value from 1 to 32767. - Up to 50 files per session can be open at the same time. **Example** ---- ~~~ f := UTL_FILE.FOPEN('/home/pgsql','regress_pgsql.txt','r',1024); ~~~ ---- **FREMOVE** - FREMOVE deletes a file. - Specify the directory where the file exists. - Specify the file name. **Example** ---- ~~~ PERFORM UTL_FILE.FREMOVE('/home/pgsql', 'regress_pgsql.txt'); ~~~ ---- **FRENAME** - FRENAME renames a file. - Specify the directory location of the source file. - Specify the source file to be renamed. - Specify the directory where the renamed file will be created. - Specify the new name of the file. - Specify whether to overwrite a file if one exists with the same name and in the same location as the renamed file. If TRUE is specified, the existing file will be overwritten. If FALSE is specified, an error occurs. If omitted, FALSE is set. **See** ---- Refer to "The SQL Language" > "Data Types" > "Boolean Type" in the PostgreSQL Documentation for information on boolean type (TRUE/FALSE) values. ---- **Example** ---- ~~~ PERFORM UTL_FILE.FRENAME('/home/pgsql', 'regress_pgsql.txt', '/home/pgsql', 'regress_pgsql2.txt', TRUE); ~~~ ---- **GET_LINE** - GET_LINE reads a line from a file. - Specify the file handle returned by FOPEN using r (read) mode. - Specify the number of bytes to read from the file. If not specified, the maximum string length specified at FOPEN will be used. - The return value is the buffer that receives the line read from the file. - Newline characters are not loaded to the buffer. - An empty string is returned if a blank line is loaded. - Specify the maximum length (in bytes) of the data to be read. Specify a value from 1 to 32767. If not specified, the maximum string length specified at FOPEN is set. If no maximum string length is specified at FOPEN, 1024 is set. - If the line length is greater than the specified number of bytes to read, the remainder of the line is read on the next call. - A NO_DATA_FOUND exception will occur when trying to read past the last line. **Example** ---- ~~~ buff := UTL_FILE.GET_LINE(f); ~~~ ---- **IS_OPEN** - IS_OPEN checks if a file is open. - Specify the file handle. - The return value is a BOOLEAN type. TRUE represents an open state and FALSE represents a closed state. **See** ---- Refer to "The SQL Language" > "Data Types" > "Boolean Type" in the PostgreSQL Documentation for information on boolean type (TRUE/FALSE) values. ---- **Example** ---- ~~~ IF UTL_FILE.IS_OPEN(f) THEN PERFORM UTL_FILE.FCLOSE(f); END IF; ~~~ ---- **NEW_LINE** - NEW_LINE writes one or more newline characters. - Specify an open file handle. - Specify the number of newline characters to be written to the file. If omitted, "1" is used. **Example** ---- ~~~ PERFORM UTL_FILE.NEW_LINE(f, 2); ~~~ ---- **PUT** - PUT writes a string to a file. - Specify the file handle that was opened with FOPEN using w (write) or a (append). - Specify the string to be written to the file. - The maximum length (in bytes) of the string to be written is the maximum string length specified at FOPEN. - PUT does not append a newline character. To append a newline character, execute NEW_LINE. **Example** ---- ~~~ PERFORM UTL_FILE.PUT(f, 'ABC'); ~~~ ---- **PUT_LINE** - PUT_LINE appends a newline character to a string and writes the string. - Specify the file handle that was opened with FOPEN w (write) or a (append). - Specify whether to forcibly write to the file. If TRUE is specified, file writing is forced. If FALSE is specified, file writing is asynchronous. If omitted, FALSE will be set. - The maximum length of the string (in bytes) is the maximum string length specified at FOPEN. **Example** ---- ~~~ PERFORM UTL_FILE.PUT_LINE(f, 'ABC', TRUE); ~~~ ---- **PUTF** - PUTF writes a formatted string. - Specify the file handle that was opened with FOPEN w (write) or a (append). - Specify the format, which is a string that includes the formatting characters \n and %s. - The \n in the format is code for a newline character. - Specify the same number of input values as there are %s in the format. Up to a maximum of five input values can be specified. The %s in the format are replaced with the corresponding input characters. If an input value corresponding to %s is not specified, it is replaced with an empty string. **Example** ---- ~~~ PERFORM UTL_FILE.PUTF(f, '[1=%s, 2=%s, 3=%s, 4=%s, 5=%s]\n', '1', '2', '3', '4', '5'); ~~~ ---- #### 6.7.3 Usage Example The procedure when using UTL_FILE, and a usage example, are shown below. 1 . Preparation Before starting a new job that uses UTL_FILE, register the directory in the UTL_FILE.UTL_FILE_DIR table. Refer to "Registering and Deleting Directories" for information on how to register the directory. 2 . Performing a job Perform a job that uses UTL_FILE. The example is shown below. ~~~ CREATE OR REPLACE FUNCTION gen_file(mydir TEXT, infile TEXT, outfile TEXT, copyfile TEXT) RETURNS void AS $$ DECLARE v1 VARCHAR(32767); inf UTL_FILE.FILE_TYPE; otf UTL_FILE.FILE_TYPE; BEGIN inf := UTL_FILE.FOPEN(mydir, infile,'r',256); otf := UTL_FILE.FOPEN(mydir, outfile,'w'); v1 := UTL_FILE.GET_LINE(inf,256); PERFORM UTL_FILE.PUT_LINE(otf,v1,TRUE); v1 := UTL_FILE.GET_LINE(inf,256); PERFORM UTL_FILE.PUTF(otf,'%s\n',v1); v1 := UTL_FILE.GET_LINE(inf, 256); PERFORM UTL_FILE.PUT(otf,v1); PERFORM UTL_FILE.NEW_LINE(otf); PERFORM UTL_FILE.FFLUSH(otf); inf := UTL_FILE.FCLOSE(inf); otf := UTL_FILE.FCLOSE(otf); PERFORM UTL_FILE.FCOPY(mydir, outfile, mydir, copyfile, 2, 3); PERFORM UTL_FILE.FRENAME(mydir, outfile, mydir, 'rename.txt'); END; $$ LANGUAGE plpgsql; SELECT gen_file('/home/pgsql', 'input.txt', 'output.txt', 'copyfile.txt'); ~~~ 3 . Post-processing If you remove a job that uses UTL_FILE, delete the directory information from the UTL_FILE.UTL_FILE_DIR table. Ensure that the directory information is not being used by another job before deleting it. Refer to "Registering and Deleting Directories" for information on how to delete the directory. orafce-VERSION_3_9_0/doc/orafce_documentation/gif/000077500000000000000000000000001362147214200220355ustar00rootroot00000000000000orafce-VERSION_3_9_0/doc/orafce_documentation/gif/ADD_MONTHS.gif000066400000000000000000000044671362147214200242170ustar00rootroot00000000000000GIF89a?p!M,?3f++3+f+++UU3UfUUU3f3f3fՙ3f3333f3333+3+33+f3+3+3+3U3U33Uf3U3U3U3333f3333333f3333333f3ՙ333333f333ff3ffffff+f+3f+ff+f+f+fUfU3fUffUfUfUff3fffffff3fffffff3fffՙffff3fffff3f̙++3+f++̙+UU3UfUU̙U3f̙3f̙3fՙ̙3f̙3f++3+f+++UU3UfUUÙ̀3̀f̪̪̀̀̀3̪f̪̪̪3fՙ3f3f++3+f+++UU3UfUUU3f3f3fՙ3f H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ`ÊKٳhӪ]˶۷pʝKݻx˷߿ LÈ+^̸ǐ#KL˘3k̹ϠCMӨS^ͺװc˞M۸sͻ1Nȓ+_μУK܀Գ~s=| ˛_9X wԟ+}m4Jo 2ԠI:X ET>:BaV@#rT"NtFX(cT3Vb]#P#C>4c ڇЍ1N=6 d=鐕(#[hLX%Ey%}Hl)2zAa7&WQِ6 )%HC&QI"q.:\K0)@ Y@ĽU'Ba )A g5|z͖7cD  f+@ 4 z~m PK_ )#nHNhAĜ+d)R1dAm1> `._=PZoR#Z#r}7 K-*4p 7 s~ hB_˜ 4>+ۂL$^f [01٪`le\%yL*ڂ3IqhqN+21{dզN+9g]Z>Kҽ}EZ z7<&D/o7zAgp=)I! M(N42NyAo D@|X'1)<{zPܸSD^|"p; 5t붙Lp;ANJY9}< @P- W!Fqw4 : @4)0K\pkK{i 29Bum4`T,LJ5X@UIkUhE.(c<7Ȅ7'"-׿5#Th f`MkM"MRG'F0QYBЇJ!Y0 #.Kp O)%XҚ&u,I~Z^+D& ^{D(ի]Ug٥\3vz!b+[8YR@cIZ23>-BW[dBUzJ>@F@ aEUkNa) /pRyVIq:"ٹ{8ӌ>;t*t[@ "}s T-P|6,U2 ԣ)H lӤu6_Әzӟ0G̥Ћٴ8]OoTBx ?R754Im'bԫ(PYEalG%>sO6)qXU6EG˫^׾Ω`;v9@:bc"'% ժd'KZͬf7z hGKҚMjWֺlgKͭnw5J@;orafce-VERSION_3_9_0/doc/orafce_documentation/gif/BITAND.gif000066400000000000000000000036241362147214200234720ustar00rootroot00000000000000GIF89a5p!:,53f++3+f+++UU3UfUUU3f3f3fՙ3f3333f3333+3+33+f3+3+3+3U3U33Uf3U3U3U3333f3333333f3333333f3ՙ333333f333ff3ffffff+f+3f+ff+f+f+fUfU3fUffUfUfUff3fffffff3fffffff3fffՙffff3fffff3f̙++3+f++̙+UU3UfUU̙U3f̙3f̙3fՙ̙3f̙3f++3+f+++UU3UfUUÙ̀3̀f̪̪̀̀̀3̪f̪̪̪3fՙ3f3f++3+f+++UU3UfUUU3f3f3fՙ3f H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ`ÊKٳhӪ]˶۷pʝKݻx˷ LÈ+^L8C#v˘Sfh9 ;{MhK7 `j놯;^8f턷3.g}+wMT<1C8ȉ;~2@kywu޼Ygw7);JbTOiTG[xW27 ne>7`r &WaH (P tCA(:Hx &"B/`$wi ؐL܄8ЎF;>Z 9*8M$thP&bP$Bh3@3[m,֙fVOfyZA@L`FY`F)~g( j!AyХ)SoXvK*FW&p*N+A쳑'i"D卼!yPaՓ@i+[Ԇ[Тؙ@bXu+ nL@f $ "%Ζ!P.ho"kB>͛0B徫pA10hb|vGyEƮJfQInd5rHl5۰Tb ]LӃn,:2![VKݮLt_kc*Sg>19,e1(=Ҫ0nF 1}7 W,/0>):2@7l8Kkh뎎:F;ʌ-ۼ{z0M9uMgK;>o\?HD2ӽπ/דa$g2-2폂A]pyӦ,h b|5Q>B&n$ p9&aBH3\J AP7E Ey \B.z0`(F1)H!5pH:x̣> IBL"F:򑐌H;orafce-VERSION_3_9_0/doc/orafce_documentation/gif/BTRIM.gif000066400000000000000000000046201362147214200234030ustar00rootroot00000000000000GIF89alVp!H,lV3f++3+f+++UU3UfUUU3f3f3fՙ3f3333f3333+3+33+f3+3+3+3U3U33Uf3U3U3U3333f3333333f3333333f3ՙ333333f333ff3ffffff+f+3f+ff+f+f+fUfU3fUffUfUfUff3fffffff3fffffff3fffՙffff3fffff3f̙++3+f++̙+UU3UfUU̙U3f̙3f̙3fՙ̙3f̙3f++3+f+++UU3UfUUÙ̀3̀f̪̪̀̀̀3̪f̪̪̪3fՙ3f3f++3+f+++UU3UfUUU3f3f3fՙ3f H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ`ÊKٳhӪ]˶۷pʝKݻx˷߿7È+6cǐ#KLeɍkެG A͹闤7FZnӰc|}6Anqͻ޻!Ǜ.uC7N#߾PA1*3l^ [OItG~. X߁}F~@ 1Mc&yVQXfFdvbah>OcX&)]B_zʘ 'dhTa$ٞPbO5)F{!dfbi#h¦c "tCzhy"['g@AugAiП CLc@>)i]BhBfvzm+^ya8P@&i*NjV.6:KLrhP3Z*r 4I橨1(S@'aeٸ9R+B{;kx@04$\ZyefaKn-6~ƺ:.j 6 < w.D dʙI>(P&,#1*b؊{-naela↋"e2X3LY;wh)DRd\`-wQm[TwniϭwPwVŽ< =N9.j 3wYe]wιʑn:K߯>nf:~N?wi2aG/=d*dUw=nk' _ѭT쟉8Va_RUN,# qw6O|X8~Wy`#"[@0h7۟7R!E!Fd 0䈈pÇf=jUx9jJ 35!Y sB'Qy:7#b1l 7 :/>ZlC!qx,ѱ"EU~I3"| Y;&.Y& >XTH%h!t7Ɲeӓf>wB%2%`&]Nd䵲/qDF\ϺУ%`m4*)S]x2gBDD[OG"J3O8*%.H Ĝ8y&W\d6~ bbGlIQR41Jg4 8( 2 +aE™tN!& RV/ܨˆJPfZϞAzr/(tE0vR,2]<&LЗ} Wh I^.UR@u)W##S[+ Tu])LXU*[WjSd)O%?d]+t'w+3تDtzHv`Fng*DŽڕ(1SԸv5,lM"[p,F@V,ks) =@;̕S:ͮ=C~r xK)Mz|Kͯ~]@;orafce-VERSION_3_9_0/doc/orafce_documentation/gif/COSH.gif000066400000000000000000000034771362147214200232730ustar00rootroot00000000000000GIF89a7p!>,73f++3+f+++UU3UfUUU3f3f3fՙ3f3333f3333+3+33+f3+3+3+3U3U33Uf3U3U3U3333f3333333f3333333f3ՙ333333f333ff3ffffff+f+3f+ff+f+f+fUfU3fUffUfUfUff3fffffff3fffffff3fffՙffff3fffff3f̙++3+f++̙+UU3UfUU̙U3f̙3f̙3fՙ̙3f̙3f++3+f+++UU3UfUUÙ̀3̀f̪̪̀̀̀3̪f̪̪̪3fՙ3f3f++3+f+++UU3UfUUU3f3f3fՙ3f H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ`ÊKٳhӪ]˶۷pʝKݻx˷߿ LÈǐ#KL˘3Qqϖ9S ӨH:]M6Kq}7JYΐ8I U9HQN:G_~;FI ."峻Lo0﹞o9cnǑ2b 2בq4{eR]cEHM $^sqD$@̘ Ch9h`m j'\&b^XX`a4Hp(P=P H$Bb89$ @ cTF[ ȘRF&E0@Aaf$2 hA1xCZM)yh"቙@Ydx$!J~{vbB@h8!X=yj$'3IC b$O#, Qu&TH)bCjH()SO:@ĐKAeO@TMeخ>B꼙xY22t1w 12,/qBN@0h ١<> 4 eBB'ݳgG QkiVt676-j.` cKbH*'ڥ g杭]q߀-߄}xߋ+q 6g0nؘ 6 ~I  myk4 CNCF Dk.l'O?>bCre_-"?qO*yg=^Ϟ%FEw߻ERFy:~D@7@QX(9E#~9M.k7ۈsGHBզ1 W\I gH8̡w!@ H"HL&:Ph;orafce-VERSION_3_9_0/doc/orafce_documentation/gif/DATE.gif000066400000000000000000000022761362147214200232500ustar00rootroot00000000000000GIF89a0p!3,03f++3+f+++UU3UfUUU3f3f3fՙ3f3333f3333+3+33+f3+3+3+3U3U33Uf3U3U3U3333f3333333f3333333f3ՙ333333f333ff3ffffff+f+3f+ff+f+f+fUfU3fUffUfUfUff3fffffff3fffffff3fffՙffff3fffff3f̙++3+f++̙+UU3UfUU̙U3f̙3f̙3fՙ̙3f̙3f++3+f+++UU3UfUUÙ̀3̀f̪̪̀̀̀3̪f̪̪̪3fՙ3f3f++3+f+++UU3UfUUU3f3f3fՙ3f H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟcJѣH*]4PF}JqOT#b5î:z](gY $7@1@4O&zz& V^Jy&X ȝ9jEnrZm7jqܨ4h=Kԓ@ڈʨP&$N* Ĭ @=k eg*џ,)@:$'h*Fh1"t;%zz')lR)Z*d0rn|sd|o 3HݜZ}~4pAK[<9;` KKLAdIAA7Dks3-zO qc-C#~"|nWgݥJK@bçGqˈfbꜴd;B'7?n2Khxܱ΍j|=݇0'iZi  ?hɯѷSJٗ͆gS5k4lhB$DJAA$$_ülmm(XS%lym }h( ó!> yBLbC\&*kqb*V̢c.j"X/ƌdL#cĨ6hB6s`>Ȏ~ ZB h$"CődJ FIZ,K&/Iqf (RRxA)WUŕ%hKY?.yR<#!0^Ř%2drn3%)MTs0r^m3n= NĜgyL P ٿ Y3(3D(@N|IL`ahLY%ْT`l/yѫu`Z@bRl^ L4*Ę["'-l1fW5dbjTi)rӺ^oڟ '2gmt[Ev&}LfA#}EԹr.ӬA6j*XͶv%o6mga[X$zQ5MÞ 㭀 8m'(G9n8絡o D \%}Uصjɹ:@pZUWhOWR.pLzcEN&,$8ŖVݸ 5H>tNB1|:4[R#iu{zk^ g@A=jpZ^Y*l)iZkӵi9=TTӔյ!i{'M%ζr\sn6}$oܦ~םX̮ͻ}by޽%P ߷&%Js|l$H{xV$qQ*82"{A>|Y?MSsajISd<=/tz~o3M?zC#+Qv@|F;CCUwzg龹"֙;^Gwgw`Nc_=gX-~6^o&H(b8~=1ϢB&5z\6>H8]9~gQ`WyG9~9Lفtmԑ$ ي&iJ$id)!ْ`$FdMC,:AyT7AO6@Wr|'uuɃȔ!C`HtIIXi֕xC #t`1':Fshyu x)Nns uq\rt wpx%by&Q2|'})JisyIɗٌ٘蔐yx]eE7,ɖS(/pwyc3)~YfihrhY,5XՆ5I j؅nhU޳'}4ܲ]Xn˙-#4(\../B/9i۹h?~IU5b*2jx(b]s1UeƠvj-7=tzb4@70h-d_ZGhI\ %:r('f&BAՙ֝Ή3 xe'Zu0u88@*Tx&SUV.*b)/h;h's2w)4A%QI2sÛniLhwzd@OC9u 9DvF,Y"\ߕT̅UÆj|*25z255.6Y`8''ZҜ(~:5|u8HU 7vâ,`b,T8Yj  ~bqR&F /*yeU452/>]ZQʦOw&ZlXp:#cZ0)גܣ-r]uÊPچtq޵-/ ǹ]5h4+J]ɴO#+ r: Kٟ躙i^;uhjD1g< Ds۶q ĘEG;˰a{mR19mډWt$#KM;mi[N[;2++H E V$KZd)id c$€KYdՈš6,J2!* 5k<U4qk*@F9D,I/Ky<'| y_VN?lEl ;kQȈAk.nl\eT{7 ,OU'V0S M"e2#\ٲjRtpo|\&p& S\WTM/}uԐmV3eN'rՄ06f:Ұ<ӫ}]EM@]דCOU,/:b =̺M%2(!iE.+B~Qݭΐd>&ꑾ宾뜑^~a!럞BөažN;λ~NZ^>`lnN.'^^慨Nʾ"_Q^? 3N~v<9)<ϯ޵fyI@\7$ͭp-Oə>SEQt [ه|>.8N4//N:[o.l\ewgo~HUE5mhCV̉cb%OЊ-#|_Γedb +Nb'Hϳ;c|vF-M/X0mqr&lܨ݄,!6bU~,cnn=%VL]5N`U f1+^SO_ݲ4}Tu5gk=.Wb>1DPB .`D%R|!#c&3} bRQ3 SN5^XŸC5TRMDt_ԕĠ,x`Iݘ2 *X"m*iz7ZQGSr k! ܇l.i(LoNHbI/.ӥ]釙`" z2Ăs<FoFbz mfgx ܗ}R(d F{_?"fx.J#J즵̋nl"eTFB*ϧԊBTH90,=/54Kr'-B I#J2 cJ&7d -eJRjG/"JmG$Ѽ C6+E4\C&}V idKIhPKبbp:.7b:v܎4TSB+FCZέ؂Xu*LJ\J,6Z,GguHfQvYi%Vnzu[je7ޅ7^yj7y7_}m(M÷^!e`ޗ^/a=8@!h)p܊!7V0dI6YnQٔ3X_FTdh9X~xFg׼\yݣY蒝M&ZiVsТf7ڧZm~[܋l[o֗9卻pGx'x"G>ygy矇>z駧z>{{0 ;orafce-VERSION_3_9_0/doc/orafce_documentation/gif/DBMS_ALERT_flow.gif000066400000000000000000000115371362147214200252360ustar00rootroot00000000000000GIF89ap!I,3f++3+f+++UU3UfUUU3f3f3fՙ3f3333f3333+3+33+f3+3+3+3U3U33Uf3U3U3U3333f3333333f3333333f3ՙ333333f333ff3ffffff+f+3f+ff+f+f+fUfU3fUffUfUfUff3fffffff3fffffff3fffՙffff3fffff3f̙++3+f++̙+UU3UfUU̙U3f̙3f̙3fՙ̙3f̙3f++3+f+++UU3UfUUÙ̀3̀f̪̪̀̀̀3̪f̪̪̪3fՙ3f3f++3+f+++UU3UfUUU3f3f3fՙ3f H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ`ÊKٳhӪ]˶۷pʝKݻx˷߿ LÈ+^̸We"K`e 3_ə%nb}'Ξc5"q&ydߑ YYk12UVvCLdؤĈ!\ 3G6ppeW@u͟N7s紁O~@1>֛W յVY= !Xo)X1 x mJHar`hy&uawAZTbiA DaoO 0QGIw4ã`e_uEz$Zz O֘&ѷQVez#}g\A}rj@ Ac@ dwmycA(\t>yhfivhvA\fF'xe@+Dg]&ArZ>&(z@~'%m[߰re^zy@h(hX!FgC ⮪(b(I s{#g)T|yo6乐j蜺K@f>it)p]J&$܊}A+`i # q##}fX2/s3|s> XCT5Y[g}]z-G]{cMۮp-tmb|Uv߀߂nXXWG.Wn.x砇~碗nzG9.n;L߮;.<o7{N^|ث}}g}|o觯>Aӯ>߿/aon? cӾp/;˒:, |PD Z̠7p`T"H|&J OBŅ* GɆ3 01aR("%F4J;#Q!$PsU1ڏ*,g%Kt𶶚bb,5ql5JI軪KS +zxKiG̑12R+cJFLd"U.Ji5'%̋5B1;ܖҺ K^#veU%FDHu s/BFfc+L8A@uMzK@'4R/u}ğI$?VCVtoazP0T'LD Ģ&EqQnt~IH?*9(MJAS8T.#[L_ړͦ4(pSrO=M OJѡFKJ2u6NX}*]7Ju?\U1rGږ VEmͭlfVUv5U+|Z`jk=YTNeRd# Rd1۳rv+Wh?k+=mRZ,lK(f{mmnXep%qdz\zR=MnT(֮έg+]Č%}޸ Cny{0ͮ)ĭmWJ/]w)e|B."^)TxyVn2|̢$& `Y&x'02ILj* eBə@U$ :y<qNE+RL>qLG8jf͒H&͙$_Yh-%"7 ˢvweEV) $bv.;JW 'y&E9MJι g[RʷtoO}D^8=g7ΔNb.[m'S ADO?.1n81LIBT=ᄚyykڬ#?7F?JTVY^] vm3n w>:cK+^u{QY=zA|NF= ^%q|Q'.{y)+7Oڒ&eo؏$[EE= #?땿yg>G(/_$o_O|[&g]N_r>\O[]kP%u?Mv8[<xhd/';luFchldFF9g~e6U5}]h$(jñ,yhQus~w(7Iusvn8$;a KXmKH LMXcdr.$[1Z/] b2wqh%j؆iނ3 1&lz Gv3(6dpH/$@.8h'Hha2hQ4-$؆hK!$I2 $؋$H dkϘ !AxA8*TD tretbn%'!n"2 ʰbbHhx4/t Yy1Ɛ!Nl-9 $#YX(y*IXIL gr +f 8BA $k!(A RIGNٔPPISAB'He*ƓIz8wg~wW陂%qG񆚿Vך*a4I6$a)G%19C,dԃHǜ 1 aG!!Zι{Շѝ)i!ťٛiI)˹1矅^:<%Y-ZZq̓4Y$0;=1?qHh_IF^T=>z`\ڥ^_ZjqcYdD>DZgwiYk*̥E63J"&qb&E4"LEd-L`xw2!4O+cF!um dr:%"0"kަJ3dqY`YE$)qk&,;Nc,3+rIuzdxLsGBxGjۺ2kKLnmjNAgRVH JARj&„$zdc*'MMjMSѯd7K떋!*8RtVJ:Qjr.+: -,ֳH,rZ4k݂rgp!.NMV[+04mrngavPG)\$1^%vu2v0HEƤKv%fcT]`*8vڳT;zh 2AiEiۺA+([{[k<2u;[k;Ƽ;%{:֛ʽ1k9{p۾U[Rk;PۿZ3s)K|  '\| 7 /<$\&'5"-&,%L$l@Jċ  ,L\V|xJ(Xb< l dnƻ ,L5 xz/(Ȅaǂ\Ȇ|AȊɒԛ1:)#Qx|ɢ*ch=.i) +CZ@`fm=jPNDBOry7TꄰvZ ^)1tֺZ*fwb /O1kmA W淵 ]ajA׊ ͱQJ>bqir@bx)D=LPS 3j&Jl}Th2 &&dd NĮ. tQJI:{%hA[(@ _Qzr?bvE7B#5=zBK.GA]ׂNs>7x*`g&*c&o'@Кk=@*1!b_Y wdsJw$1)Odɼ?eynAރ(!$C_"؉I1h]36̖zdK>ޏ'UƷkGBH5Gf1aBanHDh"Bf+ΒCpO p#VF uY1#aŖ-fnbkȘ|B $:h4b{ xvW?|"a(E* !B8zQc&IJZr:.I|F"aL%"].UR +gYSbF^Fvi/I"H&bxffFa3Ihf̦eYYj&ar:F99t gao'`ȉ~EQ?*M(] {*t,X''I="PmXP!#]t5M)`6JǸ4)ahºTNSԤPR vT(?KLB-KT9R#ujA!DlWbU@$kVM*+IVbЩvY{Ե: 4 p CRR2A nD#(+4,{頰&T pѭ#Sļ[UvBXu4% `02謩 ?YH)1c.*`!{_#coE#ʡʐw=9?YPuxS9(9=`q 8FCgclD{hZ7EJF X|s||Â;Ic}'} و9yS! bHyYy}3yqUrҁZ)IH%BpYA/#c 熎UyLZcLÝ% ٙ噢DihdRp҆Rlt"t*BnIA4͒OwYvbJbY zye:VY5tJ-ڤliJjXɝP6ҡDT꫰IJj\؜UaJgڬSaҚEj*̺ح*Ozl۩(P*ڮ z7GgʯΘMa2{|隰(L kX;˪Z۱"Zx*d,k!0˱Y$8}9J;-E ZgY!k;՟lO+l)}ȴ7`N;HՖT;hk)A?r1V˨G+I[K{d岚m˵~Z%Dzۣ&s5@@ģ%e0B^yo󗷩ǟW'`㷌{\NVW2vǃS ? C1y Ao!!+1vۦ,({$@ؖ8B%"^Rv#qbAK_TAy 2]rBo~bvvA vrEw709ov>J!Uѳ6*()@wu Q+3y08`]F s8೟tALĕ}91HUqaSVlÿq(shÜ)^XppZc삧[R,mx9IZt$~Yckp,w8l Y'"QAIvArc1ҁcixK"8f,w۷k1SQ{ƕۃ2`)39)WaYe˙i0^ DǷ܇hl5DulSl|F!Dƍ|&6óOo[ɕ)D#Raˈsibk*$?g;S݌L%Їͪ–lе ҰЇ,v.caҫj˛nzܴ6+:N,gȳK :CY[ɩ4ۋ>MUmՀպx W8`Obe=d]gmۛT֨un=TpMm=:U^&21|Z~-br5g-S،ԒPj@]tʫy},A=اm֔D+q׮Om=T)ԾMQ&=@ zW%,  6-E;F ӝln9 }=(M %; G2=)Mͥ-큡yyT7dj?8̉"CӾ࣪oaʙ@ GYҹ[3,cW)ϙ } %gr9dΔc > b.,U̯7,|eaZ.!/g{5Ǿ}x J-O<շ (.,q0+Ra,!S-! ,c:|S=l>1w1ktqZ#9-C3)/͸27u%ҋM=t%8m¯(ͣ?647wBފ0[Þ3/.i 7% "5 C4Hmj̞$>͓刴 @Vc9'''D L2f~b"8LoW3nmQޢ;L.oF.U^!$Ҙh0<1(k$C;W*89 !ʣKʢ|y>lt]i{Yn8(7.@&a.=8i{ <)' y\Y|x&O.uKj NzwEq[ jE)_/NJ܈ԋO]1禿=S.Z.qܨ>ί]P/O{M/?T/Oo#qoNL`@ DPB >Qă+QĘQF=~RH%MDRʈYs!h2męSN=}:ePE gTRM>PUSRUV]~5X1.EVZmcun\uunޮX`*zbƍVب-_Ɯkd=9wZ蒟I{Zj֭!v}5lڵCö=bn޽}#Mō<%e͝?C \Ǟ]vݽ^x75^azݏw^tEY]~/Jo <;0j)"ep/[8hpk> @ 3TKMT6q{EJm~B9+H;ב=D=Bl˳onܕFH]xG[aekOOr=sd*TP@c 'SL[Q_f|볢K'gƠ๋-Xʺ3gӢi;.5 8h!UhlѦvm; R!0 9ntgW6Sql4₤m' O 6zfFAݞd0?_m.b+[?OvZOW8Kg;l ts3};ȵ>u3-9nQ;^y(vooOP.:Be{w|?xG|x7|%?yW|5yw}E?zҗG}C;orafce-VERSION_3_9_0/doc/orafce_documentation/gif/DBMS_OUTPUT.gif000066400000000000000000000165071362147214200244020ustar00rootroot00000000000000GIF89a3f++3+f+++UU3UfUUU3f3f3fՙ3f3333f3333+3+33+f3+3+3+3U3U33Uf3U3U3U3333f3333333f3333333f3ՙ333333f333ff3ffffff+f+3f+ff+f+f+fUfU3fUffUfUfUff3fffffff3fffffff3fffՙffff3fffff3f̙++3+f++̙+UU3UfUU̙U3f̙3f̙3fՙ̙3f̙3f++3+f+++UU3UfUUÙ̀3̀f̪̪̀̀̀3̪f̪̪̪3fՙ3f3f++3+f+++UU3UfUUU3f3f3fՙ3f!, H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ=oKٳhӪ]˶۷pK݋r̫߿(xY #~xKCN(y=+cy/;o i/>ͺub4 me!vu+̔a(/ӊK^sڵ@}ϵ+rS6XYVQ&5׿/ Alr!{ 1s II"1Qysi$x`(qMba> AΧ@hV({َ>sAޓԂCff+l=P0``5XwcRXj)'Wq!L7X9asFVqP(FYgz'Nq5TaN :I[vzCƩkPꪰf 뮼M֯` *,ZĪ!A[E.kbBZDۑJR+e KVktkիgʚ _zfN ;zm£;0Fl5,f5^>!Xi_k\ Y1 QIX  >sDA,BI3n a1b`yIcKO}Sg^'lCe;rcOJR>v,yt mRLBh$(|5ɀ[K6Aɘe˄G'6B33vW&hP)Y~ҵ4/pg+id4>G^s:Q oas"ƀtx8, 5Bɕ~ +4diQAVA,7`Fb?)o^0\JֳߑPგ2A6bZZ̄'Pó/ضՅn@| <&K @:шS5E*]!δ #O82CkGeeJxnch<2b4@^!FeLt$IZ2&m$(GNz(SJ" )Z2앶e ͧ^ޒ &q)bd32CCe:S$$3f:dvufp&Fhd#^:ߘ3|ڳa$E8O}.n?16.ԡT@SCN /79RvFЬ%̓dodF]ђq9|!ف.$7k:Jzd̨D7jŒIHrD?%w(9;㿘& RYJad!UBmhAԚ̇$mE+ xY̙p?+ 8!:Lyզ A]Tysv$Nav gS՞mK ˙RZ=s*g% ?%HpiSW=#"MrWY @â E0lZVUV^WyԬe@MJroIJ x[>&Y,~Q+!5d(Cwvc%x}2-k+]S0saW 0Z>d1SUbfeiL1gSkH>=+Sj)[;G-{_1ٻ?˨毮2fף0\y}@:b>4}he&фf4IҖ2+${[Hg=}g)@F-6e 8㻴֯Fd /*|{q9QKekbYV]l,̬=,׺IMmf;W/ߎvfm;v;c̲j],hڱdҞjUPZmw͑)i7px\ S29`nsh|3'³S%G19{5;E۱2Hs'1N"ىe00zxAM]pUSv ƂFx/־%6~3\o i}t(BҘ™ہtfP9uxǓ;A#M2$gBU Γ^9Alf1xh["RI'Y5 :Ȓ։?U IZ(ٛI1}׳ ` їa`5ƵIt8)C+ - yJ:~~9 K?=)*!ʠa2Q(3: (@/Yh7KxLnq13xj-70HbvoׇJ>J6Zi)J9 } |ʋ# A7*qi↣Y砎%wr.4jڑلjʛ@܈g4IJPęPv:&14iz*y |j?\%*:zũ)j `cJ5(ܲvu9lV&+Ex_,[C+2H4[t8{.lӳ>1:DF{0 J +I۴Pk:L;"V+U"zٱӗ~M!xZ +N+ vi: H"IdGJ(~jYM*|۷uaJ Kt۰kʯ+t;+ܙ2_څ&rR.:GŚ]*#Z[W }| sQKɟ;5=T0+(rڢzJh`|$]Uky 3ާ zl]0Z2TYYS돐f9ˠE{[M׋ƒG%P~HP; Aam<Dl7r[izM 6i*=YM+'8-z˭Gl*:8ʿQмtШmΙڶ̖W@ѩ@XLh@{&ژY !&L٫ l+h+@Jûͪ)|(JU鋺 kɕ~˼)۹j̳˪;a̤мּ̮,˧c<͙K[E olįu䶵\ )X[ϱr*|ϥ)]K-$}Џ -' Y=DRM/Ѩ"},]M(]].='^akf+$[HΫI< L̛4ԉ[p{P9ʌ)ɔ{ܲ\U-IJ\ʜJ_/~f! ak{_:֋e ˚j[ X`]kV7/a|TɤTz'9>e q0\|M_,ȣ$tj Wi4 L]p,PmL>ssX|cA?ҭ ]}֝ؽ=ݝa2sr9y}}9br>^~^hWeH== ~Ԣ-3-]}&(~.0>2^4nݨCH SWMȕ' }**=˜nŞ~{Ҟҿ^rNھ!>| ~a~<is&-,A] Oԯ /mL͘>x>zr['"o.2,չ&(?$Yۓޒ;_›vʎ48>Q.8\N0z'3Ѽ\y7OBMnAHڿS|TXWӊsZ2_-2L%ñe{\u-n$ ;?}."ND'XSLyg1!#~ ?SO@ pPaB dPD-^ĘQF#vƑ!MXF [z\)eL5m 1gΙ{JgP1ʤyRMO*u:jCU^ŚUV]~5*հe4kvZmS W\uksjݽyXහ 5Xbƍ6FXdʕ%GfΝ=6gҥMf j֭]g lڵ[n޽v pō6\r›3]Sӭ_Nzvݥ;_ x򗷗GտOoZ~1nH@D!AA'B 0 A üD9H *=5ԃL}UU@L2KuI0oZK] b40$—fBJeUOaR=H dՠ5t>7Lʳ*i;$d\2j[.=hb#SUjVZfUmwЄπoZ[:En }2Uv5'F -n7/5}nt  mvKjP2ƂIHzNt}gw=(ю% zIR 44xjYZb,jU(}e1;oֻAO9So?  {p;@'r/yW~& ҖvÌX7а7E|ɟa|^ɭT 0b R KnfBpx- * LUDW4yiy F!2lаS GXЅ$1SSf>Q f 5nE"Xf5S51x{Ă箪*˘ c.AwaC[Rӈ$]!GYʼnvy hni'LslU6*PL"IF&ɑMS"S'Vr %)IMBΓ=%3YMNSm UF?4%,@^r+%Z|9Lb2e2Lf6әτf49MjVӚf6Mnvӛg89NrӜDg:;orafce-VERSION_3_9_0/doc/orafce_documentation/gif/DBMS_PIPE.gif000066400000000000000000000445061362147214200240770ustar00rootroot00000000000000GIF89ap!W,000TTTYYY222{{{MMMLLLDDD***rrrPPP%%%QQQ ~~~vvvyyyGGGaaaoooŭZZZ:::333Ȍbbbfff```---@@@]]]񦦦www$$$HHHppp(((hhhxxxﯯ ߿888XXXɽ1B1mH W*\ȰÇm%4qbQ/jȱǏ2RȒ(S\ɲ%H8͛8sII< J\A<()ӧPJiDV(@YK˰*BٷpAB(h"+ A7F4˘3kfyD7P8Xh2"}a͸sލ!T6Z} TM|N2"҅?d b.;C˟ X Bܤ-)[|Wknd} 6PaHcŔM"dMe wmք_<ח5$3=(4a!EBU$,Tpc+6{#(T^tHTY-X`ˍS]l"Cf;ftY/jS!x矀瞞ɛ\Fi碌%:iLq5gf*ʣ%iLꩢjju&#BjQ*Jzn5+l3j챿ٚlT"˪"˩L5-f鴷Je+n.J{b$5\ 1djnn7 7xf$AEw˽Ěn"<Ю_N exAfՙ k 5_M8_Z[!81S,\wW !yJEGw[IVq˭@z%s7TmY٫)Y=r*/h#pqIor)Hމ 'H\æa(*=;t>UтX$t h3!_l R{j\e:d.K5̱.}1"(VX)rՄcUnu]$5!J4̂6:.E8̈́nʅ&d0xiYη^c@d:2*'C_y8AmJ W -.ir*TUD` KLL`:5JW )!tW ^ fb (Z3`t2ۧH ;y%8 G*ƎhvZ!֣^!zӣ>P-{N,PKCsMWx*$p5J˖`6(!oQDZdf ȶk8̪bXЍo5L 472O;W%: A#6j uN|. q;N8(m7~^7åQq0%whme g aY 5DN+^[gW㗃:C:kӃ;na*Ji=D-'V*XWZ8Ӷ8dh$yȇjLa5-X)jd›e9L2hNYW HZv,tH"CN½,&# !-z*A _,2V|rb ӕB@]g6G]f!^]wkU੏Z+lb_Yn=-2[kLM䥤.-M]fFn!t"Jm]>n4e/^ǹŃߑnPʀ7; L߲!{B֭=G^gr͍KR8px5\mypBDOrs/PIӏ[Vpַ^g`{.JY?ǜp{>^p帠Co_BOP oucENy[ސoLDγe:mBzߨGͻՎAO{۞긇~kM%~>9!(ٕINiyĝPyHQUf0hEcuXw~?".E_#Y 9EeSDn)a[PCh` hIE9dU;0Zk3H70VjbBzQ*"u3}JmLڟ(dY2H9UeZ3.zC$k~8Gfez4YS89AhwNy:/]K[Ơm *Va-BTkq8Z|?(_99cB* 2G9YVk՚97DoStS1 E/8D: "#Y{ z<̊ĩZ:V\%IVzj$' lӥ% p&뵰Kr ]˴|ռzgG'Ș(Ze2e2b;2 Ad" RC#a؈Uئ}ڨD`$}mlMSңÆ=Aⷖlܷ-^z9I;Շ ݂xqE =Olݒz޾i] Po졲 M]4ME]61em -qV,ut{] =a,~4n]8wv<B7@߇D>?^H^GL.P^oKTO\XO\nC`Wdc^h޹~g9<(֠ڮ)3D❘s~uv{;{>y݆r禼SNܐnb3莮țN@ ^>\BS1t..2#c"[㮮Ш5L3Za5ž@%F8)}+]_, MTsɧ_ s:DMKE8>^R>]=uf+Bjų+4@ EoxW$Y!0рz]_ˌ!C D-mqDK׼|l/0h%H cX|nĘ$ cz=Kyb dDH"Jv6o}Y/@oNN^n}MȘ(TQ. E$!|1HxZm>$ Nr!%1R2bJ4 atdȥL*=))H(MZ5Zqm#M6* ˑYyzPcDBU2=T^Vr}4`IUrT-R|EPyPa^0լi uٴkvwjKjHw-WEBjر ^ 0DoӯZ۝{"Щ^j @B.\r>n TrZz lu`N%XڙF_򴗑 [eHM0ωU!'=v.E؅ItQn 7p;|w_[wbݷ߂8n[c݈?Oζm9nk{oyیN:ԙky髝:ԮN;cz>$_Y,|[_U;;񯿽< }K!Q!* ~~_LV~Ol׏ p, 1*p l+Jpg]p?xp$, %A,l _Hp4 B.p<' qD,`g$*qLR(JQ9,ްSӢbd$q22EJK$8ASDpQ|;y!-Fe/~f::>򐔼M#')F0|YP&Γ^%W2rcu+J'jRl)SIErewˇ5%(y#:R &ގAYcd2Y!iRÙۤdMVn2Pt)N{6ߩCmreȉrRbTVэ9<ZC h&9A[©M2QQQBT`(BDnDe"iCi9Fy퓒s"cI.0og1jZǝ<vѬ?ZE!P3>K.E2.\ak\U!|h+i %9 O 8DS픬V/InccYIQ< z+}ޢpD:Z-$b*@X'$Į[Ы2EZz5C/vq$d'8-27^w pthKEcF+ ҁNV0wSF_R]~nџBf ]:ՆJrv]햊]G`D#U?DnС|m#u",:&:01DDZv d 3*G2pO/t/nmA,k*YƤzz $["~d4]P'+D/#YԘHJF|3 i͏+}W+:ӟ$h9WbXEs٧.I] %# \0Ơ f%Zcv`"U;aTz)k" 瘤L's Q透5I:ʑw JkxڊL׭?쪓f㗼ӯgZ눺ӡ ՚ 9 K: 昉CI`i"k6::z#I˱);E<{S8!+:E@l:'GРK&EJa9ۡ/V^KtV E[}״~S1jN:JbDd˓f{x .Q XYEioA"!_Ƿ} q;0e\%.! ^Vٙ[$[V& i$A/y_'˧; $ATrc.iA\0S%ىHH{EQSU Ë֩C!J^4Tٻ!el " ѫ(k zv84;8rЋYlCk \FGJKn ˴;6Ks!gl=+ a s:mD*è ݧ{Úü+A|N9h \qĸySRV%,lƬXYkE"̬ {la<$ ȉܔl1cOtZ&ƱOX7#Ƨ =vNwW=;oP5T GT9චOjp~l< +RFT!̱VuX%1~ۀX 6XWW2W[ 2,Je(%S8 KP]/ h$].cjyJ("a 4 6T;a[[[tYk\d<ܸҠ ĝ!TR7VM",XcH#:8#1n}aj_U% ȑG CO.J`&LJ-˷-\`u3՘Tj(ґ-"΃r Rq( GK뱐`*v,.f^T2cPccۍԀy7y =M06l̟-mט撥%+Zn]l= fn b* fn&pj+jh P vg@3P2"x-87 35#x ;>DyF'5jzڒ/bMjޢjj G_aeQQm TN|Ȑ`& GeŕPMw {;D^oo0|x蔅)X ب4I_ 鵬x ꭁ,l<|%5ёk α># z恜m>Ŀ^PРȯή֞켎̮~߰"Obe4(q~9DD#O4t O\*4}̣ocw!O7%?)-),1O&58t9Ǘ.i˹RG+4Zk(cMLU@O)[ y.c@eD=Wi*?Cn?Ykfy_{Jh#|ٲ9oʐ@Bnʾ22.#fʡݼ⌌6Lo߀svfxA@c] |la2x203ϼτЧۣ/?kQV_/D2 N2d@b1"c5zakUtN MMAEB1†DŽ7ʭEJBئ֑$bMZ%tBX+p 2 4ntcFL AAT6q)-a\ ¨lخR&JիXj:H*E^%*f βM\EH.K۴/=pf6HMA,@o$ M%Y.lVEEuH䯘3k̹g~=vTp׫adPU^LMnXqZj-hozZ궄jr KG7ڪ&1ËOуUt#%n x$;`3F w]T ]H R|MnRmC=f;mJUɹ;[,of7/ ˻⸋F,ċNjS7sV,$l%nz,l,4l8(9@ BmH'= J7PQWmX;u>[g`s]mhjpSttm݇m/|wz{^urG.$?nga~-P(1:y:NQ Nꠌr <2_'%Mcܗp۾o~+:ίhKYT IFQGb*i1OҫT"2U@$ˆ$ 8%2j"(\_&h\A;QR KGm) ("%ը$C ΊP 짤JX%)#jGNmST+i$\(%JDSYE6`>@a: "l;\'iHRMDӨm6ɂ'Ғ%E2:sDnIԅ$hd&~VrJelB|K7Ow֨J2hSGJJUJR_mKQ>p~/߼O;̰Sj.pGb 8!kW `Ƣ)qO Q~8t cʡ8KV^[(&[TD>}]ts2L27M6,pQA:۹csV9}]Aй-4h9ѐ`-J[`7]?טӠc2-Rr>WmyհfgZۺ:w]Nֳy.v(ULG(et&󦾻P{h)9=B8lA9FɎ$xJ Ny6ER 8M9Vy5QyZ5Yig(Bжӕz=Wqdi6fy3䘔XA(Qya*ev zBh4K i|cp |z`JAI {I` z̤@y7M Oz(}–mYp z`Q=ڐqexysP{7B114~(;ndR"!d'Y|jE$iHUhڠi ǦiN5h "!$ qԀ 1]2}qh xІjըb#:KXY;SBP @mT ѱ0tڂ=HPSСY2YDzzxy~ʘd#5\D^XF%9 Y vDI@q $pvxXB:h|,02;4[@$#<#Aat5N`,]Hĉ<?] #ںtxQ:'Gk yyɄ,؁f n:Ę7r6*}V㬎i2|+j8K< 6긒+Ӹt{iY3M(+XC4&6[溚B欴{Tb;{Ȼb*;.&{bػ`!;ŷ{"軾=j;{^ݫbgke6(ʩ;xV, _ ;y ú  j Œ[/ ##5ֈ1,8IÃ@mk?%6 CLz~T),4 ) sBKz#@ (A Aҹr*K@"~EP<M޼WK- \7{<36(^1%Β .0<46~:><@B>[F>NH߻LNR>T^{XZ^>`kh~'\g'k.m'M"8t3aY}^vǓ~̀^{9!Δzn%L^ 瞞kNg7\\Ǎ\$ ')Bfhl6#uB;F4Ti~aE NԞJ^gٞF,v_WLv1猎쏎7|Ꞹt@H]Z\ygںz,mRV2=޿N4jz~|ܢ0L x{ тUʠ—) Cx/.l7H W=ק O`'ͻ>jrw +Ձ<须BERLQ(R: h!ڱnjVIVUw14897VCx]OAIt?E|~wTGVx>%[JgYgYCp~ ?wH5māw>+{X:h8Lj 77 h]-KOyP*} UEhO0$P۞i^Zh߀ 8HXhxH!(P)9IYY)` Iى: +;K[k{k+* \l|K\~kL/?O_o?p-0… v#(I,wPE;z2dÍH&2)2el(Ĩ2̙4kٲ͝rm"LD=89} 5ԩTZ5֭\Ne镪_=69ت} 7ܹtrЮ޽| ^n>8>f 9ɔ?fY9͜; ѤK>'լ[~M5ٰk۾[2cs `Œ4<ĴVo! &o?kQqp-RF3zk6[: :U[ PpN[|X,ɬs*eJMY=vs 8ҒSt - I ZBd`*9B4`24/NӶC0lMυJo_Q:fw{S;5o7] \괯6/79R7[{֩tֿIẏԞ AqoZԗ"ו"eg+^Єxz0G_PBcq.Z:T G0Ąhlg70p7 0OWأ n57*uZcc$G;q|F>MyeERI?ii?h@_5oJ2ha1+ CCoDZ\R*2%0`3WZfAIFȤ@ NK$F5Į?H[-$ݐ?YQM"0L Xpg۲e{:"h=8PbSw{Wt\UxitG? Ґt$-IeTQ 7r14mot~a`ک 8O5S: u)jwzTT%J)ګ\͍SUR]-+l$Ȣ62[zҸut[׼u|_ v-a*vmc Jve/jvg? 66;orafce-VERSION_3_9_0/doc/orafce_documentation/gif/DBMS_PIPE_flow.gif000066400000000000000000000303571362147214200251250ustar00rootroot00000000000000GIF89a!p!],!3f++3+f+++UU3UfUUU3f3f3fՙ3f3333f3333+3+33+f3+3+3+3U3U33Uf3U3U3U3333f3333333f3333333f3ՙ333333f333ff3ffffff+f+3f+ff+f+f+fUfU3fUffUfUfUff3fffffff3fffffff3fffՙffff3fffff3f̙++3+f++̙+UU3UfUU̙U3f̙3f̙3fՙ̙3f̙3f++3+f+++UU3UfUUÙ̀3̀f̪̪̀̀̀3̪f̪̪̪3fՙ3f3f++3+f+++UU3UfUUU3f3f3fՙ3f H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ`ÊKٳhӪ]˶۷pʝKݻx˷߿ LÈ+^̸ǐ#KL2Y3_p3FodLmfcF]>ѥӢδg bs{m7z2@kYǕ(&ge7`@,^9-W_U/};s摒îwtzGjLOu9܀t)VzvsAxhR A-Nw$!8ڊݘ1'߈cVe6O=A"yM'Yil2dxjv)Зkt&zd YOWi`Wi8w^QGfs('!JK5 ʕI*Н3q)f}驝b jTZ7ЌkٝyJfySyhORlAj Z~*Mǖ>6Sɸ¦ Z;$8Gh+jYnbPG ރ֦)K" iç0aw*yeR)_Þhw-~jiD t~Geݰg]̢J^6?-jE=ub7z`\-dmhlSp&\tmBV߭k߀owlن'7G.LsOn ץy砇碗nzXꬷG.InEä{oovf'Ȏ6=mi;Ծv %tq՝nrްjF~ӿf"J f.qGC|N[Y'Q᳜87SƝf[ELk<j="$ ZЛ؄'%]Ѝ-O6v(NQnU/wWým? Ҝ:/ ro1xXCH!Ȩkp瀗`Xx T3T4B"8 Ng,؁u.]0X5x_378=(?(AChEH-hW$r^Q^P=UoNzAk 70rG*L!`\2/5TD-q5Ju%QMA Ib ZN3_F*e\|N#D5VOg)ȇ qWNDMD[8ށE5G?t G*]Xt}LbEG O7rq(R,5PXU5 %c'xԆ͔Rn43B QR+EbVo$!QĀO\U]u%yMHZHHJȱcH`HdS- S]5SR88H\4j];6C]L8 Fx9".I0_GdxCx(-Z~SB[c("MbM(3pŌ"8䨍%,R\8T(ԡ2w$D P$q؋^ȓUVURR)3 9%qSC\(DHO9 N(kYVSXgPYDq *Xyhъ^U(UX([1)QGTY*ya•VQLX hep) -ᄮW]e3Ȗg\aZK9[HNuf[4i` QщI:Hv~"zV)    J. ~X(A":$@긞c ;* ;%:4J':98~:Jd=J}?dA:7;9طcEʤ:18I9b>vRc\JS:Wcz9O:G7ej9g Yn$Ùcmj:UJ7m&0vqi#٧Z*s^A^J.5ڨ @]j;iJ'W[D&+atXb~`ZfqEs~Qax[8YDfZFvha:a夽a8_ @Z MQjz:Gx!9 ϙ_b*9|+fᭋC~*Ƙ9jǬAƮZcລOc*z 332j*v%Vu{|=&alZcQzs9CJ. ^ckOAa~,8+H;>_(L;;ڢc|.v{(cT8JX:={4(ѴwC;;k'TSvq^V䵑'UKU\;WL'D6 o[q&(Yr\8y3SJ)F- K+0Kv2&kkMAg:rgt|YnOUy8 񸷻>vO$>4Q۫?lŹ![\tDU){;gM Y1O%\ŸT-Vc2%*i&Mo6S*CL-3rMk咧6+BS)K+H>絸sx/' DӁk.bTr匓5EA M<!Em'gt{aFYˋu]Lt(2v8c9aF'A=cLeܯ'-|?<_KL"yʵ|+? ;|YʫS%F˰,_a: ˹l;[NJǻʞGl7cQAuAfʔ+D+D}1uc/|L7ʳNʟKd%׳LDVhz JbH.?̼v1n?\`0&  9ZJPc"k\߼5F ͣ,=暶7Mc\F-@^6\9(KcџaqX]@L-Z )[=]}Mc=.T}&˕ \_Iqhs"JGKGTK82sH&MBix-^Z:Ƨ hzyKWD7+uCrGGHH$-q8=eċ77!2#WM1!Խ_.\:!|QUȋMw,qՙ 9ӻurtYZXkQυXPU8TF[F8 N ./Ή޶,բ$~GvG$IH^/>V2>68&@8.#>21HB.WR@So7g+ǘrT`řU޴#ҽB }52:>@?AC>(VEArw̔ PP7Q[*źuUudYpq>u(A 6d[gRy}F3EuEP)Ԥ.b^1،,}d<8:;᜷n^h]5D,Բyx^.>ݎ>a>~ݶs.\MW~>^/~-tmjalckf>AJA^|~ /LdL&Om*>,8A6_3=GOM~aEop3"(K-лS__ >VJkOf_cbqy}PlOx_`Bo}߭+IGD17htCت^90ho!DCO!HbOQ4F_s/H(JX6!ڡp(X$Ít `_1҈hW,zɵ^_y#a;_X}hĠg‚b&s0DR8ɠ211b1$H$EG\ LeĹf}7v󥘚0]丏hK8gl 辨E3#ѣNVXe 5VXkݾW\uD]}BHl@gpb 7^l J Z|f͝z zhG.8M3Q>aFyֺ;yOҸ9W$FʩGoz&ʼ w{?_yT XPӨ|u >n%np*fL@rA"B /B*9hhVzR;M5SdEnxM6i1Fo7W[qM JnH#DR$SFL 'J*Rޢ0C/]A/%tP"H@Ȥ%:3b)̄ |zI$(^.$PDEQG#rjzSԴSN?& TSO T5tJz\n 0VdJnU3V2VLb%F+"VjQl$il7\|-& Wp-@҄`Bw` A`*ݧ Vlt^Ib['bڌ7Ka =8dGNdOFBV-IMj[fm9gZbwh9F:f⥓V雡ժfy'g:D&ܮݚl^m܌/;o΍GM*=z g{'Ka %(C%j^-n[~PZ^H1aNLZӲ6גŲPz\L'F-z$cض5bc8G:B9LlG4ZcXA~;E.ti#II𑀼*)D?fy6yQrDaOҕ;%bYYe_]rʥ~i`0rsdѢ9M%3Τ5LlfSԐ7)NGSx$'89iN6sܢ;I)O,noI} Ԅ9P $hB9Nz[ThDlBLCh^ HkQѤ'EiJU"jTz.`Z4y6ŤBS#N{I\!F ʟkR=y:u^e*ԚZuB NRCr'^+i,qrQ5bYu&+H;,k]-+1Vɤ^eZ,eVቁ\oA,By2dTM,"FѰe&,;,%4Ѐ 4( oR\jS;Ѵ ~ (WclaYk@"Ȳ r-g',bA!Q> h%?zM|\ XBђ.Жc+'`/BqL"..Ru:(L|;Y9-|RԪ400ew%2h*:Y΋4*CLC l{5Pe [__v({d>-Y µ@řrV8nR ]h@/YhiT{"B/^F1g,gүwkXAa3[b,W1>,um-v25v16Tlf;m\+bڱׄ6I;kPem~|}nvOK>\i=oz+Y0|#BW*nT[c~8ޝJ4cx(K{qnuEq.#GTMY./TS-iT:\:y3y=o77ѕ.7OK J<~kg]藬λ?2:~0+{ ?v}/ {7j{I ><^#/~۝xoטF̘}35_F1@5ãۏY%qoeuv^{~<{ErZǗX_LO>CBE`ywuʧ!4c}u=s3up[x/HGǿ.>/(7[> p=ClS@X0 IAC7 S1*tA#AȿSL@Г &JӾ/ 6D  @#'$l6%̝0z)A+Bt@© C^3 >'lîi 3IBʾ;'R"F%F1W#b^,!ap\\C#ѷIXUS1ǾRǗ͔yfPyTʌIƃ|%9=/YY֋Ě8Aب%]BZqȰgZU.*=zJRuulиUw*@ŐQ [elL ĩATFUYY*%ܐ[,,Z c ͍ې- lu]mh=պ@䠭#tt SL]l5\ɭ?\+^:jF%״"]Oj^ 2$UE&E_Qb{\-Y#6%#5D^ VGbrV>6!`ծK༭jCN86KE6n# nCޟ"a3Yi6fO8`&J3b ${%N޼'&^)^#^,=-.d$/b*v#+6%&dGBc56$#2c;a (c5&?V1Efd"xaIFvdBaBbMQ&e9;-dJf.9(^dP*ZteTdUudLe3e{e^6bZeadb. FQ kj ]ck୶rڒK,,e oODV0.4=_g\6".JA} " c,H*QUKLΟ\JBz sD>9`|OnUSU՘ē^I1Y /HKUH+ތ XαЉY$CF6 V,S  w㪀0hGddfN @/ Ȼ*_ gD.9 ➨ԫ Y,v&!lF(Sl@mc h!hs2_O)P>QEfLIG-;Ou&#tF_uDWOZu =s"u&wuVHusZ\jv[ovsQVWj ⷐ}btM:$Qҕ _Eb`p[q**"RTm&w aIP `Y9r[v_xt-s~5gpԨJfhGw(j[:^9ViNz:+l1JI+Ա(Nmь:lvBZ{-U-Fr-學+窻nJ+ /go-&/ow*0{0 +0 ;0K8~8+Bn38>9c$k9{9!>:饛~:ꩫ:뭻:>;~;;orafce-VERSION_3_9_0/doc/orafce_documentation/gif/DBMS_RANDOM.gif000066400000000000000000000174621362147214200243230ustar00rootroot00000000000000GIF89ap!R,3f++3+f+++UU3UfUUU3f3f3fՙ3f3333f3333+3+33+f3+3+3+3U3U33Uf3U3U3U3333f3333333f3333333f3ՙ333333f333ff3ffffff+f+3f+ff+f+f+fUfU3fUffUfUfUff3fffffff3fffffff3fffՙffff3fffff3f̙++3+f++̙+UU3UfUU̙U3f̙3f̙3fՙ̙3f̙3f++3+f+++UU3UfUUÙ̀3̀f̪̪̀̀̀3̪f̪̪̪3fՙ3f3f++3+f+++UU3UfUUU3f3f3fՙ3f H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ`ÊKٳhӪ]˶۷pʝKݻx˷߿ LÈ+^̸ǐ#KL˘3k̹ϠCMӨS^ͺװc˞M۸sͻ ȓ+_μУ'a'ѵU_}GG~F;Ǻa }NT`~(}E g=XaHc6@#h"U!h%x Sɸa) T Hd$AFꈜ%d/&$s0%E6X~9y$o2b!Ad yi$ƘLeD|){]ԣŠ̗I#=fcƵq͚@hG { D bЪ$T٧jq gwFub4aKP&E*(Ah`Yh&+tniC&@u3ƹj&~.&$v*0rjAgA>Z4~I"O9 C,"t%Us-0]{<<9B*+r)^JR'&ث-toDH-d=6fW/*Q?+@Mꏈ~,*ele2π*Sx ᾊ2~+>-e#{? )>l%ͺrԗK$iܔʬO*+J3lva)|9a z\ IYwAʟo,B(p7bC 1j`MY\66Ɍ{ f= )[^6)!LR@}Tw ^k D &|.> q.iD.JtvQSX).ƋqIb:3'ȹpZ{8;nzW*4ZBњmD|DW*T\筥FE UU/S1/,g3\&zZxMkx檬@4G%d^nwADAcet CI_ ;6ȝ5u9K,TqrT CQNv{guznarw=M)f4jhTі[٣FH*PuTh"r\f'R I;$LG5lݚE-fXQvT+cdVS- >ȊY\"w+ \`r+eκ8,0>rH}ij>k)|e3K,X]J]–+YsO^6h(|S nfjh}Wg@bt͇}z W,ɛ4W j?z+.%rOR:Yʧ_Xcմ\Ҿ5.lB*.v~]T+~6)G2*ɮ6p=^kܖJݛpGe2tfOq)o{޷wSЍ)7moҗۦR\)R|X; îlhI8,Aʁ(9GwEQD>Dkx7s[dyFKQ fH@EWU:ڪF*v}5S^*ע͵[ZLjt&GL6/v bMx,Nqlv-Snڹ{h#/VʐK kWG] %- JCʥПιW N>јis!!gzn>0pAwhiVN~}nUO 7% vbe¯WyyvԱZ+:1Q0 (u&'X))HWGVxtl^Wܳ4fuSulvrXg؁I7VFvDayxaww7v:hIu !X0Xdw@R7:|$1;h8WByi-s|}WrDghs0eCOA{UnrE7L(\ |pB'pBqGr+bA È|(lɷ㉅Hȉ1ϕ±?8#|ыȅ16b #52cQ62h(2YX;Ri,[Xv[5Ix7qu:[>6&:Dy0'9W"z$\P}W*GYYm)ӕ_w%p;B(z#֒+;U5$tؒGi*)q?b/wlio9J9FN h ىXrvpQreV]t-X)9~6ٚIkbPf&ӈGם)vd+/IɞwrCWɜsJyQ8)G|ɛ7hpX8a)YY cI fT+)w  :U*,wٸsAva-ʡ()- #FlF5'BWi?r]d4r8Uzh7%nyY顃Qp fNJHyfPdǒyʢqI*vaQF>xN^EH Fܹlj!+5Ձ!i7ERq!1z,u^'1p:ZzȚʊjΚ:A4ڔa7Vƕj99GB Nz] z:K{N$ ۰N+Ҕ9wyh;a(Y.ڟDCvjB蒮C6z2<-ɡ\=!\Z*"CKZ_mZe;rV J2ʨ_JPj$ K{w^$ U&ʭ#{Vۄ檵e\ -[ʶ"Ht(ڶ,Qhᨀgw˩tfAJdkɡhK~as57zI9r+[z[sںR9KP[+논W{ {ѫ ˽ mՋtCH+BԹXE4vˏɽ aYci)|z˳ rjoU@o+_ӘIx-Ҧ{yr}|> UP=A]M~7wlэr5]R~X>\VZ^+:mҚѐqƫӻ[@3mmNKԁ.ڄi嘫ꀾJҰn/=췮ܯ~]V)|׾г.ŎzX|^ <7']Em_̻&a΢ ?ſ1ߢ|Ϝ?X)!__\(+-($6S4/|3:o=)̿ e˘s[! ~ƾS1@$;b85}vQWdTMu.ݮnOpB_Q8KRwOy !QD-^ĘQF=~RH%MD2$#Yr2_T&0>4c -L?_H8p@-U u`SRm,ҪS]~VXO˞E6lb2͠ǥ2s;늹;@p |;61bW8$j-_ƜYf=lRcNbrlzz}2M} 4foE$hōGwr S:bLGlt__׺cb&1.[8z/|˷l . Lz?d,023 /S ?1DD$;+Q _c-itD $kF%G")DHoQ !PB^Q}b5E%{R!grNX#,"͌tՈ8Ǎ]W ZnW2Ib})ɕDr@dw6&GV,~,9IQJik+6Md%.4˖3dd.P2"Iib&'9 ,JI:̢.L_X4*Iʈ 'xP'yST&!e,oqQGr'I>=RٟNH!aig={UvM Ռ-II;ڙu^Dܸ  [N}m;)  =&*hr2ջ%1hg{^ӕX)vk!tUmxy߳ڗ߽{k5&z LZ.nmzNn/4Lb+Sa'FqUb/qeLN>ӾL鷏>h'2`k - NXŔ xY@5`(>hʘh"hcO恆|1G#sЁ7& Rz mx*)GAYVNeAUVQ[eVXi!g јR7yUt橐ɩUi䠄jgl>s=:vGirz)Xfz\^Vjꩨj*HF$*uj*NgGŧFcnT^f4K6v&";GͲbb]Ɋ[Zn]^4'v8}غ~Wb$e&Y T-GސYBUe$>,E̚k70iҺAJDmCY}6!m@| 0ɯ@$1qV@A@KI@;3-[S@ k㩔2"ml)-p7Flϋ֣@Juml/,3AH0t ߚ0ˈJPU(L WX*dZ[>70p!~SNz YSeb &10({AG$M eh9@cHhx;pc8ss9eLQu1Fuqi6"B M†U4g72 j١2c^&Xvà@1g湹gI\c yɨB}NATd~1x"X|읧t]~ه%R}( MlC'%B?J6ٮ(@ʹOϑnz)X ĸρЮ~%ɘaBJaYwЦp˙ )mAba *1K㫴.$+Bƀfl$NVfsh~ߑ+4+H/ kByY")1o:qz~H]|_rĪ@\B.*pLZ$+߬? efMyX\cgI#ի^wirMуWZEMNCS~?ZefF[}yn騧ꬷ.n/o'7G/;orafce-VERSION_3_9_0/doc/orafce_documentation/gif/DECODE.gif000066400000000000000000000064751362147214200234630ustar00rootroot00000000000000GIF89ab3f++3+f+++UU3UfUUU3f3f3fՙ3f3333f3333+3+33+f3+3+3+3U3U33Uf3U3U3U3333f3333333f3333333f3ՙ333333f333ff3ffffff+f+3f+ff+f+f+fUfU3fUffUfUfUff3fffffff3fffffff3fffՙffff3fffff3f̙++3+f++̙+UU3UfUU̙U3f̙3f̙3fՙ̙3f̙3f++3+f+++UU3UfUUÙ̀3̀f̪̪̀̀̀3̪f̪̪̪3fՙ3f3f++3+f+++UU3UfUUU3f3f3fՙ3f!,b H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ`ÊKٳhӪ]˶۷pʝKݻx˷߿ LÈ+^̸q"KLe7k̹g>LӨ7:װcnZ۸s cȓ+_NẸKN=%t׫kν+Ny#`NuϿl7{h pق 6F(!MhfevUcEC)3e%Ƈ,ԈdjМ\21 M<&dIHz\2^\M.i啽$U%`Y eҥ^_NpКl)niPij@{:RPi(tZ"ZТ*NJz$XNDBu)vP< xJШr/ɺԜaڊ*銫CyPPI;ĮrC )1дm).edV/1죌dYչܰoײHmm9I{@a{X;~Y&5(+gB1L9@#2@åaH4H,BI[>Jfaf {dW:}\"gB7g 0݁M8<}V!FoHn%fOͶN"U}нaXNu>#IdD `fǻ~gB^a?c*lB+_^X:ߪ#}os|'-S>+پ\WC Ѐ Cx*^M̠/S@K: l@AᐰE"| K~(q! q#055lrx:Ta; V@,O#Y-*bF, 6.Nn"1zhlB('2noi !l%sG17H#؜@iһ (<"ZltdU# )^Ie $EP+4m.Hh2#d"?9JS&݇FbGWڲ%J\z23'LXi%s79)G2J* R#7f3Q f4]1=t^dn ufځ M8;Xi]QxTkEg$2tRU BMlQt$ݿѴ ؽmUY533 +T1%;P~L)[X# ~'UcUazHL +f̰!f"m뮦| VVlxkm`CGǘq{GO"Ǜ0[g}IN䅰A4jә5eMYaow^׾6-bƾoZdھ7H([ a1uj*ؖxq^mPSJ ɔvAa+ۍ6Yy#5!drGo9 1v\s0֔7b};Zܰ@\lWYAc2KhF2nY]E|\>17;''~ٍ -̮F [] nUNM@Lhӭ׽Q2p8Gyv>maG=ԃ.PJ# ߵa3fK? 2\>8| 2Eqx$*ĭl!ľ;rƳ&_5nH8h5xBănGf8:ȄTQ{4z*dg$kjGц3dprhExz|؇~8Xx؈8Xxi;orafce-VERSION_3_9_0/doc/orafce_documentation/gif/DUMP.gif000066400000000000000000000042671362147214200233020ustar00rootroot00000000000000GIF89aNYp!L,NY3f++3+f+++UU3UfUUU3f3f3fՙ3f3333f3333+3+33+f3+3+3+3U3U33Uf3U3U3U3333f3333333f3333333f3ՙ333333f333ff3ffffff+f+3f+ff+f+f+fUfU3fUffUfUfUff3fffffff3fffffff3fffՙffff3fffff3f̙++3+f++̙+UU3UfUU̙U3f̙3f̙3fՙ̙3f̙3f++3+f+++UU3UfUUÙ̀3̀f̪̪̀̀̀3̪f̪̪̪3fՙ3f3f++3+f+++UU3UfUUU3f3f3fՙ3f H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ`ÊKٳhӪ]˶۷pʝKݻx߿ "+^̸cDžJ\H1Lg?~8lϨSwh3vwq>bH$ޠ̆ƈh(/c|(䇏uY!ğ@i2䕗CVUq4`APxSThBH$ٕ륩Rk&tEne构'B%ZPiy>jO^iNz4iY~jje:Ϩdz0ڦ/c'a$ k&6kiB묳ZY^;ʭvkj+"K /zƋfko1 ['+|^ALaVl1cQ|q`ol읊&\ f@Wʱj$oủr.+sk3WusH?d˵3Y)i-gD4mF;m1O?36׬ JiZKZ6KCe#@U5gkg 29}%AX _* ]wAxJwwkD)GwO O-@+<܎K  P<^=tC~#vh_'ꨟ2ʈ`d [c6~/rV8TXy~&y^6 Cõ-C!Èۨ>.47quE+\p&=iz M$-+, @ۙ,Ƒo"+ٲ :)t5:e$t!(d3!TP/'ĝDF` H2I!af*VC ZL1`_= ct"I@c|qXM{`qrY#+D.rX>z>h$F)唩Ad~'Z2&Z&/nI$AfZ*"Je/ITiYYؖ >snbh)1\e^hxv駝I)l((2jZ@l&{+_fXe ɤe #ׯ 2,vc rYOszla{'fD*AA]gBxf`Hb_wj_lF,ĕ`tY&J l%|y,S9rŗiq4"m\V638sy3lx (ۋPG4LsXgluZ-6u#.vflpǽRmݮMuxV|߄!n|7.9EgK标͟nN\:Ge@ۅ=:n;J:xRt {<|hAwLEGMӛyMsQd.I"r'/ɊNԡ93 fHrt%^H ґVҤ-)JkR)>_*Ӗдb)NSӝb>- PUhGQOqN}],JUmVoՋJt`m[@:UT)Pͧ8.T߄+J֮FoFu+Wh9Z׭ܕ$yRt< kWqk_#[еJ,e +Zd?6ͬg!Zvm(aG{6"1T_miw[p~(֋Kuldf5sa1Y!\ Dkw6ۃ|Qq=Z8,]A 69؀`P )f+.[{% Jx/+XI:QԻ^ 7,C4\b$J朆˄A58"lR[~)xŬ}1 sAݕs{$7ƍPHi:LϚW(Vv<~)t&4'D!kM~YYB`F 6F@֠B7@"xʬ@R}Y PAĘe"De\)Cd@yƆGi(i _MXPo5'm1hّbA"g @1dEI$&$"bɟ5|dc mߘ;VgЃ47Pi 90}󟍗A_whAK0^yHFh &ijAٜVyΚj.6l5iMxj]N2Y.۴u܊H&G"h@w&hm H\ vzdŵP%.q$eP@vIBjF1)C|Č6+-yZ1{Z@ڲPQ{WE *0 sȚuAdn-ۥ:d)5ҰI>c g ~o$}D6z,C 7=~pE^ySWQ͐]̒I`4Q#μ{չKXOF}ew/o觯/{;orafce-VERSION_3_9_0/doc/orafce_documentation/gif/LENGTH.gif000066400000000000000000000034241362147214200235100ustar00rootroot00000000000000GIF89a4p!:,43f++3+f+++UU3UfUUU3f3f3fՙ3f3333f3333+3+33+f3+3+3+3U3U33Uf3U3U3U3333f3333333f3333333f3ՙ333333f333ff3ffffff+f+3f+ff+f+f+fUfU3fUffUfUfUff3fffffff3fffffff3fffՙffff3fffff3f̙++3+f++̙+UU3UfUU̙U3f̙3f̙3fՙ̙3f̙3f++3+f+++UU3UfUUÙ̀3̀f̪̪̀̀̀3̪f̪̪̪3fՙ3f3f++3+f+++UU3UfUUU3f3f3fՙ3f H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ`ÊKٳhӪ]˶ۯ1ȝKݻx˷ߺ1&K8o`+^̸ዃ'~[1[)&9ji:a봯8imA̭3A[nx3;cr3=94˙Xau77[}^uIb(~c}Q׾}JbpCs;2v@&\\t_~)ceU T@,Cf7L`8y !m5DdP&hx2h!O2avQƙgB!Bh` $͕I=sC_ JB&I%BPA: >ag|jZAhH40(|m:Pc2IxbY BZ>y XL]61ꢓ%YЌuJ8fjQkEC]r'bHwo1p#⏴[cr,ӋPm(bK3l=+S.Mzwgrzmƨ2(gA$kpeA1V$v& b+NușůR zk+A@ XmisuApv|m e'ZڕxAH xǖ4[[4t_j9c.$z8%TY޷]ңkEC.M{~)|5H;1j}RGn^|&mrhH9 :'H Z̠7z GH(L W 0 gH0 ;orafce-VERSION_3_9_0/doc/orafce_documentation/gif/LENGTHB.gif000066400000000000000000000034231362147214200236110ustar00rootroot00000000000000GIF89a>p!9,>3f++3+f+++UU3UfUUU3f3f3fՙ3f3333f3333+3+33+f3+3+3+3U3U33Uf3U3U3U3333f3333333f3333333f3ՙ333333f333ff3ffffff+f+3f+ff+f+f+fUfU3fUffUfUfUff3fffffff3fffffff3fffՙffff3fffff3f̙++3+f++̙+UU3UfUU̙U3f̙3f̙3fՙ̙3f̙3f++3+f+++UU3UfUUÙ̀3̀f̪̪̀̀̀3̪f̪̪̪3fՙ3f3f++3+f+++UU3UfUUU3f3f3fՙ3f H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ`ÊKٳhӪ]˶۷pʝKݻx˷߿ LÈ+^̘` #KL˘3k̹;ybѨS^4h֪c|E'qG7E$cC'T9CCA;A;X eu bAG" @I7P 0[(Fe=hFQ y @JL ctar!\?vyo@bhYa*Y&@v17fO=ڗ@MGRi:[x pND&b)hW$ơ>$$qDo=y⃔A3ZP=7Hz x#le.dư®y*oV)Й&"dZ>Zme,F`").W4ɸ1') wl-Қ0'A[b٭`+Ƒ헜qpKo&- [ѱ&jm/*M 7,I&e&@X&og8Z]ȳ";KBx*.GuG m}טzAX?QaK)k(+Ws̓T]DRw>Rō^w˹x\ ;7ӛ[GQ=l"<.5KѰGןmo[sLG$՘(b;<:'H Z̠7z GH(L W0 gHC;orafce-VERSION_3_9_0/doc/orafce_documentation/gif/LISTAGG.gif000066400000000000000000000050571362147214200236250ustar00rootroot00000000000000GIF89agp!D,g3f++3+f+++UU3UfUUU3f3f3fՙ3f3333f3333+3+33+f3+3+3+3U3U33Uf3U3U3U3333f3333333f3333333f3ՙ333333f333ff3ffffff+f+3f+ff+f+f+fUfU3fUffUfUfUff3fffffff3fffffff3fffՙffff3fffff3f̙++3+f++̙+UU3UfUU̙U3f̙3f̙3fՙ̙3f̙3f++3+f+++UU3UfUUÙ̀3̀f̪̪̀̀̀3̪f̪̪̪3fՙ3f3f++3+f+++UU3UfUUU3f3f3fՙ3f H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ`ÊKٳhӪ]˶۷pʝKݻx˷߿ LÈ+^̸ǐ#KL˘3k̹ϠCMӨS^ͺװc۸s" N{^\!+F;uAfn]8ayë7c_O| GA>U:v C. FxY $2lȐb0E$6A >)D b4fvA)*Fm P& (#d=1oCMLe1O7֨]Y#B(@o(>LRdĠ&fFsA feH{nTUzjhIࡌ"hy+H$)iz!1gPc6jMjkj믻&D@h4 n! z [o"D!&@7d̕)>WNǮ ۰m ոШbZi+i>(p>I +X J~[DŽ~_K$Mqb)`?HF$(p Ⱦ}!1 .xAen <@dGj",! ;!*ȓrzcj311'Z%p GўCmWȉ*9Gtb#vՋ +Y9>aAȧDžg]qTȸ̅)hG@=k gB,D b 7X 4=K:zql_Fz3"D腣=-Z' BL1Xz$ME@v!4IJJ !P"".RV|9zKK 2 ֪qkHY8wq2 K HN&;PL*[Xβ.{`L2hN6pL;orafce-VERSION_3_9_0/doc/orafce_documentation/gif/LNNVL.gif000066400000000000000000000033211362147214200234140ustar00rootroot00000000000000GIF89aX2p!<,X23f++3+f+++UU3UfUUU3f3f3fՙ3f3333f3333+3+33+f3+3+3+3U3U33Uf3U3U3U3333f3333333f3333333f3ՙ333333f333ff3ffffff+f+3f+ff+f+f+fUfU3fUffUfUfUff3fffffff3fffffff3fffՙffff3fffff3f̙++3+f++̙+UU3UfUU̙U3f̙3f̙3fՙ̙3f̙3f++3+f+++UU3UfUUÙ̀3̀f̪̪̀̀̀3̪f̪̪̪3fՙ3f3f++3+f+++UU3UfUUU3f3f3fՙ3f H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵe `ÊKٳhƈ5۲kNm.ظ oGEL]7&fxgc/F99i儗'f&yfg" -4菡MLzTժ:k[16䋙3>+חyG #d⨼]k A>$zܱ'̴^"i4& ,oq񜁶~0>ܠ Mg'B`>5 Ā@fh[{pC} {-XЂ~@.f@"c,BE$ 8I\X!9fa21aA;ZA{9@x)#Jz%f5G l9 xPu^.$^^b.Bz)bbhhPpoI2O $@w#ƖJ b}iZ$7J~ d'_|݊uXkIyfB2;laBQ$F&YsA״kL=~)] ΕK:WY}WZƖai"_I2*P|ճV =j[0fa$0bJ|ŀ.@M y#L2ɕۗ,Q*h*j@ =]<֍0e*5qp40j̳"U%F̱X[j6RM$j(fb.A"t:D 4!Y̕> yLV|Jn7!^,(T8C}'PM2#MB|v4H#Y`>pex'EQAo#]eR@79FG@ZŹ2IW{vitgA ~ (#wvbU*S`C=7PlҦf2kldO3^*IaK ޒ\J*i`$ɟͦ ne*1ҫb{"x6r}\1ׇ 9#p&' sX(] 0qj$eB3AFJl4׼jkѨ:Ҵ v6mtL8_yCJ%=ʞ6 XF kTwju`m\o]bKdij_y-J7[ݭ|h-M·'xD/θG^P3Dy嘟yKo9褧:駗:z;noc+׻ۿ/71&Sϧ'gT]fmiP{B/j?A;?]kg$oHC-* `-Wlàd"8\3hVP![a8X6o!DaZXvЃ7t!eXHB ~p1 {L'6s9()n#!OH0!\t EUbf4 p1P,B+R9#E5D2^dAzc3LW)rB鬅6jDư9 ZBJ%!+B4$;0q6& ᤑ)MqEteP6Ǹ$DCmq@^L)S+dwTFGV `d^FODX6h% ,g3Ǵ1SNLI"HzCgr9Mv6F2V'"s: rϊ2Id1 p" Go 2񓈣c`%444_sL:gD8с !YJP^h| Ѣ]xbTRPVz/kYj$ >e$0%hm\oVyɮtk]׾x ,_;Xհ=la{# kDzd#KYV,f7;YvhC{ٌRHw,rWЇLpN\@T&nE. AE&$y䑔E2so0]bm4?@ֹz /0+M/z׫/|ۈId_oL>, 2KpcR/)U!hRMS'ZzPxS7c KV*IOzBbFթA#ƌrX4V\In~ S ޖDZ-ӸٗծV8NfFdžLJq e'ԉjl0 s cgJMBoUroVA;s wbŃsSx<^B1`\MGy7h11"FmR4Ĵ-]V0 h[WZuLq-E_&'mL#0=vF_@[쟸7{nt+68Mzη~NO;'N[7I@;orafce-VERSION_3_9_0/doc/orafce_documentation/gif/LTRIM.gif000066400000000000000000000046061362147214200234210ustar00rootroot00000000000000GIF89ag\p!H,g\3f++3+f+++UU3UfUUU3f3f3fՙ3f3333f3333+3+33+f3+3+3+3U3U33Uf3U3U3U3333f3333333f3333333f3ՙ333333f333ff3ffffff+f+3f+ff+f+f+fUfU3fUffUfUfUff3fffffff3fffffff3fffՙffff3fffff3f̙++3+f++̙+UU3UfUU̙U3f̙3f̙3fՙ̙3f̙3f++3+f+++UU3UfUUÙ̀3̀f̪̪̀̀̀3̪f̪̪̪3fՙ3f3f++3+f+++UU3UfUUU3f3f3fՙ3f H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ`ÊKٳhӪ]˶۷pʝKݻx˷߿ LÈ+^̸1HL˓c4ϠCMǨS;5CvaM{썷斻ƽ/'8m |Zɣ9^ҳ_oYz_A1VKv/~G-գߏVB sDw/)߃a9x21pa C&sd4P lhHv2j֢͈}jdx$!Dn5)192 FAf`&S$eW 4 }_#}Qi10 b=1e=GXoiB]h$bYfa FM29cA)ff Y l` vC|gyj|3J}qR 1k}Nz YŐ6?2+Zπ@Ɖ`S2z@׎;@eo9kҾ=9I2 o{"^ YjFfO+kb0,sk|&mzNV)~KL3#" @: MѮI*;IT`gsAF4\}hEnǕ6tpv|7Gww߄85wጓt9ߵxw:uw8s y[\iuꬷz룗.ٳW];o/<ƣw./;?}SdqwoB_o{~uC>^qjg^?޸{WWs((_ 8.pB3 0$gOZ H29qq5~5Є%, V=" BBЂcI;2"\2َjd$. -0CTu ٠Ad#yG]~h'r YR8A2h~Fq7Kԣ)'7D$NVtǔ> %'CTَ'  MU)ŝ1RYb $KxrvC$(b42!z4l4FB >UePxǂlSia\&Ixo~Qc9'E1Sf+NfbIH#ry-uJ*kdKt @@VvxIpEe65$*+ ?Cq=΍tKZͮvz xKMz|K/I;orafce-VERSION_3_9_0/doc/orafce_documentation/gif/MEDIAN.gif000066400000000000000000000035701362147214200234660ustar00rootroot00000000000000GIF89a4p!N,43f++3+f+++UU3UfUUU3f3f3fՙ3f3333f3333+3+33+f3+3+3+3U3U33Uf3U3U3U3333f3333333f3333333f3ՙ333333f333ff3ffffff+f+3f+ff+f+f+fUfU3fUffUfUfUff3fffffff3fffffff3fffՙffff3fffff3f̙++3+f++̙+UU3UfUU̙U3f̙3f̙3fՙ̙3f̙3f++3+f+++UU3UfUUÙ̀3̀f̪̪̀̀̀3̪f̪̪̪3fՙ3f3f++3+f+++UU3UfUUU3f3f3fՙ3f H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ`ÊKٳhӪ]˶۷pʝ+4x˷߿ L8ov +{XbŐ#KVɅ+@!gQ8k銧GnkAvCq_ݖ@A'$esŸG^[*ahvS*;3 M[Q ͛\ hp֟^ ~o&hT|e"GnU^Bm$LH~%YjݷO)#sW 6QkG#W3]$0v\&Atɨ$Av5oHU(@H+$$mFR_ N)j@zc@=M>&zRbc&ts7p1>j#Ab<&6}9dM +hPE:W~u>eIyX~IbcX$a:z-HJҙ)[DZ"ǙLx!1^v@L*jk$*@(/ $U1y%6Rd)tHB]Yd q$ "A2膈A4Kѝ:c#w Ѽzv!D3:H:+Zy&Z|dc1ۛң0 7$!bLK)_{g,YxPxQ ?\$P*PZ0x/>WqQ,m$T0]ANXN;MV q0F<0/!U HExX̢.z` H2hL6pH: x̣>% ;orafce-VERSION_3_9_0/doc/orafce_documentation/gif/MONTHS_BETWEEN.gif000066400000000000000000000043671362147214200247170ustar00rootroot00000000000000GIF89a,4p!G,,43f++3+f+++UU3UfUUU3f3f3fՙ3f3333f3333+3+33+f3+3+3+3U3U33Uf3U3U3U3333f3333333f3333333f3ՙ333333f333ff3ffffff+f+3f+ff+f+f+fUfU3fUffUfUfUff3fffffff3fffffff3fffՙffff3fffff3f̙++3+f++̙+UU3UfUU̙U3f̙3f̙3fՙ̙3f̙3f++3+f+++UU3UfUUÙ̀3̀f̪̪̀̀̀3̪f̪̪̪3fՙ3f3f++3+f+++UU3UfUUU3f3f3fՙ3f H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ`ÊKٳhӪ]˶۷pʝKݻx˷߿@È+^̸ǐ#K8D+/Ĝg–r8hҨ%N8:uR.)[b펷޹[a9|`Ǘ&qAC }]&ސP̯O:{!?b]͏w_gz3BbP_HWt쉇Dނ!)s`H_tꖠC dO w@hܖIa& T"A݀؉Woň F̸2xaʜ襈P&hHCh%a/ bЀϋJ$ra>/Z&fpV$ *]Bjb&0/l1萝2*1JVLkncf: `i,|L\NRܱ@7BAh$Ahp[Э_/fDN,X+Ymbs3aţw 7.3sC8ߴT$J 誼v4G>Gic~l ݫEp gV坲ӹ@1dhGYk\c|$k]jHNi׳juj:A9ۇ2N74k;b`=kHIIY ncUjZu$~ͺk*PF 6ȍW)Be*<=1-ϸ=g0>|pL2{c zfǘamgb/PٍL)}~euWx 6x Mzs4V@+8'!h8$L✅>e(b] Xa{Ä9E >@F4t >LH m,F@n%i72\Hb ΉnI궛za%E=p쳢:gbg@Yw}wV{Y[nbpYCeEmi饜%8Y MBc&$]n1ԉ2ж6Rx*K$p1'^k1jDUgvC4^W `hWWHvu2 N*[@>IM4Zj$_|d}ef$e$ϖwühkyRVlM=R^Be\ ($2a&7r0L#O,8,S9-ʈ,HH3F'|-]4qPWm;\w WW4-nh k,7xvyޮ Κ'1ޙ^G.mZ2sYw޵.{&%;DfR饣N:խG;]a%!#l|gmζ.뿯޻=_{4[Y![qJە~H =I@[ءAy*"O;HdπX,zȜU!d:zި L[|?Pu`A DQ1~!`ْńFMx=nvED GƗ 1ju=k4h$Q+|"%hQ@ lJbh/!W\HhbEM*$ŪhZA;)Z,SG̴Ќgԓ')2ݰ|YL]E/$FѷJPJawT#A 0!Vд;#l CsId=<d-#,SfedJSd"8ݤ J[K692 17.u|aT(&hjmbEm-!(A/(a)W1j;ٍk &ʟMӊ1K=Nh0!HBQҢvXaL1;%N|XƂhEPbֳ%M,GјK[J|v(Ӫ*Oց*aVT%sQգѧ)ȖY"+ jDH\S(OkɆ ';e\Ey hu[\[Vd>1~MlqYv}X[nַԋJ3Z{w-Zzu{* / $ T ] [;.7rçoAL)(N1T[gbRF4Xp\3;f "[\c~Lr|*YeAl|r&P)d*Dg% ϺeSS7 9̒ 6&}Sl1 էΐn;tӄ"5*QL5*N/LVO b5YZ7u*d ,*FݘR&vq>Nbȵ (?EIU *TrzHDKIiRH\<*Лُ6We?g@Cgjԣ(=l C-'rL=PFeW<壙ӡnb`%鴇Ze>sg{5{/51ԧ\S\qOO{^{U~?}M?ڝB}p(߸xϻOO;;orafce-VERSION_3_9_0/doc/orafce_documentation/gif/NEXT_DAY.gif000066400000000000000000000044061362147214200240030ustar00rootroot00000000000000GIF89a<p!I,<3f++3+f+++UU3UfUUU3f3f3fՙ3f3333f3333+3+33+f3+3+3+3U3U33Uf3U3U3U3333f3333333f3333333f3ՙ333333f333ff3ffffff+f+3f+ff+f+f+fUfU3fUffUfUfUff3fffffff3fffffff3fffՙffff3fffff3f̙++3+f++̙+UU3UfUU̙U3f̙3f̙3fՙ̙3f̙3f++3+f+++UU3UfUUÙ̀3̀f̪̪̀̀̀3̪f̪̪̪3fՙ3f3f++3+f+++UU3UfUUU3f3f3fՙ3f H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ`ÊKٳhӪ]˶۷pʝKݻx˷߿ LÈ+^̸ǐ#KL˘3k̹ϠCÌӨS^:^Ҭc˖Ztaسs060wJxTWУKύ9I 'վ{H"^a{9_}/?EkHBT_6R|_A1!~L 7TlaN\~ZbB3؇SiDgNpU^s)ةZ8]eKݞvO8QӟOߧ|f#0_b@h'27WLW߃Bɀ $ƀb L!N1ŐIbQ*TAb@)&bgD#j!t2A DL FPx1:RGe-c@h̖(@+0ߙPIؗx(_H@x: ߵW` ڦKgg9$&Qצ~u xMIZ]ЀiFjk\ZؑnzJm 챹 kZъ쳯)+9 IYi j x+rfd~%G/ u<['=9W|bl1i|ߒ,%|( L8%3;3C=D4GtҬ2NW8OTό[grEmٌI9ڊm4pǍ2zmhDd _uMV͝fYZQHU1>88B8͑_Q@eN}ZnґҕNRM~^cN;~vߞ2G3xc谯-;Aw\Q:6h~h`%|P&<;DlV7Ҫhoh>g6stT:X}twT?=P#תgT"& 8zS}< Q Y x@'ar(ԣq?Mf|Ӕ Wđ;d}7`bŃL"7# Xa(⿛P) q6fQP~qt+ y8B'~IXP38zQ_5N 6FNNe_ qSÐPC݃'w^e[1`E+;'AeX@DM+)L"8FGzHP4ci-ăE4bBNFn!Q\A>#0rb4zhABܧ9P1&X~ƚ\OE;ueFr_Qor mBZM(~ݬnāR.DH ixZ3jDpËbĚ21ۜ;wzRsRm(y\NV2O#7H`RYojSzQM+_.ԫݢ85,D\/QβMlHZ ҚM*jWֺlgKͭnw pKj% ;orafce-VERSION_3_9_0/doc/orafce_documentation/gif/NVARCHAR2.gif000066400000000000000000000036331362147214200240170ustar00rootroot00000000000000GIF89ajPp!9,jP3f++3+f+++UU3UfUUU3f3f3fՙ3f3333f3333+3+33+f3+3+3+3U3U33Uf3U3U3U3333f3333333f3333333f3ՙ333333f333ff3ffffff+f+3f+ff+f+f+fUfU3fUffUfUfUff3fffffff3fffffff3fffՙffff3fffff3f̙++3+f++̙+UU3UfUU̙U3f̙3f̙3fՙ̙3f̙3f++3+f+++UU3UfUUÙ̀3̀f̪̪̀̀̀3̪f̪̪̪3fՙ3f3f++3+f+++UU3UfUUU3f3f3fՙ3f H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ`ÊKٳhӦ۷pu#x[ݽUK!&n`㍏ K>9ceOfldɞ)n~9cjOK,8ꈯQ5Kېeƌ5iߦwmxkŽij({+y0/p?si"}N 遦vy C{]|W=`a] e ALq$W↎)2'@7([ء{"Ё2U`nhjy!L]ĈO'Z MD%$RqF yFO P=GXgYۖGu,xݘؒ&AA ۠p%BN6Ifqu~BʡK`&j馑5)G oj4*u3bDhrjgGԧh뚴Nڪf>kYBK6[[Yi^VZ.N k6 ZE׷믿f.{ĪjSTG; ?jgE* {<+Fhe%\*F7^ŵRV!o 7RE=;h[7*J4 HRZyXs'1h\ Atf~mb\{XؘMWѠv4C'4LY;+8t[b4 .(s$I?5;t R=iv Ӆ'fd76I xKSNCbx`X Wa:c4^QW[q>$f+#" )sco_dp,=o?^Yt샦tmq j[xf&hP mZLU9U$KE;F2q_p`]R5 78C ]ջ m?Y1S"= qiz 9T_8do%>ŊQdH"Eͱ,+AXŅQ(BQ3{k\0qBf;q* BL"F:򑐌$'IJZ2;orafce-VERSION_3_9_0/doc/orafce_documentation/gif/NVL.gif000066400000000000000000000040571362147214200231710ustar00rootroot00000000000000GIF89a<p!A,<3f++3+f+++UU3UfUUU3f3f3fՙ3f3333f3333+3+33+f3+3+3+3U3U33Uf3U3U3U3333f3333333f3333333f3ՙ333333f333ff3ffffff+f+3f+ff+f+f+fUfU3fUffUfUfUff3fffffff3fffffff3fffՙffff3fffff3f̙++3+f++̙+UU3UfUU̙U3f̙3f̙3fՙ̙3f̙3f++3+f+++UU3UfUUÙ̀3̀f̪̪̀̀̀3̪f̪̪̪3fՙ3f3f++3+f+++UU3UfUUU3f3f3fՙ3f H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ`ÊKٳhӪ]˶۷pʝKݻx˷߿ |7È+^q KLeɏF93͜C}3ዠI^MڴBa7}vBqԬ^{iݱ|_ǟ|.=bׇJϮ;g#-c{=)3L?-ͯ7^|}<'`.DAɧ |/c~SxP&h@_H߁-2D,)saJeaA " Hr H$*O&2ftA*V$"Ebs-@@ A E/a7Pc4ra@uh|(tܗO cLgʦ +db'qP&7j$iHL2@Qϣ8 Fz*$ŰeJf2>7dpg(BRyjie *})4qZhx,4ݠ 4 )j=70hjp)>+A;b+i>ifK(1%D 6ih,Ic>)N] dDbz@Ą@1c4qbW b \.$%9p֗l7cȦ5UL%5n#~0\$;Fy6/޸Ӑ<9lSvl1({촯8C l܎n\6_4{'0>{qeQlbd~#߶وhVhbӈ GpٞD w 1ALN m6EICўF,0"R :Q")|I03(p7aޏ&))eb%+$C#dZ G("l'z1$XM󅴓 9=sx+5":1JtF|}Tɒ%*t8H"q F/MY$FEb^*,Vh D)O(@D|)v,1ʹ.3]*5 &g&  <2oe:Ќ4IjZ=̦6nz 8IrL:v~ h7;orafce-VERSION_3_9_0/doc/orafce_documentation/gif/NVL2.gif000066400000000000000000000051331362147214200232470ustar00rootroot00000000000000GIF89a Bp!C, B3f++3+f+++UU3UfUUU3f3f3fՙ3f3333f3333+3+33+f3+3+3+3U3U33Uf3U3U3U3333f3333333f3333333f3ՙ333333f333ff3ffffff+f+3f+ff+f+f+fUfU3fUffUfUfUff3fffffff3fffffff3fffՙffff3fffff3f̙++3+f++̙+UU3UfUU̙U3f̙3f̙3fՙ̙3f̙3f++3+f+++UU3UfUUÙ̀3̀f̪̪̀̀̀3̪f̪̪̪3fՙ3f3f++3+f+++UU3UfUUU3f3f3fՙ3f H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ`ÊKٳhӪ]˶۷pʝKݻx˷߿ LÈ+^̸ǐ#KL˘3k̹ϠCMӨS^ͺװc˞M۸W Nq18>μ;N9tҫk}=wO=| ˛_D왻' @k[柸h R X&!B1Ȑ"AؕKQKHTqȑeHM'E+:|:߇Z$6ȢdbS)_Iܰ[cC(DAГVY!FTB%AbHfu9!a)Bd%Hj.$1PiӘ:RgheTЏL G 2!eL|MzOCJO4_޹ Mr)[1UP&dfjEE2t@б fjQ 1,ak:lAh ]q;d@nA1@*ӯf$n۝2+B1-y )sb\6Fhf s]}$1`D b0.5 rL7],K['F4۱Qc.oS~ZO 5T|5hs3t`MaFQOْƗW>"LZep _Z%C*Zcק97s8bsi>p ,9Zyj3]b.{+S;/ ^~{^dㄣ{мAs_&nN: hO˯lKN#K1̀!+W*l%}pR5D8;]p*ExQ`:"@>qPTs>{DGr;i%#9F$KOs»ޭX7!0sȠ쾔X!O h^!٥fVo*819#0تݹqDتq /B! wŜ@Z=я +ApROtb99 t dVFX E\%t3+`,lXJkW/_w'e]L^1qLe$=Fj&EbRՎ~..YGiHT$$uHK΋NK-u g>MXE4.h'I̠p|(tZQ86mD^tqgM"=M͋@j~Bo:NyvKEZJT!eAҥJl5HƠvR`֞v,K O'O>Sc-zPFCk OUo読nJq] 4}5W"A49* $GND'Փҵ-BiN2xLKX8^dhmIKZĈ:[V ng;5WN6)F,&%*swB:)boݫfVK'^otޛU8Cɓ4*~qR^7wpO`~dZykY t_(FƇ/ )0dƉ8#1$d!d閛&;iL*&iVβ..{`L2hN6pL:xγ>πMBЈNF;ѐ';orafce-VERSION_3_9_0/doc/orafce_documentation/gif/ROUND.gif000066400000000000000000000042631362147214200234200ustar00rootroot00000000000000GIF89aTp!;,T3f++3+f+++UU3UfUUU3f3f3fՙ3f3333f3333+3+33+f3+3+3+3U3U33Uf3U3U3U3333f3333333f3333333f3ՙ333333f333ff3ffffff+f+3f+ff+f+f+fUfU3fUffUfUfUff3fffffff3fffffff3fffՙffff3fffff3f̙++3+f++̙+UU3UfUU̙U3f̙3f̙3fՙ̙3f̙3f++3+f+++UU3UfUUÙ̀3̀f̪̪̀̀̀3̪f̪̪̪3fՙ3f3f++3+f+++UU3UfUUU3f3f3fՙ3f H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ`ÊKٳhӪ]˶۷pʝK3xov LÈ˸H!;,˘1Z޸Yag30EQkUM5ia mیm?{jofț{!7Q<ʑ+\xBnL,>ew#%/>V#4} 4d@&'1٧ZdBb(t_L vhV=x (4zbmEBq'ظXR!F@"D_ȗ@sRB y^EE M'$\BbyT b_X i]GxfGYvgδ'G}vf4(gkuhFrh4iFnuif~iYb3N꫰*^j+١B h!k,ʆf>kNI-rVbqzەk.b{. }}W箺 U|S櫾)Ll g)kC*g{TR!pi?1,lD 13ȉfܯK̩zZ˪'ך *Ό~ #^ZE>XlO'^U rBFAhdM )C61<#4@ @@e~*##(7†)sH,#@`R4szi};8(Qww= c@_܀ {ʅ:^k$y znNyAJ~:B bw f8BQ{1To @/_@PddyA84PrЊN} TWm~/A|ץ2;ƿ,e_w8n hP^N$trl+'2SچF(#xY̤&˥iOV1 /F?] +Л6;\(uGvȻC|nLA1vnZt'os|EE`sb,/mNόsś$-OG/"x11mik }IR@sR,M qbJ]{El64'}A;ͤE'@{r2M#IG{ &#?L@SY=MQn,M&]w4;PJԢHMRԦ:PTJժZXͪVծz`MK@;orafce-VERSION_3_9_0/doc/orafce_documentation/gif/RPAD.gif000066400000000000000000000051551362147214200232600ustar00rootroot00000000000000GIF89aN_p!A,N_3f++3+f+++UU3UfUUU3f3f3fՙ3f3333f3333+3+33+f3+3+3+3U3U33Uf3U3U3U3333f3333333f3333333f3ՙ333333f333ff3ffffff+f+3f+ff+f+f+fUfU3fUffUfUfUff3fffffff3fffffff3fffՙffff3fffff3f̙++3+f++̙+UU3UfUU̙U3f̙3f̙3fՙ̙3f̙3f++3+f+++UU3UfUUÙ̀3̀f̪̪̀̀̀3̪f̪̪̪3fՙ3f3f++3+f+++UU3UfUUU3f3f3fՙ3f H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ`ÊKٳhӪ]˶۷pʝKݻx˷߿ LÈ+^̸ǐ#KL˘3k̙m CMt?^ͺװc˞M4θs.`do-M+T.;8`uףk7EKN_ţG޼eGTY>HxpqF& @$@7`5`VXԄ @@@ ZRa)# ܶو#% c&(*su> C0 6B"TV Ӕ !>|y#`Y`>2$f_f2mhp9٢| iIP #d%F~)&> h Tl1'"ڪ@h)ƦFf"@d!im*ĆWH t+h6rak2.L=ÅYON5Ŗ j{@y \-un>Ii iѧ Hfuv'h8LZܛ(.٩lޱ=R|*",VՄ,tfkT4v2}Gc4c@/-{OLVOvUWubQo-9'Wdan_Oai-7gkjCv|Zs^+n8eAKǵҏ7.Z ]Ǘw>3Yn餧.z]5{׮{Po|Mş{a%iԳՏv}wC{Pޗښ._zϖ^-٤[\iFenXxzāf`/[җA ES,:u0$= MBqP--TBBי"ҙTAMЇ3T\P" C\J{n !} y/DH&X8!&g _A䵏,q +r"'k lbwEYdȺJzqPШ:5$#˚FJD8,K>4 L1^ T IIQ2$#B6π0MBЈNF;ѐ'MJ[Ҙδ7N{Ӡ\@;orafce-VERSION_3_9_0/doc/orafce_documentation/gif/RTRIM.gif000066400000000000000000000046071362147214200234300ustar00rootroot00000000000000GIF89ah\p!H,h\3f++3+f+++UU3UfUUU3f3f3fՙ3f3333f3333+3+33+f3+3+3+3U3U33Uf3U3U3U3333f3333333f3333333f3ՙ333333f333ff3ffffff+f+3f+ff+f+f+fUfU3fUffUfUfUff3fffffff3fffffff3fffՙffff3fffff3f̙++3+f++̙+UU3UfUU̙U3f̙3f̙3fՙ̙3f̙3f++3+f+++UU3UfUUÙ̀3̀f̪̪̀̀̀3̪f̪̪̪3fՙ3f3f++3+f+++UU3UfUUU3f3f3fՙ3f H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ`ÊKٳhӪ]˶۷pʝKݻx˷߿ LÈ+^̸ǐ#KL˘3k>ϠC9FΤS^ͺװWL1涻o7G8\n`sϓK7atקk^]7ß:yū޺{7 Qs|;o~-dB&$ @"TK 'TqĠL 7@ Őgz6Pp@S gmx @6.>#p}GNhdSE4`Bh 9"}ʠOR䂙Hi'tjI$v4楨y1j >bԺaAL @…jR1pl*;*FlsH>(nhT+Иz*\JmҰ(,0t&I| ̂;|_Øn?FL޶@v\@1)P;qnb,skCK`OyC& b ]Be+ٜ7iڸ| \=W^vAfDmDžt7s5w|wtECu߄k|x/vw~xחS7Qڕ{=yl]lꬷ:룗.;s>o>K|r{^o'O<Η|mGO=ܧoBt/F~y?cU}I \WίYzG U>R_v86o[/@ Uq` l'Br$d!G6N!08B 0#R h5Аl|En3npm)/l\ {5iE$52k :#r'V \ 0$>D@ NrHBrd S~G PM3]BTϨCa3XdR!hד&L%f6IİIȶRRkFY,2nd'+D 2!Iw1qXe:ވ.zqKT~Z;j1z #K'Q&7t Vnn#%6-S'7J:JЂ%BX6qqnDCNĕ[J̖Ԝ}et)%B,I Y)H]TXI;:ʍ8mZ:>jW'6R"4yCvjˬh9Qģq*KZ1G.e>"JZ,S\֜,"4NT*C940=Ê~YL ٧u !c=558Yn9H\)ר\ kֿD-7٩:3SluYrзe*gmt]\Aͮvz xKMz|Kͯ~/;orafce-VERSION_3_9_0/doc/orafce_documentation/gif/SESSIONTIMEZONE.gif000066400000000000000000000033461362147214200250300ustar00rootroot00000000000000GIF89ac3p!A,c33f++3+f+++UU3UfUUU3f3f3fՙ3f3333f3333+3+33+f3+3+3+3U3U33Uf3U3U3U3333f3333333f3333333f3ՙ333333f333ff3ffffff+f+3f+ff+f+f+fUfU3fUffUfUfUff3fffffff3fffffff3fffՙffff3fffff3f̙++3+f++̙+UU3UfUU̙U3f̙3f̙3fՙ̙3f̙3f++3+f+++UU3UfUUÙ̀3̀f̪̪̀̀̀3̪f̪̪̪3fՙ3f3f++3+f+++UU3UfUUU3f3f3fՙ3f H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ`ÊKٳhӪ]c pʝKn\7n LÈ+ދw"Cm1osFLA[v)za銧,uh Ɔ8`m~rn+Xcys=unՙ\F?(@}{;2rmG?0S᳿Azn Dټh\ygzsve`f)sMTq!zɇM2!x_e '@xby-8:ĠAʬH[ erD'4j8A+|f"raEf1+#{M bWh"tCϘeEGFR EU"t)A:c'F ~݌wdMNH~pcJ}b$ I+C&u {Iri5JJ 45`zjP=7PyMag Yla 诘:YP Ę$^ b7zi L䞨-Vjp+401Dqv*,H*9ɲJ f)묝15lw8)AٲKhAꢋdwjjpR+"z\A׵’J TWg=iؤ j }Ҋ7፨\ )K Yޙ,8]5sjRJjtBΝM[y,96B]i.痯p(Dr|ﱣUn!E*J~%m{\}ޟ{a ]o HL:'x;orafce-VERSION_3_9_0/doc/orafce_documentation/gif/SINH.gif000066400000000000000000000034561362147214200232750ustar00rootroot00000000000000GIF89a:p!A,:3f++3+f+++UU3UfUUU3f3f3fՙ3f3333f3333+3+33+f3+3+3+3U3U33Uf3U3U3U3333f3333333f3333333f3ՙ333333f333ff3ffffff+f+3f+ff+f+f+fUfU3fUffUfUfUff3fffffff3fffffff3fffՙffff3fffff3f̙++3+f++̙+UU3UfUU̙U3f̙3f̙3fՙ̙3f̙3f++3+f+++UU3UfUUÙ̀3̀f̪̪̀̀̀3̪f̪̪̪3fՙ3f3f++3+f+++UU3UfUUU3f3f3fՙ3f H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ`ÊKٳhӪ]˶۷pʝKݻx˷߿@È+^̸ǐ Ǡ88œ'V̹ϙ/n9VmQOT}uD]aSMUeq/wBU3ΑSgD>/FWH̀Xc_v%:XSwokxѣ0i|j_>9e b4wzܡwЩ21Ġ Aa*@&i^A BW\\PyV$Ɔn#P&1@SjQވт_$hI|M$F4Rh#(t1M0`791^x B7&jhp# Ygx ix>4LMgr {J62qYgOi揨94&͡eV"M>@4)D * gnv%IjޢPuqL2j j+?C+pzuzD^Kfe6mNVjMe ;wC -j@=TQZݸD̮oW+Qi|7 ={׫öx ~ѧzw 8P 8HFQy!X|Fw/Q؜ :db^` j20Њ(◘@70b7*6@$q; ؑ YxP&CbC6"/nDUD#b,`E1ѹܙD&9P&) 3M$йS Rf1CXr%BAF e"Ƅy%ZxcAvÑJ $ơ)6pe b1,yTufH 7%%uACʩ zֹtn'&z+&$Ƒl0 L9>\$mVJޯɐΖ{lI&%XiymAء>6YBD3,@79ɨ8rѱ8Y*YGvy5ӊFCWp ϙ %~u\wqgTc3&~dLdfH0$IJJdd# Nz> (GIRL*WV򕰌,gIZ̥.w^ 0IbH@;orafce-VERSION_3_9_0/doc/orafce_documentation/gif/SUBSTR.gif000066400000000000000000000036751362147214200235610ustar00rootroot00000000000000GIF89a>p!9,>3+3̙+33+fÙ3f+̪f3̪333+Uff3Uf3UU33U3ՙff33̪3ffUffUff3++fffU33f̀3U33Uf@pH,Ȥrl:ШtJZجvzxL.@3n|N~D_LY[HWTBQUzN]ߋMKJHE *$ Y F! p@?3jx#"0 XpcʜIF0T"h!84*] isGHPfvtdʵWYpKvYN8˶h7dv<}m˷_  DÈ+6vljGYPhOGhȠhLފB /C>ͻoے*o+_.5&N먃{1.:9j6ӫ|{˟t<1Y{PQ_݀6 *1:Vh^vh z$ Sb6'b 0v3hc5z<η#?($xA:XH.wK&iMT6%WF\vJl`N!hYgzfm)oB%}ei;R!=~ʧ_$ =n 3wh'd)I7 BU)jL/  Z#g맂JhI+Ʌ'J.[ =cg,Bꭘn[nq(, mt"Ё dB@!Jz-olD`@FIR/b AIsBt9r"0w[l/[2ԬZkDM0thMR Ke'ԴBXt^$tBHC!JK2pnQ,E}bmD8 Q r-gChh.ـ}GAO[BX }wݫ+Ptҿᵏ4#Pm`Hg9N}`؊@D*#mx*"1b|\p=u B{!ܿ@f \Eإ)ꐈ )D ^1EpaApHG4,amP!xnyX 7 LF@}_␐fT2p\' ieV.Ol?(+۞!^BoC; }"ϓ#UȬDC9$7Ig՜6>qpY27pm~t-h:n&! I 4 7_S/ I!A+eLƒیrϜ4Ģ (QEBQ39 '.HԞph0lwтWPjØ#{ENC;z(n˧GקϿXhV^$[ C5XтnIdD"$2f(>m(Q)sY&#)]&ƭ( bU2(e>l1(LbDfeCX2@hd?ȤlGU[f~-d_ H܊h@b柀$qP=+*A D畁F 1P饖xvji|  JYf^骙*@ 1Z+%j+hdx6 uڪ,+Ц%ZfݴYYa|qY)슆n^n;ov ;k0e0j O.[?lqjfqrn \ZlʂL,lsf4|Ε <M1w@ mYEwLfO7-VQ<ՁUXw זJ0hedkOmGt4cw'|7~3Q'wd7~Ey7֢4[yM;MN4䅆1O .+Nϸ:^Cy %o{s&PϮ36Eߛbq%^s3p+P^>Pه^AGƀ1o<yiL܇h(Gȹ`w*,>:D |:!FpCDW}J"iLA4"#hKȱHBPjUrE{z Dަ~+GD Q4AtQ#xG ޑG?$aA8qt1Pa[laHE`Pv)ĠpɁP"I,#62@g=E(")rZfklA0GO!%黂0Ӂ /#9366t&$+@T"3VXAD$ϰӨ}2ਁxIb@J4Xɢ$72-ceDZt"l2!"VU0}L/ Y s{f zO4O 4>r,R-Х: \A$QfPeV깧n5~:&x"EB 5K d21׺*w+J׾ï`K5l4gFREb :.Yfe;(bZuGQfb{ɳQ Vt:!f3P]LMns[P*|+V71*nnY)v @D Q=CnRe껕 Exw/|竰r/Mu,$;c; > jB9 B}A}(Yt{L+=6\*tv aUc0)(@Ƈ-8'.'OP!$A3&&][I5G INN6D?XǕF!FcI]VY :C" 1g8?FKH :R:1ŒsGHo/b'zuLp!5, >3f++3+f+++UU3UfUUU3f3f3fՙ3f3333f3333+3+33+f3+3+3+3U3U33Uf3U3U3U3333f3333333f3333333f3ՙ333333f333ff3ffffff+f+3f+ff+f+f+fUfU3fUffUfUfUff3fffffff3fffffff3fffՙffff3fffff3f̙++3+f++̙+UU3UfUU̙U3f̙3f̙3fՙ̙3f̙3f++3+f+++UU3UfUUÙ̀3̀f̪̪̀̀̀3̪f̪̪̪3fՙ3f3f++3+f+++UU3UfUUU3f3f3fՙ3f H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ`ÊK,Ҫ]˶۷pʝKhpwb޽tc@@DGTR^!7|B1ՌAϋ)8h驧fzEl="5]?wn۩oS Ӿ 1(d eo}<3'XBf xe+>A } tE2&Aq!C 4ڗb3uhЧ 1VDJ ƀn9wA؛BĢP2')(P>8jsQ(bBeTftxSu!ȖIV Yggx g)Zc%:ttxإi-4$ژx]SI]&(㜧֤)k%d}'2w&6Y`"h1((eepLFKkQBP1Hgj @=vZ:qWd-FZK|HllBsCiX pDsYmnΫF!Bpȁ|Dv 1W 0QŬP{[BYH'L7PG-TWmXg\w`-dmhlp-wR;orafce-VERSION_3_9_0/doc/orafce_documentation/gif/TANH.gif000066400000000000000000000035621362147214200232640ustar00rootroot00000000000000GIF89aPp!B,P3f++3+f+++UU3UfUUU3f3f3fՙ3f3333f3333+3+33+f3+3+3+3U3U33Uf3U3U3U3333f3333333f3333333f3ՙ333333f333ff3ffffff+f+3f+ff+f+f+fUfU3fUffUfUfUff3fffffff3fffffff3fffՙffff3fffff3f̙++3+f++̙+UU3UfUU̙U3f̙3f̙3fՙ̙3f̙3f++3+f+++UU3UfUUÙ̀3̀f̪̪̀̀̀3̪f̪̪̪3fՙ3f3f++3+f+++UU3UfUUU3f3f3fՙ3f H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ`ÊKٳhӪ]˶۷pʝKݻx˷߿ LÈ+^̸ǐ#KL˘3k̹ϠCOӨS^ͺװc60ۭiͻߦuc w&eϽF8duבOBW;ߑ|VطDO}T_?V)Ͽ@yDpDX~'>Ԡ27JJ`J-Q 8 ásʩa1 F @#t _A1hbBQeqL 1Q)1hIysZBAKzaј#^~W a d1HmĠA7S-C@XP*&DF}hA=%/n@]u!B+$IAްO&!*s& d9Te UjBe"v,XceW ɜW6ga$gAд AC\r]NF=r)"zħ@vOM N[fBL Cbо"yܴuڜEqƙL'& P%ZUQ4ۛ]s+X>?)@pïHtL/}4wtӿVnWg4oq)j&kC hxlU)UkuG\uW@t2/n2wrOnlK@0B,͊gAO|@q"K#d1;dj֨AӹounAP]HnYd 0DKnIomD%Kbo}j]?Ehؗ?π#.R`k?#t" ԾЃ މ6¼k(L [F?. Y#Ӱ@ H"HL&:PH*ZX̢.z` H2hL6pH:xK@;orafce-VERSION_3_9_0/doc/orafce_documentation/gif/TO_CHAR.gif000066400000000000000000000050301362147214200236410ustar00rootroot00000000000000GIF89ap!<,3f++3+f+++UU3UfUUU3f3f3fՙ3f3333f3333+3+33+f3+3+3+3U3U33Uf3U3U3U3333f3333333f3333333f3ՙ333333f333ff3ffffff+f+3f+ff+f+f+fUfU3fUffUfUfUff3fffffff3fffffff3fffՙffff3fffff3f̙++3+f++̙+UU3UfUU̙U3f̙3f̙3fՙ̙3f̙3f++3+f+++UU3UfUUÙ̀3̀f̪̪̀̀̀3̪f̪̪̪3fՙ3f3f++3+f+++UU3UfUUU3f3f3fՙ3f H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ`ÊKٳhӪ]˶۷pʝKݻx˷߿ LÈ+^̸ǐ#KL3k̹ϠCMӨSیװc˞M۸kPͻEeNNj+_.0yX̣릭wՎ;h[{Y|VSFZYݠ@k4߀qG 7$ԓ`  h % ]&f[&* #*Ԇwbا 4Ʌ1x6(tvB >I%QFVi%l)eN04Iܰ'TҔpv<&M[i&Ib3u zYv(6gpr6*J.ʔa: U i:F*ꩊ>Z*ș+QW&.eh1lNZNʈcfa-|.V靛za{]+/szx F{p_ '^G,Zyalg1d+$H!lǫWTk-4sQ;CUK74 (VOо1R|4dJ904H_7UY7]e؅R=*gc(9h1^N} IYak*k~;YPrO[TcɛmϭP}.wBɱ\7,Ni@;8AZnnQAs]=ypqs;>^Dyjӿ~1PqqA4x=M刺M|KZ(D@WnqDO~"2 fzDfD}}*R?k4%.iS48;I!!C=?033ċA&B2zcD Ā`EJ!X8]K"$%'cE0!+ ^㦚0rhӹ9PkXv(AnkO Âl !MIbaBc+EPsl@ DrDV.D sF˓X4C$ 抡IYjR"y E-iĚ' 'LD6&I*v"i&Hk f'0BSTt9L"tWІ:H_|hm H6}1,hGJslBK. J_IV5 s*ƒ)P auYB=* PuNSj%ں*V;4ՅnժPꐺUf}Yִn%O[2׸%Q)^FҮr'\TW"_ Vڅm>Ȧ˱ue#طhvl Z:zawUZw96Q Fgz\p ASWke[o1`U!4-~$UY[\h"I 9i} .]I[0X q2[N.[Mڏ^Ծ Kqm|r}_tex{R!x}0kL p%bɬ&&1]oxV-^YX63αw@/L"HN&;PL*[Xβ.{`;orafce-VERSION_3_9_0/doc/orafce_documentation/gif/TO_DATE.gif000066400000000000000000000045401362147214200236460ustar00rootroot00000000000000GIF89ajp!A,j3f++3+f+++UU3UfUUU3f3f3fՙ3f3333f3333+3+33+f3+3+3+3U3U33Uf3U3U3U3333f3333333f3333333f3ՙ333333f333ff3ffffff+f+3f+ff+f+f+fUfU3fUffUfUfUff3fffffff3fffffff3fffՙffff3fffff3f̙++3+f++̙+UU3UfUU̙U3f̙3f̙3fՙ̙3f̙3f++3+f+++UU3UfUUÙ̀3̀f̪̪̀̀̀3̪f̪̪̪3fՙ3f3f++3+f+++UU3UfUUU3f3f3fՙ3f H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ`ÊKٳhӪ]˶۷pʝKݻx˷߿ LÈ+^̸ǐ#KL˘3k̹ϠCMӨS^ͺt c˞Mm1ͻ N\vȓ7PC犡+N]f7w;78^pEϸ:oo>}맜Z&ܰq1YC2Vሕi )21d17H⍐Ȑe2Ɍ1 )>h#869ڡ`h׈ Jw cIeBnhik ŠLssCby\nfj)(P(C(Th*zhxP]0Ⓥv4::񈝔mqP^R$*djA::q"pY8k¤@G+-+Pnx`vkޖK ˓={,{7ܒ}aWlFW۱|N,&L,7 33o ls: @wK|Gl14NӃN]Tt[g]{2ةh ۞vll3t[]o}V6G2}ϔ޲TK . K>xo3Q$ 9ˠR+Nkn9n~r뷇Ᏼ뉽k[|G.6)~ji鎲" M +) hܵal $@Ml+k;B`=9!#\Ao!ĞٙOb%_CT}=*.<o tNڇ g D (L0B0SV<ز'^aQX@ r =13` -ݰAC\Fc 8ΑM\ ,:w2Ҍ0S%C3DE[< D&F,#|lv4) s|b=%N,Q8 ĔC 'i 0IbSb ee1ďSGF23@H\V*AL'G:rr'bF0JG6`dtXpcld9 E-m C[lJʃCMVfyP0EeA7q+PR&d5()ё-;Qɥ *BUWS&HY͡6d :r-Vx`OpJVU2UΧEu<95z9%KVub :Qn䬝]?"-A螁GKW! b{*z`AUBj{0^,-jWֺlgKͭnw pK&Mr:ЍtKZͮv6 ;orafce-VERSION_3_9_0/doc/orafce_documentation/gif/TO_MULTI_BYTE.gif000066400000000000000000000034701362147214200246470ustar00rootroot00000000000000GIF89a5p!B,53f++3+f+++UU3UfUUU3f3f3fՙ3f3333f3333+3+33+f3+3+3+3U3U33Uf3U3U3U3333f3333333f3333333f3ՙ333333f333ff3ffffff+f+3f+ff+f+f+fUfU3fUffUfUfUff3fffffff3fffffff3fffՙffff3fffff3f̙++3+f++̙+UU3UfUU̙U3f̙3f̙3fՙ̙3f̙3f++3+f+++UU3UfUUÙ̀3̀f̪̪̀̀̀3̪f̪̪̪3fՙ3f3f++3+f+++UU3UfUUU3f3f3fՙ3f H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ`ÊKٳhӪ]˶۷pʝKݻx߿ LÈ+^̸_ :f 9ɘ3k\ͅc$酧C>l낯;:qgĭ+&W=l).?;ct\qVa}}:뫎؍GYF`dW~) A1 A4X~7` 5`HUFL_꧞{ h@ iVOm@~!HP9P&5"C gؠ =(PgPX C*>^`l^ (h4@nҤ: CiՉgFXy$S*'A\hI䗉[.b{@fzӞ1E_7wT*]F j%}!@IeeЊ#B:AbǠ"U{(E+<)LEi5jc=ﮚO -o8JP=7|`g !1ɠ4Bh-fw3X)6Ln\pbK,a adzBLfq)}i*lMz5ulkqĠ>_U Sp1*s& դ>gXs%͒ ( ٴVH1tmvixPA}#h`W~:id J'Rͽno ^OP&'X'JF"K0o??> ay]qVU(̹ȬOtMٮ[gqF7j:wBHm^& W0 gH8̡w@ H"HL&:q;orafce-VERSION_3_9_0/doc/orafce_documentation/gif/TO_NUMBER.gif000066400000000000000000000060621362147214200241220ustar00rootroot00000000000000GIF89ap!K,3f++3+f+++UU3UfUUU3f3f3fՙ3f3333f3333+3+33+f3+3+3+3U3U33Uf3U3U3U3333f3333333f3333333f3ՙ333333f333ff3ffffff+f+3f+ff+f+f+fUfU3fUffUfUfUff3fffffff3fffffff3fffՙffff3fffff3f̙++3+f++̙+UU3UfUU̙U3f̙3f̙3fՙ̙3f̙3f++3+f+++UU3UfUUÙ̀3̀f̪̪̀̀̀3̪f̪̪̪3fՙ3f3f++3+f+++UU3UfUUU3f3f3fՙ3f H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ`ÊKٳhӪ]˶۷pʝKݻx˷߿ LÈ+^̸ǐ#KL˘3k̹ϠCMӨkװcǎp۸sͻ߲iN#&':`гk7}cwo\7(a\C 7)fd$wcYfeo $Fk ]i(CL Jh/"w(BuX>.Z覈zt8 ( LhHL2Vi 5*A*Щ<*\&WkZZ=*gFU,fl5EF-M2[`n+.Tݞ`ᎫRV{n`+QbuΫ/Qz_+p \' 7ZGS R,Kl1|y"lܟ, }3ql:@K4tGn1NNTOe\wa}YBdvM}rCn7IͭzvGgq{ΟZxl8s68ܔWB7b "kbݘ ϫW4I@8ɕ.^Ȫ~mBhh#'nN g }ދo~&秏+#h ?qğ70L &1} '% V3A >Ax '(dR{rb@ dRf( bsp=a!G%:P|H)Z#.r^ #(2nh"H)D8s+9jF7kvk~g)nWC SGg"YGJnu$tFf([(GI@$H,JU>K *$$Hb $vF5{}> _q& ;kYs \h '1 ^ pMײHU](YaٙVwem\ t{)_٦*i=j+]֧ԼcXmr r_,99뎖9e!Fq;ԄZ.5MY_F!Nà{U7H{U4F&NGpz` EMK; ,_,1xI6oly灍Pvn0C׏50Gb]Ot4݌z!*ұq?7|;1xfxҘ;2+h|IKi49mRIӣHjxWwiUĴwyԱN#_dˆr1Qh(,FZmez?y6mh[v]mF$<4 Т6E7=ntJ-HJN޵|92PK3}ӟG%R|xwqW_Aq<%`W0gs @м P˩S) .C7,ґn3]Wz.SJ$A^!*vg^vow{ň .G^H=&yR%JoKP*8*F<"Oe[$?7Kr=5Gfϓ&KQo՗cO{]w0OO;ЏO[Ͼ{ O ;orafce-VERSION_3_9_0/doc/orafce_documentation/gif/TO_SINGLE_BYTE.gif000066400000000000000000000037611362147214200247410ustar00rootroot00000000000000GIF89aGIp!9,GI3f++3+f+++UU3UfUUU3f3f3fՙ3f3333f3333+3+33+f3+3+3+3U3U33Uf3U3U3U3333f3333333f3333333f3ՙ333333f333ff3ffffff+f+3f+ff+f+f+fUfU3fUffUfUfUff3fffffff3fffffff3fffՙffff3fffff3f̙++3+f++̙+UU3UfUU̙U3f̙3f̙3fՙ̙3f̙3f++3+f+++UU3UfUUÙ̀3̀f̪̪̀̀̀3̪f̪̪̪3fՙ3f3f++3+f+++UU3UfUUU3f3f3fՙ3f H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ`ÊKٳhӪ]˶۷pʝKݻx˷߿ LÈ+^̸ǐ#KL˘3k̹ϠCMcXͺװc˞M۸sv { 0ȓ+M|@=rzD(+;B%O]#An{$&f%~peT ~ w`E`v)M,Ȓ~ aփ'y1P{B!A rBb )Q)藏ᑔ b4IqCvv 426( )]k7P@Ġdk1`ٚYP&#DZJ7A)gHİ4Beq~G@M=֭6Wb'Ƙ^%[ꕛ')c[@4 zT㓁(ZYzZ!1Yyk +Ƣbh j+DA+GJ$7{Csݩa @)p-A"7BkAދzhAJth,:$";vg/ĜO#S 4S+Т57(\ZLIL}merfB^ɮk&b@کfv74] t~x -ݺe>>ts /֢\@ϰ@ #бb4$M6$Q (G0oP׾ͯLF4΀^Ԉb}dnx1Z.es  ɔ;hO/٪/9 0<uV =$BCNgh}J+8m_I"!I&6$ۚH *O=)Utch3&m%KKIB"cӡE:i$$[̤&7Nz (GIRL*WV򕰌,2gIZ̥.w^ 0IbL2f:Ќ4I͜;orafce-VERSION_3_9_0/doc/orafce_documentation/gif/TRUNC.gif000066400000000000000000000042431362147214200234220ustar00rootroot00000000000000GIF89a Zp!<, Z3f++3+f+++UU3UfUUU3f3f3fՙ3f3333f3333+3+33+f3+3+3+3U3U33Uf3U3U3U3333f3333333f3333333f3ՙ333333f333ff3ffffff+f+3f+ff+f+f+fUfU3fUffUfUfUff3fffffff3fffffff3fffՙffff3fffff3f̙++3+f++̙+UU3UfUU̙U3f̙3f̙3fՙ̙3f̙3f++3+f+++UU3UfUUÙ̀3̀f̪̪̀̀̀3̪f̪̪̪3fՙ3f3f++3+f+++UU3UfUUU3f3f3fՙ3f H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ`ÊKٳhӪ]˶۷pʝKb x˷o^LÈQc>Fv8Ylǘ3sB^AkM苧 ֺ[O,mظ1߆x{7U߹ްm]gh|>lz!7fO:=6O!1xxȄ _m{%$ȇ>eb(__A>b!3b(ԄUX "(P ">(T8dd)^ywFvWvhNȐHf =Ǥ@h(@c"(&CڍZ Hї\;yPhsxz &* Fj#uѹfYZy&hHY/|*fJwh1l"nNf-nfcmV;+^&搼`\T-O ]jq-SFR%\1 ;*sǕZxrP& NfddW&q QcAʘ=mЀkDԷr@=4RȺM2 9]g]1>^ѧٸy +u n]8XiMr/.5o Db`8C]m$3< XD=y] RDolMVcɐ͂dW-AW*a@ˋ"<h <'>"dx8"np1ƺ4hx^)3!FAp^쌑6RfOz~ w; $CJ8 D iH󸻦NDw' Ȓk b#JlB>úHNA$R'(Ca;Δ8aI,%iQ?MHlKS:e S#2gn blG>Q+Uh.#&M4k5'6ç;3v3N&m=(By"*Q ^ #sx#)JWҖ0LgJӚ8ͩNwӞ@ PJԢHMRԦ:P TJզ;orafce-VERSION_3_9_0/doc/orafce_documentation/gif/Thumbs.db000066400000000000000000007460001362147214200236150ustar00rootroot00000000000000ࡱ> u%+ L& !"$P'()*,-./0123456Q89:;<=>?@ABCDEFGHIJKMNOhRSTUVXYZ[\]^_`abcdefgijnlmnopqrstuvwxyz{|}~Root Entry@256_2e4eac3ddda94cc5*9@5256_cf13226c22f1dc7e* 256_7874b7e0dc70edc( 4g  !"#$%&'()*+,./0123456;89:;<=>?@ABCDEFGHIJKLMNOPQRSUVWXYZ[\]^_`abcdefghijklmnopqrstuwxyz{|}~ t`͡P PNG  IHDR3xsRGBgAMA a IDATx^{LTW35"mhX[qW%5GKqvMV&l臘jGaYlhEHE<ey=ߙ3̀38~{s^rwW8@DP{ 2Đ A1d"YcڠPJ1.v޻RrpY0MR ,ƌIsؐ <M:u /_.%j*)).A1d^]NJ6>|AJ @t~}qFHKKl]6ܼ{S .Yg:.` qwQH$$ :Eeyl`<*W#h9{Sbc2@0+`"@0 @ L~:=)ikk0+׳obn԰`v300嫼IIMAee%UU[NVL$󿈊BEU\PZYu1,,YrBiu)jkҨf$\IO? {{{DG C^f6mww̟?`6فxhݴP۪Ѩe+ @II #/igۿ0 遤$ܰiΧ 777i3I?Zg-jk0@ym9667#'E%EP)UǼ9ބǶ<(eexe>Y[46o%tvAǸq öhioe7+b !rA$>z&BPWW͝7QU]{=tFݬjĤnҼRػۣ +[b͚5z1Eyu907x?kCG[ϟ}܇d۰*+4|ǹ4y={ Bff&X%%pպ&[jCxwnPnZ78:Z5YϝkMŅG$uE$y#@2%\ @ }]}$+B$C7%\ @ $+B$#+'rE, $C׫֞K9"zɈK"zꁓrDK"~#rI0N믿%ySUQ1~KQrr]r. U QVUƂA6}>TT şCGW z/%%'ODgחrrr\B齬,74]=}4{<p6{ť쵺ȿҩLǤho`ǘmبlxI WBJƊF %' p%ܸ~q1<#Oqe/ǦM{gx!b{/&:3'G0V?{?؋7hjj¥KqL&;((3g+W_h4} glل;Vaa.hl4,Llt,kJ8d`d>ImBK] &`0:I^ŷlEY֯]ܬ\ ؃z pU@bIII0ٱ(DTLs3p92r07b.>4 11J[jll$/_eYV60g\M ;C^cŊOV8u=}=Li1Qoh@QAjbcX2 Yz,_.(" [Yl R>"H4J%C>,jM}&۷%y K9b҉ "jO  ;Q+QlbMǏǶm۸$#Uo&6owM ktnt[bT۶ĝߴ(ww;##/Gt,4@VP^.߿< Rb)Z'w}K9"[ '/bw]9A˩\a l*`lTU@`A/ Ƃ#/ P0l3L06hV oJ0!;uMu4446|r2~:N9ҒRL db~_av3{~ 008ahfTD&dU{JF ǠQQ,qlJFu_9rD>tGe2.R٪P*رiNi:Fa!awq`.:h6t~8jg:6^˶!ر*Uj cYaGaʖ}OZqԚ͗4x}h4PUg|lހ:=~t j}:oڇc/2/eqXx1 c݊.e˳%+# ׭GFv~⏿#ATV`׎]`a?0 d)6&6l}{~S'bݣ8j1?#?.\6 w .4'sы17Ӽ MbގFK)Ϳ$m|z(6gK&5BPg#Sib`iI1v .`M컐2aP;y:/W,wy:?Rl?) $~lzfmXhn\~)؜.G[_G>6/?nnZb`iRfqF9YX>a6kVAfVP=x$ܣ~v11ܼy_x9jVn<= ///$^NĎ'vOo5ڠ 0F'v=`ד، 46ܠpush^^ϰk.=2bd`zOK?RlY*y*;rad)'U˝ ^n C汤`@`4$;s|yI WWq9^#Hp| [GN /,rE(o6^{5,l$t^(/ U.+$=S|m5';[d}!RL!e.)kc439t/Y7~/Y'G%g߾}Ud^dgg5t**+ꚚXh FnZݳM MHHg^ptoR45 S'Q__ hGΥQQQ\^N:a5L931+3hR=#0 D´܋Ȕ::=z=3a&?b3h[zotz/./kVKY];w7o@mƀna;O> nڊ DDxj5}gscQ1(.(Fhh(V\̞[Jf X{{ x/iiEn~.K<ƒ\˥/J@㩩RMuȌ\Fм .Yٙ}&$w/,x$3nLw/CLi[I8 c%7BX4R{O.@`d7 ;܉ډRW_l1`vsI`)Nl.IGWWʸdDKC VZx?x#ٿ/>#j͕~ \^ ̹+VyB15fٔ\^%HpITNNNƿۿqiJp/pUaܹ yEEEqz0Jʫ pDT]3r}!2RZ{!WF +KyرmSҿҢ}FTՠJuhG~UUUl[[-;~+c{;n5d tACҠF.}{Rꦖ&歕y+aðըfqF'xIbHLj!YD7c4~sk1R2,41A@?߿_3\c2Lˉ'd/JJYgW'u+(el]¿pwMv 26رcvZ)|q ap!vB,4@{u;֬9MRFغehu+W]~z)?qRQJCgX _{M.]>/pgm Rݻ[nM_]w15ͳ`87g5=b999,?/utYSK2f4YjR__*U0ob7*OU?r~n\*U,//O;::D)Ƈ2暒>/@u}Qo1خD?a3vX1:o<Н߇,XWBرm45sg!l˅hx_ !99s"/sp+<)x~%R"ߠBw dy 3ʢ#La( 651]WO<΢Fqqp9Hx=Ȧ>|v<5wEz 'd9Z[!fT7DGFC]JCז](2_ǹRӗ1'O@FFxyJCC޽[J:X4TTBj1k 3lx3MXtã6Lhhm=z*(MO`ȱo_[xb7D ixD̋#x9s`K |rWs5HGCљnزe.\x] F7Z)A$@ii Paߜ9wF<qㆌՓˮ]+WY~xsۇ״ǏYfI&/cڵkP\R άwe=b)UUUb^MM6ydh[1k֮yN;v?cסx%g] ȞWR =β:qTA8 S^X.9YsgVAF;|t ~:XBxNߗA\Q\\ J+ >^&t&55fΙi[3FQ^һ[ojԣ=&gwƊ)<U^<~1`04Xc:\ozr,=#0*$ F AxbP)*aLTFT\Ǎa\:30[Zm(0$P^c= Lj0^͸Xkb!\~Jcbd|s 7) oM:_C-G|Xf%eK_Z'2P` $?'p CJJ` A1 A1d"!@A bD?EMIENDB`#z,W-k%rH?SPNG  IHDR sRGBgAMA aiIDATx^}Lw/m ʄJ2cuš8MF (BDE2Ct,4**EÛ"¢  {>^z]6F!$a@Q DĨ"bT1*BD !"F^zW^a@U }Y?B{Gˢ ".&MXdvKs /gHl$1Y`iE,i˖-ջ#::ޕZmͬ+++Ehǎc b嚟6#3#ee(//gY*X"dneE,kA @Vd@`` ElKuL:I[6f-PxJlgKKKQ{!RR>~p {A[]&)~Z-/;eە qqMmz+l'K@SS^!iSZ3k @ޡىZYVSX7O7tH@q^1N8 > WMQJ;؋!e$pr ӧOG`` ::; QS}a HO7{6 DGF# 0vL81c0gڟwƲe˄>eeeؼy3oPuu# ?OĻG}+VtMM ~'m!߆ " . prQU[ yg,^J%&MO*jVZO> 77'X %4"58:!!5NuSSZs¨ꂂuiY)P F&+**x>+lW򲚓NkWm )׳CZ]TT.-nCe <ݭnmi8zHڠy fS+m適SwRU矇#Fͯ&L<{ʲ3RٹgΣGx\p֭j`أ;VkkkYFS__ `<>Ξ=g!R* ` ,CfS Bw(C , aP  AX0‚1~$;' >r_"\zF96 O767rC;; lvm 㳯>h'@} Ar"8!~PT A=Vx}\~ 6W L 0ڵ1+͟!vtW!e̦ ݻ!'B'NpCSՉO~}=}iɨUA9tG640CdtV^k׮!3;|2gL?hnm*fT*;w---DV#Í7 +[T%ơ N;ΑnC7 tiTTW ፷W-J韩S}KHɵ߿'j,ۗ!#ƍ!{wQYQ ^a݁PS[6<79ܼ}֮$I|hP0!&EE $X{ A \ Ǐ!ֽ=O߾}?Z~)l3aR#,HpVuwW~TWWޥ]ٮ eXYMCІ BX | epa! GRNNN1釷7]O8q(Q|L:+2O@@c f қk)(("I?dUfe\;;;n#!)A ѕ\z~G@ 塳S(ōAlJBII 12CD]BmY-*eF$ -= U((?q(*6~uhI& i0̪/sWZ[k[>?3tDjN*=ފq u}醟݈<ްXVZHVPY6z0?$_ef 222m?mՇ J%m謩Rl"~gkww:mP)[Y.{3JR0e߷/ ?;w鴌4 pvە'::WFbX118uuu7wX8̱cDjpu m.E7nI40oݤ;wdL%[~;yݻwߑhٴiP_cB LUU~D0c@a)P? `(C , aP P%xG&mSܠǀ% N-j3PW_'ᨭ;ʵRƇ2k׀u/~!P\Z eR(HNOFiA)OkT_̟;_(Aw4irrr ec/6Y{.~ӟ>5RA4==̐liӦq=ϮgС _^(㐘^{I',]Ç}v) RB.OO:\rE .v]]]BE6eS(IKKǠ6j^^Pz?~\G\\ZT {ܧ'j' lVmIIIx\|5U5僅6geLflXKq=:3:*W#"F%`ǐ+vDߊ<0Хݛw܄{y=oeq'^& nIބ4t6(7O?lP*p#/qEg mC]SSq>BS%Bg['ڻP!{w1w Urns'Y6i[Uimy ᕹ`K1|L1 TDIS#R-[`As'pup)SEKLRQ!\3 .c\ ?~Ǹ}6V,_??,YgaϮ=xg;‘#G$A,XyCU8 ۶nêի0sLlX.gcŊZ Cw^Rx{ 0[7oŪZuClo/%^ 4?#L(ʱe0N>P* yᒚv23xW(rFmHÇo޼''ڵkyڐ6fk ʎ3ussz0OOOk׮]Bxd0 ~)OkÇ~E ?t9/ ~cX'& k, s:ю;XxdCY:///CMM ~_>qZf:SRRxZ͛ٳg ?0;7x1e zEFg"EGnݺZ< H& v,++㦹 z @MϠ@ `(C , aP  AX0‚@ `(C , ?wEqT}i.8Ot4c 50M><-eF  $$'NK&ͥk=gFɲ %L?BCCEj \RI~ k\_KffV|![A`ٍMHyF)(ːSN!#7*S(x gR~o HKUc69ފp%HMK4%,\J}7*91c{fѕn`jkjc?dUPuPRZ-Ywq\յBl#eذa r ɝP+J+92:K-Axx8{pcYfoUpt1f.ފlpطw΄Apk8w7cx ɔ)S+a()/ Xd)̙?gN5.-vn,\ysapW +͟T;g. ҍt(;`gcw׽f ΎEsg3rr'$uruRn0U$૯P&\`Ν;f [puj /))ucFQQ4;!݂h:{T*>({WCivf:|G<7o7x7nprKU>cI?d̶y|O<X]{ӦMB oSgDLL mg.Ϯgpp0n*,čm#>RꘚtsKx{{ 5c}xiC3m4L0Y( ,4 G 5_޺2Y>ӧO*OR% /]р}p e|B 8A LHHl>s=m ͑#Gգ_ 50k׬Y#o}vz ~:z- N vad@Jbl(䡢O[Xu{{P,RjujjQ(}ÇEjp=~R;q!#22R-- ?/XkOtdi^=3;x:=-ѡ9X#`kkVl~4;dFJ# B̙3S=P##;]`>W{)vJʳYqYk\_{5F9m`Oٺ Ǐ˅a߾}: q-hs`(L:1<+0AX0‚@ bzݘ8IENDB`:sd4jѫ߻_3@ycOipMd!4w)$eNp@+sm|E KR0esIѫ߻_3RX2A-ƭ}|ċ:C$:ዙB&Qܘ>l 䑃)\k-ӮKX]4`-;L՛]{[XmI!qdŞ5jI>yw,p(% }^~E@k_г_=G :խEdk_г_=G :խEdk_г_=G :խEajb)X~奯vM7A?_ǍroM3{^K_ljPNG  IHDR#sRGBgAMA a2IDATx^ tTչg~'b^ R-^\Ruuu]Z^]WpU"D`HBBx!/!9!I&ɼ͉c[5gY33I8;{s !Rz$B(2Q dTAVVΜ9#-lR hkkJokjnH%B&E hhhjƍv?O7ܤ2m[jg ΢s"E|zM޾+ȃ7N\N222T8Ca<*>S0?qIIhjjBPPz/cǎ@J.-;#]]P ^k(--ŢeHZZdd#>> c!<8O۹ê`铧OGBl۶ L7MǓ?| nVc52e`21\(9Q8_t!Vs ]xb(R.cQ" {"qI"|MX- El|,.V_D[Svl߁˗/b2n X.b<[7anph?B!}.^f44仱ޥXGҏbaePX|bd+ ZN:>*8vQ5V,[*..L0q7?s!d6uo|9aGFzV^6Z$$/Z:o؏;T R>ȹyooZPT0e+;}B )քw@V_nl]_p:P]256_43c5754f7c620078*67256_c7a6a9a8d70a9ee0*)TA256_a6f154e7f71e9745*0v8 256_1a2f1313ba4ba28f*7l)BgAMA aIDATx^{LSW/ςT!V`q$F64!&E1Y|c6 iD"(l(*aGQy !t>==N[,;=Zq:`"YWa,K cX` X0Ƃ0%`f@x ek< YNgkcs#с|_UUE} Ɛ&L4\m]m5jڲ\].<|LgSqU ] ][&%@V&Ck[+VXgHoKO7O(d?fM%SIDYعs'b/!QDADE_=ZeX:dp8hr477C!A(.]߮#d2!06:FL PVU7{J3!-JRP|$ySCդ`y7F3?]va޼yt C;q'u||Xr\˽; r)C-Dɍ`lظTd?Xx35BCBIl y b_>^_=f,>}"mB塸$-="##Qp3{I%%%C0Kww454a"xpdDXJepuwEȊ 7ʊ|t' 89.fgg#&&F@ZFFyy&9[Pթm8V_ MeX[/~h|&TQM+ :>̔Jo@uu5lm  wkb…ptv3_Xf5T*ܯAXTN^]4`/'\^e za}7`C ”"`kk+;Y\^n7<8L{?L->}q>VpIEe"""h4F!SO/m6oL#׿ }.d_T6m2o>2:;۷0[`f>saK cX`Ag-hsQIENDB`-U#(8长S m}>M}_}}iq `.9Ga+ cX`; 1VƎ0vc0Z-"#"+1HO@hX(MLehd#K 7w7vm$Oۂ[C🂑n*& MF!z e1X촘flK42y=TUT|[CbOY W,axxdeeףhjvs+++#4\tF{n:7p:gZrP(ɓ'id{IIID$==}L9a cX`y q80͌gPaAHi|;"w`Ոy3]h#H:D*DAA >,@tt422mAUCT( Xƃ745;qʊ֨i4?UVTFz:zPv 5Ո;ѧKkdd4>JO +3 B~`\lٲRo' }>9AZ"R/?X] YXӡD./\}>UW~YӮ[ 8QtyYyk< U )Csq ptw x-5 pQz JCSSʺ0PXFAե*|c t2%ؾ};M_D 0@R%\uGR>/aCbŒgm;56m{+WB)폃jxj<-ƺ!66۶nJ@ѯ--yq|>#nw:;;q"V_~M#uHܛ.m$$X ,kLmڣZ5zk֬Pz4@ \^ܽ140vx,Bp|^9 MMptzVRRWh2c"QxٙF)J$%%ȤF77\$d7dxSOήP%??[ׯ_oBf'7742h4شiLwEP] !-ﳾ]ӓo_(OÛ D7o牸"yJpC=F3ρ2o}P%L7 h8Ipp0 $Cd2ʫT*z1Tuҧ'r>14( Dz$55]l; XY9hp n&u?Y Of%u]Nlg˜a@CQ 4z8sɹsxq2& u:/﫿'~~$--j@EJ?=9n6À(_DyDT(VK:Dl916.76sc`n#gf~0aG}~9jYPYMW-&Lsi&; sd{3gVRIwyjt1ǘ;ْ23pKbO>r6n>X4ʷńV$Xo/rJ8pW;,gvۀMǁO7 cXo6@'DǭOOL SO?=QNF(b_zp1_xjl޼ڵkqF43^cc#? =9Fq=+VL?(z{{qAЌIOO°j*7nnNff&޽;+///D"Y c-1VƎ0vc0},IENDB`zmKNԒ%J!͈䂏G fBj#WdO 7Ygg{qi >+n߽bPNG  IHDR$f8sRGBgAMA aIDATx^{P/ ^2R8+S^208ShqFvRbN*TE@T5`j@X1ȹaM*Ngfgw9Ɇ{Ξ106ID Ɔ06%aXbY1م+WbZb$+2%[]B$a4z q aq!ek׮.!zݏ5Ɔ湆nMϚStvvB&q=߼hLϱFkKzmK wcgq&ewwK>JJJp ǿ=f;ܐ58y r͚fO;{UP܋ɑ_QPX(3g'8w7n~mxf^GGhniFsaֆAAAt/֢K^R]\'t/Q,QGU)3 999PQB-AQp(*.\ቓ'QQ^,m6ፑopݮn˛.ȃ]i q6pߋ1Ij6,/ci}+LR\) r1ݣo*P u㆗Ҵj sb"+,^{فhxЀАP  åK͸yrÝ5ːe MہUEIք.#偲[e}CV![kwaO3>? L)t .W  F"C\}Ƶė>jdi}sfӖ叀"ޙ<$<6.!!L fo&LuEhp(9;񪏑1χ?\tEݣ:ށ#88:?غ?tMU/a^puR__O#?ҴhK#m@BnJ]06rHaݘ^T OOO#GFy!6mڄchZˑL#˶m}"3=%XalK c #5GG,b8a$ H$BXXFEK,cMW&7 MQ hiaɒ%d褥aŊf\'=iu87d˖-ZbKVo !!ׯu_I€7aC᝖m w.1ӟL_{FFalNm;!>aɃ؎D|K`ٲeؿ?;݋1Ƚ8$%'!#+EEEkX\(t:;:i_V*xw OTO c@Zm%gMϐ|$+fƏO1]pmgGg#hn"##1fj<Nz'460rs^ZQcؿ{?4}ؖ!Ii?3?>]; 3zfX'F}0sL,]{ Hdf#0 Ϟk?DZh"$|/~8FOh5DTTRSSQUUe RjݝkqEDDD 00F&8x ͵]\&%(+#7...&L%50|p89 s 놛F#s...ذaWSOh97MVۮXzLGNj. ZMhdd'įEG~:k\9b8DEGGIzf:),'_>|?ǎ8q.iDN#NѨg te/N^CߓobI~^>IIM!R૮&%%%4bb߾}t˨dfd2k&(kȷqߒ/3DuAOCKD2kа LN\&v,V%(( `A?/3dΙ\{UL~e߿"p}_-zр:w)(5CRR?/BCCL#nmmp.k͚58q"-a`}3yd,_FǦ3 cMa,0 c alK c9˧IENDB`fmINaPNG  IHDREMsRGBgAMA a@IDATx^LW/P]m{ĶVĤ^kӦR$%*Wi"判T8VaiX\˟ȉ. ؂B*vf_gZuü˾ߛ7,; f0�hK a,00hK a,00;EQīі:E=Kdz$I£ޒntuv!%% %x"4Ҟں}I#8"##ikzZnmTo'Ovy;` YPVVF{LhmkEQQ.U(;:u vή555cjkk]QEmOwl::hV/9U/KDGL,^fX.Zp  ,KZb:&/?>D])j{F_Wnށ^4Jr:_yyMM8_q9u>Ft8QXTaې3ƼgMG ܹs%sAϽBCC@ǟr^_Cqe\N>l*2!0~3ws_xqxܢ9sp3=/"P6ۛq,]sz C[Mr:5 3Cf"=7ox!w E/+tzC ߪXLvCέƞ/8A} xpN/spzkV/A jUʩhgc[rKBf,zrJb߷)8)vAoD ݝ]7@HK<䞨Q[mm(#$lO'ׄe.!@}N߁֎VyrpBӞa?#y?99XRu0̛?{Hޙ3eg0|'`A"8rrUO=ya2Kr(! x4^iDB #ĨQ&N'V,[[B}F" 8#. r9f>r0%)IyC?O26r-?Fzz:#_IG 2>͠k^y oye+\r%W\\x\'Wyu(ߘ`;=:+ٌ̞={ԣ.kQoŗ_DpP0]2ҵk҂˗eiWJKF HUXPNG  IHDR-A7:sRGBgAMA a IDATx^yPSI/GG/PvdEuWGݲvWk^]/A(YU@*u))-(xhydЀ(#H n@@~|肋HJBE ք D  F  F  F  F  F  F  FH+..FaaWD%.A-"j?(~zlٲEDm{u7t F R%LԼ#%GLS@>* yƒ%KT)]wĉPNG  IHDR+csRGBgAMA a(IDATx^{e̤K&% *\LHjvt:y:?|,/Zȹ_ٳ'K@-/RpGGydo >\vek3ixwΝ;wyGydjb׮]… O>dtkp7`ҤIފv1{xe˖k_t֯_t-#hfS}ԨQڵkիW'xb~V F8裥>dȐ`ݺui|ANd|o) @G@A?,[,xǃYfSL ^x_˗/|`09#>l0|̙2m4v[p'Ka5kHc A$4m_|E+j}>O炣:J/rгgOܰ=餓ݻwodh 6-j-NbK _p20BIƁ 7HxO}DkBa \! #AčO2;a  /7 $Ca'V}s=xqpا_zѷo_Y>!|`qr GQ`?h)J `(}Jʑ1#cU$<;h]…zG^R+ʅ52 pueȺ3rhMQ* B Eip|ʪ I`<@RXz@.=wt 󟐩u%֔f"r絷`g֭^z)Z;gy&vRi\|.$~ 6 D? vO瑚o5 Ǿ0͈QFJmh"rɋHA irRM&/Q ,w'# T +IbAP)_"&DWxU0ՄL1tSŅs ).ձY *B |CC Q(0~pQkȌC?EYXr#>7ZGap}ǎ+ ϯjyOP"ɽh`dV!jG~EB k8Y>} w{{1W^yx6o|}1Ok>jsJ(3׍x-? g6-s B Eip|ʪV¨PF.g356!IT Y'xNvxEASJmd ׿ΦW\`ͤ-I@Qn4nR0HL8ת\xU8ʹ^+waǎiӦ/+W,lܸQ/Dž5ڵ+Zڇ= X|ɝ!b^޹sgF׊{ 6$FцdΜ9QQ=  h('UuD(dz[ ȃy%CJ?|Iw0 iA K_EK HD1 9̑AetgΜ)34~ y4dJs[%`%4rԾ<{ذa}"%92?_4Vi¦NDhAs8n@3ݞ߿&7!δD?|pYf*[ ^믿>ZSL>W 駟)L (PQZm4Lˆ34zI3&N(UV1qqcR3۟|IỷU5NJ&"|Vd^GPH4ew}wpw3f̐XD^SN4j0SyyȭgKLjB s0뗿eQv$8%g|0t GqDǴ{I802`jo_ BHY, 2ۉ 0`@iAխ[7(A#r"ɩƧ6 6Tv}R;#{;Lsry i 2DZ׿uN,=TG8ʍ,+V([e˖IU_~YMºu$tЫW؄-i!lJ&[nٲEBZony46fƩ&=" {{(86۷}3 \o^ݍ۲yФ   |S9eʔ/ KD!h %>yٗh: c>{~MJ>01L0!?~|ӟT~+Msjgkpw'O~_Hp3S*R]$aLy!!) (  6G馛d ];Ϳ<*ܣԃs\mhRV5I.QÁ< 5xK\Tfњ `j`#ު=ڮ(y%(J>)T&u zYg!-|0Z裏K$覚0w֯_/E]qF#.y:dU.Ȭ)w>Lr=JG4DݻWjgd‹ԆlGqsZojs=>ס]E~\ZOPrːhy?h|qX*K.H4\,3 M嶶SN<<ea[9Gku<\^F@d+VU ˸XG %#z>X6+́S9r<ȁQ@A@c$^y2A%˗, "ƌF΂$J@Fqӧޠ{Pb0Dnm06t 64p@Y6 I&J@eٳcna-bolGDZQ>U:]2*@{IB}bSP6LUJG)Ѡj0 dwKb6f̘hMi|CjÖf@ԣGhMQZL (PQZmx}Qr~+J%d}'GkQ޽l;wnPVqA裏Bݨ4^5 r AE$n7;t۶mlߣ4&>n@1;3gΔ$HKzH=nV"j}F.A2"@;~O%% osNߒm?n)pۡ D0R`QcA5.Fߕ$2V)J8H>+3PP"aSÑkÆ "GE+={#"p9+RaO?_*hD)2FxI&u۾odlYzmHT<ق$z*fnMn1AEI `j@@ 5zV 48Kܡ (ҝ]6.(I(J58ҪsK`@ & ,y'g@#b)ƞl6uXih%/K1{ (3 4&^CcBZ,9q%H%4cُu<Dߍ֜7v}00LsNdQ~1Ƚ^<8Z>e5 к/hV"#e\L<$A R:BG!x \ѭݻ;rdbđ5$G4! ^Wl5ѣd!pqf6 \>\Dy .$Obh^H8/.',%y}%g?FxIlBf |È8]jQ`~sq4{hi~ CHӑʍB3&z>}xC7@qYlX+gw׬0/]v1E(t}x)CME2Mx8h16gndPُ0V(< 4ܗɓ'˽XAd%<-Z$I 8NPR=XQ'(A$}UF)"LKZ~1AU|~^%зo_9O1rjZB_, H3㯦3vXFƽdd^7贆p88 oAp/?0j&`_ih}ݩUSiD -5 Y{{-5Ra!w_As.]Z5kV遤(7/^=(շL N3<*~VSϔ)Sh)TYsJ7:Eip|ʪ*Q(-L.i6"-lL6x9Lߋ^\3.p8ʍ07t==ZzDֹhdϳS!?ZԈo i2X*gyبyg? cIEY:d#r]7b Fu+J6֬Y# rV^&'d qRPF u6mO 2{{uS_Yz∬zT F>)ͅs xR2\@qRQoi(DlSQcL(i5h1O~"1HcO=T9C9 Vj1TouSc% eZ b%)Ǎ%Gm3X\)BRX`Aa'V -@]l=պ&yvR{J)~ZzBCVr:/*YF8K=I(J|TǧHQZ5hRo~9Y{QJ5(d Y@PtYgkRx g@pE2At $JQUYc(Z0w).m۶vUرcGaڵ29l۰aL,a&0Ǒ!A +W,u։\g-ٳSؽ{g߼ys瞓&7 / lٲEMY&Z q}m7`}% >ώI1HYEvI&IkDD9eDp[nf3 %a!""Ԁ$@ HMH#ҋj{P"2Q<q i$M:Cv\JAr`%8d!c3l#a tE $hyui|y90Wƍ}pժU]`ɻe?II=5ChP3lBi%3Fdݥ0ZS) ov疔*J(|ʪ*Q(-L.麌OajS2cnQ&Gܛ$": rCIYR|.{vԆ{ ֮]+\D qEm 1#0} b"qD DZO|Ղfd_E%@z/^I .0Qn n7]$HٗdСa0qD)(~vLB̖9Ҕ'/!bJq+E(9PiRPjt]QBxRINS. g >@}% >Nj/>(v>0@pRM+ej}Z8Z1뮻.ZS6 9m(/6!Ɗ҈O>5_+>¨PF pY^/~)JI=8{MaŸ[ /< h%a  !whMQ*g:FJc߃?0ZڇWQː>R 9?>I,a>=}hK-odH(`Q^墪zJ}0J;0I8J &sN0wy1jhj\o"TqRe6vJI'Ȇ 6C(.|g,h]|饗Jaӧ㡦P#5r_f0A=o%C6lHi~s }b0Ȅ{ਣ-n Fxr~H HbY1HroK3y/qG[>f#ׯ^Im08R(6P~4hӻw9)N5}ΝU >ag;53)YFɟviRKooo޼P1@-JAKO(:9{R;1%?P7(.qpfq`C3ϔeab JgII=5sN]  F14i~;Gr|bj@ڬa" A %HĢ ZR+L (HQZ5¨P&fmF rz4ztC]R`fNя~)Jxa('/,I#nKhgǻ @rȂɐL E. QwGc҃_G-G45$D<?XDELVa+S)J^x)TyL1chV#Ft#x$ 0`Ə/rGF{qIqs`l0:wj&#Ο$P-*J8KˢfꪫP#dA BP"R+h,PP9AfAKnݺ1AAGlc5=4CxȐ!曃>;Zse_qĔ)S:…m\s~;ÖJw*JRЛđwyGa=$[nC}R}j5Bhb_s@!I."PC A&KY=B\4d2XLB)tqJkI.\^#A fA9E ADCO~Ԛ( هp͡,dc;eT툗;xnߓ*FX of(=@N使EO"LRe$d}r%$5kvm#'7~tdF/Oŋ1ʹ[oU O0AOZd|~zI 3?]҄W S)ȝ E.c=6Z;]vGNwaÆg2d={9$m7 2/\jh +1jyAHVal޽{o0,|ޫW/) >4XZ$i3g5GOe`;ǰ( 6O|=Դ?|ه^{?c r>3㚞0x&a(" ]  ueV \sܾO@TQ(7t14C|b@]9DN%:D"tb8XI@n.^#ke+gZ"4ӵdzl^_k3<$qJ4"u&J' ^Ͱ L,nqBwp¬R IdZ!k7>O3<!jqz'zVmoظv;=vp:6nk7PPҲqFιy󐘘'1 4(EE;A3_vELuvut¨5tY:ֲFҨFGwIjRS_[G~eZg-[͔B@` Dl6l넣#S 677Cӣյprt#&+OqwN\]]7}6)?.h}c=:LQ-\RQ1Q5t+i439t/Y7e$-WC7.Yݮ,LgشijBNOo~.Y/999Xh#19a35`5C9)2ݻ/0uAhz*b=\R /7]YvLz΄OLt9bKhӕ%i N.YS'@DD 5 @ 6l%i%dkXu*lڼ olj:9K/%L5s+Z7-BBBxpAĆ~RBX,a&eI+/ ƂN%iIKO3qiI׼ *r.\KB[Rf#ƍ,wzz:+745`@?d%Ku| a~EEjjj϶IIIaS2( Aщ"OKk V MM+% 򒴨(} ''Ϝs KMMŒ%K̅3H|H@nZ.~߱LB~`` >8Z=}43t`t3g¥ ̿F d`}y2sWtH Cz&S`2)&%/// :`go<Ԩ|&zG|G}z{www6֤ #Z (uoG/`)&Gjtrubt E&&6N,KI3Ӱqe60 #﹎ػ3!̶6 n-ʖyR&;%+:orભEh݉v88Ύg}u=> ,~#sjlVzVՀ/:Z\ @@/KE /A à}}GO0Dw?\]q԰ߍ9y/ V [\peyRv"z2\ \<\DXLv?–Ƕ0gNNi]˓fMafőtl4ʀN j9s 44J^h]i脝-^y<˄3I@|fecdgʪ3 dt钩rj%|$XX1wf8=?VukXL $c7y)gΜkd?w` CXk&==];`ە$c* !݌E(d:ue? @ wF+0~HFmm-/I ? ƈX 8>xb.IGVZzf im*w3@(  `|`\rЩuAS/vfj .]ºu$ݮ@2ȓM oHJ}v^?7o"=# ,رc$+B Ac%\U\kg, T)GG256_8a62740948e6184e*#256_31d6db435bf77ac5*W 256_3838e95525a33970*. k'256_f29948e018be491c*#/^ 6@%{S@>:u+śotR(sظi#=~扽)Q \ee%Ab/DOTYUa1PU /%ډ)Ub/ZGy󦈀 uN<ԝjhP(}=a{o 9hy*@zz sꀐr,bj6RCvl޼Y>nzQjh@̢T,O[z`t0[nQ}̙֭3E69r7n*ʕ+cnYJo߾EQQڎAa3;J:%%Hgy󱵵ń Dd;w&ODsEd% @Rƍ|CSt|m fKM:;;bΟ?Ywn Ğ{Dd% ӧd5j1NBBf͚=zfb tYN{""l2Q RxyyYb(5ckDdhm~~.b>z(Jhx5 i/sٵo߾ 3ΰ)xTNZZTe*d3kgJ%ԩSw5Z]QjHqy;W\HiLsv /k'M 33vKk<9(.*Ri/WhxCŤIߩ?~hѰDD̩xxxq q)A Ry;qqH<^~R=.u+68z(Te8{,ݻ3YuauW.^gx2ecN8۶A4 1uk@pt߯W4'OB>kre9avb굘6}R_._W.Z{-1qDyu ?(--oI/IG=)tD"AΝlL1׏xlmO:N $Yh5yy?Hзo_ ;| 898a䰑#IL%qw@>ݐ_/j'Vu0ﳱyfً-  *Ua P?<Ŷm*j#Tao^#9? 6>=ӰvZ1vvHyᣆx%?N:! Ԑ#>*GV#G%223Z>>(-̿G.¡Ch@Tj0!ADtcO/DFF{DQو;Td$Hcq0 Âݾh4Ν`cdddٳ"vQ|85~1u VD{W(X|9ƍ'j:zbbڗˠW dw&xLshh(:~7xץk qDnݺnnW(vvvXx{yù3/20o<V8q#vE`&ݫ7 Δ;)9p ~<$l( (*)‘Gk(ءq(%Ř]m* n*$!n#p!0`.{  xw03Ȱ ;Aƌ}4œ'OLJ]bwPQ2o?ˀڪ*iUJ-++V֨5ZY[u\w]:^r-?Wii)Vy,+ǰmlaϖX*ֶ]odtYuz}uo*ͽ Xnڮ-/~?s2`Vv "2cڥKgbϰNƅmkWXY:XiVTFO_`S_ԧؗm$J_m, ]`cᚥcf'ja'Æ> ˆϪn 8)=)gsлwoQCӈal 3Dd[n^%MfRu,㙢_F l sP ĂQ ĂQ ĂQ ĂQ b03xIENDB`#)Iyyy-LOMO,շ#11I@RU#:|JL& `0 <<ة$ jE7TߢlR퟽$J @0Q#>!رd^@hpK-QcZT*CF.|i.bY|?*1Ap=V$}6mXyhb& O݆dg`248JBѠFLǏ2!)) ;b#<$ SlV;wUC+ 0tH.{c(8b}TYY#G0 ( yg`PNG  IHDRzPusRGBgAMA a CIDATx^ XTG ( (j&1$cLfԉ$3{W.D׷4 PWWsSPPl6ȸٿ|BNvn\o/F2bQTX xvγgKشyƌ"?ߣ?J'996l9 xk0.[sBpnGOMmJ0n8̚azJaa!]׏;vIJeXF箝Y^L3!aaݺu}4={؃ɔ(NzŲ<'4C(n wyJ  ڇ0 u5O s8`'ePk4RWWf4 ٴg0H6:f`śb E=xy222;4<}4[­46W_9`Yŭ)` 7J͛<,vS*Vڈi@A)(n5h+-7<5t?f}49 y([:;CUB7n(-+ŀp92;}79v$Ο?qY;(X?bڴi()-aCNztj VPZdBMfq^2tk=3PWQVV=ABuU5s1avvŴӐt" Y]X1JU6oI765b!5´R/vvvX0fNg?^z ..Xx1<=1d2?K/sWg0K,9s-.aӮg֯_\lgj=io޼sC6.72ba^71][4 @u@I1Թm۶g^[n3gYlيeo y lMc?QKE׵`ǎA!5kְ4Y9=zTB/s6t%V2oG@In 䩖vRRR¦ݻ'2J%//-+0lےdܽ;l?!)|YyT]S>ڔ~SwJIuJl]Yk O?vmG`)Rϧ\p|"*nGbq<h,jCSd郆nv;Gw1Ců.fL ȯ!Lp 1]e^ÐCx\{,]PX٘2q Μ9?P C"M:+EEFIRÇKaä?x_JNM6o,TtH $ҩSRXXt$+#bŰgLJ<(JT"""K;wa!@HhCvFڰ~.BB cZ ! xs<:`JƤ-V>/1yyy>B-2e~J`B ͲѰ6r1oY{f=˴7m7&xkCn9QrȜxzzbРAٳgW_FMP27Ĺsn:Dll,r\`ᜅl)!:z-x>NN, 9ܷo\\\x$vK-=FyӀ~Xʰi@ʾOTEWB> #yPG`,ak*zQ X @ h{hv@` %@`9'jxJ  ێ<%̍|U1)mQQ) $:w\k;iiir ϵf"_jY˿Z<ի/ysMSUU{N ~qZɮ]x4suuLCk;֯_KQP~ Ţn!._̬TeB~~>C`|cbcXLy#r0<@9hX8.KC*ܽw,|[`2 /O/ եE@7ȲV[i;8|0{#2<ݠgl)Sӟa?`y8wxOAΝеkLjr*#q,Uؽg7e_clG ?ko,{tFæ~3gmo>;߬afV0@b֩vfZ7JXͬ,-tWAZ#| ϙiyLkݏ :=iyTdJJK0qDË _dc?~<ۍ|\H777vSe]ccC.]Y0ѣG6bذaSB!PL \ޭ;kCN<  (:uTk7 &q@@VXrH( bkJKSRtt4pIgt%qF)lgW'INK [n1fRR$Rvf67ax.Q:tF:{,u;C1)N-IOBJ׮]{LKK:&}@#deeIͼ- ??j\ ]ȑHvN$;wxy0PTF KѬiG$B4߮Nڻo񻍼)[5#y$\):Z5ack-^KQ:7Nƿ@_S =0gg vرc,m)/FפS3'-A_z1: _?_foxN h ":@`9';PP׉Pi}x+@`HB X 8-S W5\|wYȂnܸ?ig*JKKرcy oc<4d3tRۗX/Vׇa,i}l޼;E/nsv؏7o묌|5e!$=vJ-` %{dc/_tJAMu Mڥ4NŠ.@tkH< ob;w v>OYw<l.ӊ3`6Z{OKp?~<n kW+Wb tڅ5 $@)+h~k׮~'6ln)P\9hizj-`og֏vErZ2ΧGYYIP'lX{V_>{z3o:StĐEFV9e6ej|Ғ:[GJR R.qq㉊ آ-PBs85MA=!} J&L 7h{|SNA: ֺivBqJ@N Ķmpqwɓp ϝӏTcH!>z8)ɩݹ;z͞J󞝇q80.Z\x$.]+>^Sj$xNDX= vɅKO&rsPx3fYヷzuBa{w]W;M?];0l0d]“SDl)!Eޭ[3 =Q{;9ԩ,J"00\,8l?G~7#9%`sǪ]\׭9ZR#JF)珕V\3]5Az4gQXvM#F<_¦[z^s=s'{ʖPYM65 ut|1(N%!we!Ѝ@ kڴƞutWM`>wukڦ)8PW%K8`go@  ӣ8PS6@`Z8Y޲W`ZM+ fa c1 (<7aL;SѱcGM If_gaX (ƒ1]a\7})́tuB X 3 Xو~HINCPxްa#ՆW}KhsH>hf,5d+.^7, cIN%jGe+.*FDdcU؏T$hDq:/.⹦!UV+qEٹXx ''T`̱; os'TUb1Ϧ!s=1,r'`a1x`qʔ)|{PoͽU %١3kv܉1c\=III  .?EրҬgϞzm17o/sM^{= @R9 (/+SO=ǎK.,>=<::ñ#F )HY;ocK0bn dpF?̇?fYmۘ2T۷˗N0`{V߆n@v ln*Waq ϔ̙3yM1s`'剮]~$Aӧ/^ 4M %% `ctU嬜ҴF*//?+#Y*.vr5sdgOm2ƾv]vZ9թo+Iht~ci}%`#c[Q]G22pܥ33E.(MlХK6Deʨ>gQY;OYPZӎ>GވxpơtNc],7+[^=OLCMExxJ|ڵ,Msɖ&%%'?`<4}[p ƒ  %AqI xdQFveP @ ն<%̍tB X M5,UmZK @q{9k lz9k]6,C6 `o߲g,k*TcYƘsjm݇qBCCyx)M.ePހxS6Xz9|6a g?X:ܵ=+ٴ bikL|O' WmHMaNQi}~u:)$4h#n ׾PPXRz L'|:LY֓Ob옱pe~ rkx4(NB(*f7gIY Cu]5 ƂKmCQ9pus`=B5(*(BnN.F>>) t BʛkodOA[v= GXM]ݴvXtϩ9t^8{U4ۖn攀YZB h^IhF$͹sc{M^oVESWF7$cƴxqN<QXXs4_b5姥\hƶ3...Xp!_͍皆\+B`&ڭm@ b!~5aKIENDB`՝tI@%P}(T4|io6h@ 4-9qB(΢֢f@s/# ;kv{&(qiv@3Cb!0? ޳gO+hT~].|،Ši5kL(4, h'myiG{{t+D *O6O~1?zv0+O+ۡEDR x]t LCq`K9?":۷|՛hj2_]TB}حhO`$]A‚q j"Y)0GxxX_ۯkrIp7*8Yxჽ.w{_'|}'&}CǺY)O 9A^^/ FVfIјbcMfk/p]pO(cmdd$@وewlNQOhx@p \x 7b&t\|MMM0_,dRb<<(=~YPU[i7Ӑs(,,7 H9q)xSTT4u!L/=%fBVC!󣭭 ,l^a <бCRUU[鷐͔.=V= { ~a5Uz.,Y}_:*(*%+xbБCBV#$ nvg$&g4L@p?9 rrQPP|vm}vn62s3]5+? Eaq!22P],/mvvmhl+lmYdݢ"y]hnjq21bֈXdVzz ݺn89 -Ia&7=EY-.-q۶90 080%Fq[_{xyz|w+V&{rp}:{MN ӄV(={OENsvuf駟fer9TyU9*J*Xn Z4*_X-Y`[bwH!kƖ׭]..U w'wبmpu?nE||ر'ÇcΝ\^(5UMFٳg4uI@`6Ǒp'?ϱtR.I-8;>'q2zzzĭ@Xjك_|KK1e. 0!^0^,@i~%,hc%Xy#j^^,8,z!''rE( 킱#@`d (;%7B| /H.X>s|TnrpI GfGQSWa0b <,Ϋ_ߏahfA>>>_o4K8<6n% XۈV,^pqq[L &b PlÂ9!(,S~.fff0 (/D}m=ۚ#lmA1;;;xx 00 .dgwfju)hoo/d#zV6QX Pj | '6K9c‰PNG  IHDResRGBgAMA a'IIDATx^ @YǿH1ȞETcƾ1d'w0 3eAR"F!D *{ZiUVӉVV<>ާ^~ p8Dp8j7 p1p8j 7 p1p8j 7S-B'xZZZlOaǎMzk׭ v;`iq/_ nGCOaoz`.8;aʤ)ԂiS7e׮]gJ>!!8|T;r̥4iڶmpM;v)JDߏ6Ξ? fGfv&4d?f /a`3abi1bڼ55yXh;`괩LOll,/_M=| xbQC5l ؞ټy3,YB99pZukq'>£Gq7ܹ~]8¸16o}uLF055E02]}]C[[NFMÚ(ݻ1gNW(1y?7y3s~zzS=1f:u={jiiV]Zan \wED {숊Q<6n܈e˖6M:zm=C ЫW/φ ?0U 6ܽ J:ȺLɧ*d,>V#JPCꈆl#m^G\sl0D!s?n HoeJ>9 z;P;wbʕLunjToW^ @x 0Tu> MMM|Lɇ}ÙRz]vL111>S5c255K.066f+353NuF@>d Lq8U!J%тFg$ @S'pJ8Y9a q%(pJ8d&888#!lg ; R0,-i٭l)h֬ ݻr SѲeK׏)QՀ=4JF oZQY9׬YZvɊ8هqE K{pe8s nݺ,=4[JhDEE +p&ekq8#JA|Sg{,ϐCR>~ل .\~#ѢS x)I)š#`TٸfqtrĢoaϛj*zLE -)<9y]y?R_ʚjyOwȒcJfG!y<,:.\GQ.{ѴQS+$$'`.,,,-`uL`x \`Y:=pCӖMq#~3=",X9SCz#$`ػ{/vQ5|}}iZ|H#Ǐ`Ilχ̟?&L`#fxŊL3ҥu煟V$$%& ǎ 7gga㖍45K[OaU+Cnٰ@p(,^Xx̎\<:ECq|SN9AK/!{I[S8qysst zniӦT˿]~c7v]]]|ҔIx%MZ*wUG8$Bҍ5RL74k:ҙ}FF0gZ033C`jnݺtNښЮH4@}*VݭЪy+8g x92QsqFƨኧ#5* k׮L)Hкuk 6) 44ϟgJ1ڷo23PP`:v9sus+g]"g$l DZpT(CQqs#@8 @CrDቑGQMxHƍ3U9<}vbJq]QfEzu0( ) V:?~< (ʑ EǛ7op1"23LSc/[ )q)8}YV`= \̧Qfٍѡ}}QTDNv$h(fbcc@ۤxb ֣96[h& qmܵưf i{vAD6LI&,^B]'AzB:tpN|5+.ɓ']vLAAA8z(SD"ń/؞!JSǀSjʕL3 2ʒ,;;[G[=Mv-aU% ]͘Gh$}m[M7 1b;v;w \הDy9 _%9^% ~gwVT89reS|岐%)jqPuPYlSӵښIOJGϏ{R?S4WbPfhя9y+n|9qF)j=_QG`eRvm3)!-jnn޽{3WH$'|G̨]J.1v4 yJ0GR%k$1,SgC*O Q%4$(FSSI:!ʻ,K7 :SGU ٳgCSʃ:SP58v-NY OTA8I) j7  U+zbG>,?v<'=GpXS-q V\s~ʥoܹ\E^лOo!NѰaCXZZښ)@휀iE 6C*̙; ?s=:q5W)0lߵWsǰYnp]c(f1$<$DQ' H€ym@զ+Ο9Gbx9k0khfb=틱#RG1 6tS}9UQ7Yo6@E`h`YvhѸll0vXjpG=zUf }~7c欙ty;sS0298jg$3R,)(ITC޷iӆ%<<L)FӦM1x`QӸ~:S ;w.؞!@f3RyLUDUfK*U*ʣ2P>KXUH$;Sylٲ‰']N@9SؕW>Dit 2h!{+xm?w/_#*9X庴F.<9|"GbopɪasQSݬ3~4 fŗ3Dе hdj5^͚Vh߾= d4$#p i( k&7{ፄ>DS nCF Au0rHt sss;^ێ ѐ/U V^38u WWWA"0)+e@]QY7yN)ZDYSgAG;''*WnÇ矙RoԮ.+lgR4]] Lq8U!J@PIBiJDi2Ʋp8!ʻWp*Q}]2%p8!~vZTYD9 S'+\lϞ=:XhQد]F%@XXSGZZ[vttT$AвeK۷\H֙3g2裏*,\؄P w) `qA*U6Mv-2hQ={">>>tlY|e]l=yb040Zd9fYגVɣHz0Yw hպ5hZ 5 jg/;wDvy9Μ9CǮK~vЁ! B<}}t σ\ıѠQ^ Uf͚rE~A7j|OU} #3C”|,H rڵ+SՇ&uYzbg:2UuP)Xի1c *SNNȾЫW/y...(̙T"A4 q-^IIٳgӶ" YO>D]`"3͝;plmmk@ qfrqx^HVBe@_zǏ3if͘. !߿_9R4 cVZ1RT)v g+ TgTiD9~8#J`eH{9jg$p8*G,é B$S AH.Q-tuv) OUyd.\U`igehҤ W2dҀUNs-TTZe_Y֬YZvkt3u!xaGՈ@W Y;G޽KG4CiGDD !!Ob 5=QQ|G4Ljj*K'uRR sm?(oH:t,IJS<4 ҹ&th2{L8d@>}Рq\t}GhP(<=qM~7.]r5z"J' IoEŋߘpɓ&S0x`Ohޢ9v\T*E-Zh߾=Rt9@"6mؾc;u=4Pi~ؾ};Y$884ˏ{ػ{/vQL2Y8rS@$ G؞?~g}}Gڳ4StE!<:AbR8&){Tq1H&梆z/g}xJxx0(͟СC;aÆ!<,=ZExJ0+'3oT&qc<{:ՁM6GPZ m&22?³gՁI]Djb*}~dT$Gg琿D12{r9LqJxTb}|< @>G*U33M )3|r'&Y/^Ȕbhc*oo>ٽK&Jr ŗkd*7bٲeL Iddd;v,ۓɰDfΜtl*}4nn4)6oތ%K0ZHprwlOِ}aJ]o,_ >T͉'j* $$%%Q^a@ id֭B@ɓ4 ۣjgŬh D"3G1wZZ?1B87+:u-] 8}{ ӂgfe !GbbT!5-UHNN~j<&&NKOd@ǟя∋d]vʎڀ %i8GQ>.x&#) 2Ɣ]$TvZfEL|۷nֵ[oMWq9@zyY+GQ S*p17*UQ<<23UY {{{}eة#9 %>ƍB hbڄ>wW 4 =V{Zkh׾;|,tiٲ%S6Ȣ۳f80ӧO%Sy?@ABCDEFGHIJKLNOPQRSTUVWXYZ[\]^_`abcefghijklmnopqrstuvwxyz{|}~i++5 &pe HCC4>;;kinnqwjcp(ÇLZ}obvs8vn:g9/6뿲1iL &a3MTSMOOFG5hjnǸ=(eV!xbgw4XM<қeebrr2@V%Dž 0)Ih} Y f҈yy*ya~nS ~=[9)) jTTT`֭L322g+UUU cҥK4M3nݭO@=I8FL|17eVhmz)ػw/u9;OT!3k7XHҰgtuu0b$-Mx7ٯa%}8|u1$0>Op_T |u,0zhw?o0Uk7} L)~ᇴ7\~;waW']O3,יAHR%LbZ;gxܭ-[OkOHzCaI$:L}k峢Ǥ!.q~@PZZJ\4'1.#cwQ x%1[139[02HsYg|*ڻQ__pvᣇ^Bl6dE\fn3C"n`OKx[&h 4x.9u|*ӉcppP5hl{ȍVc+Q|X {nuzvX-VtuuJhf뾾>ttt`6sbDpaԏoߏmؼ %aX~=BBBR*+HOWL&_#< F{ެ;B`9syy8Rx='b_{J6slGEeRvoe! )\1rPNG  IHDR@]sRGBgAMA a *IDATx^ TTu/  B3\,G8j m)(PBdj%HY=҆Iv .J3u310 W4@^3߇s;scB$߄ D(0 B$ D(0 B$256_5ca65f06163082f(  256_df5c3c559487929f*2256_6ab426aa68982ec3*-256_4f104d92e98e83bc*d D(0 B$N6\v ZVTnͨpLLL c{.W]F])]add$*@rpi3FTUUQc(鰶nӼ,bh 49vb@X[ffTRԭXB說Dk\RP(Dn^^^ ҩj2,@Q"aHGۉ5r$@өPYY̌abPaI\/òZ O@hX(Oyyw gym<61+ZiֶV\3qUv nvnw?2,*DXa-;"14L;iqlΜ9eervލI&J"LdNkk+&NQv1n8Qե?܆T߷7GARĮhO|@/]rucC*,Y޷`i Pnnn b@h~sq\ŬuvvJq˗/q}III= QS*u setug[uEE^}444o@^f.$=6+{\_OwLi\wNQ=}Y_ÍL=;/^ ϣZ_F:\ƹb/Fh i}=M4d *՛V 7pa{gE.)6vc0j`{q҆)oݽw?p­yicmp7xQ0x%M{th:!F֯;x ҿ;T*"99YTmݺ *C+%%{쁍tc]n޼YFBB?ӁYW_};m( TTeHprrnr_d8yzz1Z^ac,zwA@Do} a`I(P=(;Ys3sQ[3)*G{=ZTѣE1s&Ì!zVѩ ;=%(*+վ ٟo^FSM˕ۗbNW:6=;}gZs|F[ŋs_Yw꿬Fb>W~AA"^%%k|Fa@ߖ7TޮƆ n?K/l? ___@-WdIֲEpwSO!((DQ| e?ߍبXB;ɘ0e?zVvV04Fz= VVV 91m6455aΝX5ضkVFV00)ء:c<> PB ؃ϲ>Ѣ(--ldz>>|0b>S1uX!#q]"ڑialj*h=Z\\2f7OQG\ iw|Ś5|wQш%K/xX'~-Gܚ8,Z'ۮk5 _o!auj M@:`|}k2v%XB`2&22?` /D~o=G{TTƮ-oooQTSQ-ED<8faqb~_R^_FZV?T`NxQFao^]O557wf¬ٳp a"VF`3;_ƙ 04!~!vl+]IavYtI#G(JMF|t[-tU#jfe30-~2S~dfvs}옟Hf5 K@~};{n۴ kƎ Q ຶQ6`6v9) K6~zJmlm>O|g, v?3s?6Nˑ0yk2ȯ&ml~z\R!X?!?Lw"lvCq0C@ ,@cM#&<1cԝ:u @zzuXXXRTf]L?;u C}H!F@Q"aH!F@Q"aH!F@Q"aHrd:2+IENDB`B?ulIENDB`dHJMhG `HDEFa괩Xl)JJJ-%9y'X&VMCPH L<y5BoˈEBlt :ns0fT*(IeB|}}'ff!==ԫC$|}2 A_ mM X}q9͇#RRRjX0__ܽ~%,?Ieƥ!~T3Tw#Qx. 23ءޛ7[=7W2T%\>q I K2'Eaa۱2z%"@S߱G2{Y?6PNG  IHDR.NsRGBgAMA a2dIDATx^U[qQe B  D6!,FRr?*?Y~ "a' BVIBHIFdL -0s>/vLOwvmrsG*!a]GO0+ 0+ 0BGm̘1#c==iӦ`رV&L>G[}yW.,W_ 4(*|3I's=ho_^}K. #g("L^xAW6nXYhQ矯0#Wz)ٿjժŋ+k֬xG}|Ae֭w7o|V={|{O֕jnPJ NbŊ`GOD[f`ٲebMO>`ҥіaOnMs'%#7x#8Ã}k˃}W2obcDعsg}C 9~f͚%9^zIsM_d.O #L^|E}c!C35\ :4s9[o%L LOZ,2wa_:_L.LU 'kB"Z롚M7?TwÀ FkoVXT2@mF[=̙3'?mvȑVʃIC_:h0_-ZQY 0+ )So޼9]!C @[{F[AY~іa&-@֭[% &raw˒%K? S) @-M{/җ$j^{-ذa|Am"vm>Ǫh( )9;gJnMvqgưU xM7 ;`̙[xqO}JFʕ+E:8㏗L>  礠pݛˮ]D ϊZ50zx7O?=ڪBiS`/K-=W / 9az t ^{ETo͟?_ o|C %%k0$s:d5xΝ?ۜåVaa%.&5ځP E%JtO<1 :I;w?t!iO;h?(w)3Np?VZ%ã>N=3,$'A]Ƿ-Y' 2V!d_~obd4#_gƍ24]jGa<#UHo( zkΜ9Zs{>}|p;EX'AjӨ%|/ ^GBo7pʔ)?L6-.!oV1ڒzY@LPGy$X`I$iաYD*BN<\YDQYLʄpr?X='ówuX5 .y;{Ī@ h!I&҅쳏=cYG*s~wA ]0 J@ܫrJhYKtI$dd&\>ԅ΀$CY0g-ͱS/N&FIҏ~kf`ܟ}64ᐎ>*Ri$,#&MZ8e*Qb'-=%5|+љz j͉42>\ n`׮]oJ~zuLA֕jUS`-s %P/Xg=t=6Yx< w³6|M={ߺi{{.?5l}HM_C @(g}vL$pZ`McZ j:h$ZOH8q'vx 4:YC ^TKI:pV*I#̘m%S-}W#k'`ƜQG3[[@ՠ% eI".anCf{RJ W{f@^X['AM5jd`i1 j^'ޖ0 ÇyMyOt:wY)A(ؾVn_OF( yG? y+_W(e,:0!2 iԎ5R={.t2z~3f{o9ktO'ŌsL:נC& @4:it61sh?_D hHOW#2 (_@N a1z CmLAߊ ywmGgQ >ӌ: 1 (_>44ܱcG'iwF҄Ft& 8Pdk/}0ALЇ};F)I'0_G!`s .ҌFR𥏴4wa[yge/_~Y"|{{ʹQ}hίbٺukeݺuݶm;XhQ֟fQf&.'Y|g z)9L5Li7'|{WRJ FA4"UBp,t`ķOMΧԆ*hxV]C9$:>?4J9VHxdR׃nd*rLƣ@&"i!2X!ёG) 0us_Bzz j݁/}sy^3IMFi&u8dLG[A?BL/8_/ &=%~v݀0uI>UtĀx8"5 fv4ѠCq+5ҦMLFs {%trցuor+)Xk̞=[>X{Y߯ v.P$?~$Deox 7n# 0 HR]Y$hq 1:B+O}{:ψ,v{/BtzaD;`ӱ88k A(u_,%p7A1P{S(qYPy`&^1Sܨ6|&.wljX,v% mQi#_? ?u]Fh < nQFfʲeD\YV7n(W&@"*a*{o3b%rիW˾pM|wjFִS(5 ?*3:ĈBjf:與%5eVH% >`^VFa4BG0B#4'\hP~*`쌇l-vXeu@d&2. b mm֬Y DG>pPaIJC@_'}L>:K;$\rN axK/v s |0;#^|2fʻ+l,_ݎU2$v< z룭ڕ:IS?,ywF{? RM\Їh[`ƥv$aJo8h>oC-[7d3B%"# UVg}vnyV:y^fuQ$xǼ/@*?)($}!օLdzɭ a]G N0$n2?/ R`yF'#b3W<ǐ5cfuq3-À Pxݹ#AQRD=H+Ql] $iFȳ#U@[bdV    _~> ?!dA7x 1]s=hH'5A>(g _O1iQǖ @ǽO=~Lk2AN@jLWJ MרQdn+5l6.\ҮozcQydt$#V hB e@ユU>o*[qf5hYpǂ-(X5c+j0Z4~H 1z: :t Ţ`?7VCOdZWZzz?V-Ӂ RW,2Id y){wrJ$~_4c1L˰uȚ ` >W;AD%.z >5UIFg̎e2xqm iK;w|);+ ख़d67}Ņl(K.M,1&R>G5y`O>ƫ9X]aPR09 }_ ߻z ёJעÉr?rӹŰ )8{ޤŽ^'ϥ\KQ((:VL[sj/uwŭlHC)ft2IhgN9p@iV$ѹWuX-z)#8IPH!+() ȚL h]X`]L}tv1%UIA!jP:h:ኂN7RJӯ95 H(#[Fqk7Fk |~ YWX2訞}\)SDZ<,.|߳`e} >:87XT.sCvlrSG 6~Qob]c 14\ 9{l{{LXX08ZuqqFgqM~#Il oDX+2$3ӕ# kIEb; r$>)0UD6*B>Yb)0&e\LJG_rl*;v#4+OE[ktY􃔛L(J K|aqs=E'!õ8Ľq4#{`Ĉ@[^=+ihw0/ { C IAXЛSsSQQSӾOG^pذa\DcBEBȴ~PAR@3܁iǺߵ;ph˧K䉞=hADk=p^TK/a\4iR!ZM喚89O53`!$yiH2Z`a= 0U&XQ\IaR`?Fcat1VFcat1VFS( ?2RA2gpw U*:LX3ΐu 1%7!I>P&2'>!HiEUs=aY)EyιsVëvZ/G('D(R^l!P-WsWM_vm%(*>cƌh?uX43PYs,h$OCH8oCwqmj{j4vBfa܃O|G`Ѳp/\. .B]"?؏Us/_./yGop;vȺn@z ECmp=?,XS}R& 6 oLfjQFE[A0u븳|JP'O{u}IF"iσXb袋d[nI V< kF]ӓp;&k'F50+ 00&GKٟg_b/2? <(r0"-j4 7ojP5Y0j}'Jː /YDX5eʔkHFWrw .3PqP2j(P  = w%Opc45vBz7ݢNu m4:#}XIRolǷ?7xw;3[˗:@mg}?gϖO߳5ܠԩY8PdԙPcanlLG.DFb뇅[\}/:smM$),ܢuRVI`! hm_"^0 y 8PDC$|[A4`^H<;Ò BL`  )$3V(\x< 3^s1|y͚FnMgh4 h0rH6IQyH2u+}G&ȑ#GVK-VA-X`m^?qh+kۡܭd&n"2o%ly+c!x&yXDіBn0L~گc^&*1+J% cgxš,s8Fc@qz.]cKq8 8#d_Q~ #M ;!Q!j) ^X?)t3f(d^:Pz5~#Y7n\Ё .=n vl*Zz*|-Fv2QO +6mI ٫6q K/$%cǎի.w:3.ZrOYZH-gNz@YJ ]3t8t\RM|GĨřX,PۢdiӦϏED1Zܚx('dY$IFF#Rd8|`pnM/|GǔG9tL9K;Ćh)*gM,Y"-8p?O"kŇ:xW&]wݕ(u5ꃡZFZ cҥ0s:CZ] P&6 @:cM|> \`A!W24-&gdj̘1~ 7$FZ) \Yȴ&,o1q38#2%k'F50+ 0Bc_Ha * ĨKGv)z3utxm2ȓN:: |GY!m0N ݣ0%0`iJz(:ujkبLqw!Zye˖1Y&SsΕĿ+~:Z3[[n: 5|Q,~-e50Ө0;,~PRp> 1] hPUh%   /F-ψCǎ+Q@]VBqF=वm۶nlٲ2g1Jeƍ0CCa LfLj@8}[N ZZ0!kN@~0 d0}8:ÇzYP $q _|@Q+Y; -857E29q>1:e(?kFZ0 ?Fc@' m$Aea4,hCD۷02k,1.=XtFð KfķX2>21VAIKRT;&@1#(q܀Waf[b'2hCd~կzGD@u 0@v52=:aÆE{{9蠃zUk' +@7@2dȐ2?tfȡSR9]$xjMjA2LfhW`vעJ#JаYH󈣟TS<mnpfI!Ld -H^>ўg?}':-?e',{BDD&yOD@fFὍ1"_@uܮF wܣ5Z >}؆XBc{۶m .?E'D/ ־˵ƽ~Vv 'ӧGkFɚr&NOzSYo |As%SOi2;h Y 㠹]11qto~# By'VJ܂❞p 2@}5\ǣhxV`ҥi1/q%3У=sLiV~mOabdd26sQG~p80HNd6J;CA~m%ɜ(gM$ģ8IM5#"Pp3DZ&@&/-* C;@) ,v4Q*4HSH rjZQY 0B3/@D):|a>U+!i CjaxWs=WÀaXP䣀D՗$F4j>yu N̴߹ߵ(@鍀x'EpOdii*,x0>jܛnI|r@KƧAvgKqQW!QbRb0*PϭͧAJ iV- <FhsoX %{\c[l٧% ,"̡Ĵez,!m>MjԨh+Ma,B_~lRo, p'>q T#k' Hh`õ(u.F2V?6A#n"aūXB"4i2xY&{d*vFD,4y`@N& âS*>u<9^0"C#QdZ,LjM<ȪD2 >n/7o,. ÂZ0:e?{;عslAHp,}U#1 5:qƧĭ |:e?6;^-E*m|uv9hARc@Of O.T`+DZ oS y晲~- $\_0-M[8)>RJy/QNVŗt}9Y6%~ja߅DeAC+L/xI,iz"}C#}zqviko}ޟ0S^Ź>`= (!^Skjpj_R%[kڑnt HJL@z I 59ڷIm̱G;jQx[7"R0wJĝZ=Z ,=#β /P2@U8tEz8=u@Pj2o<&… +RYhQtdK<8 ҥK+ӦM;SI~հ\'V,YRy'*a&$~># 1)]㔢65bQR ><6lXtD~B;>" wۗP6I .@zʼn\`d<;ܚ>s"k 48 I )iOwݔs4{tv" hFҸ-c:{ˀs9'L/^)~ϏB 0ZFcat1VFcat1VFHl&PnIENDB`#3"2 9@x11`f? HH’|^ &| @xж% ȵ( k ˃}:\  X$Xn]?^9^Af#~z,p2b`%APEokaG<&H_j4':k*g_C^FJBCy]v%=[rʴ8K;_(Bq@ϕg`#_X ND7:fA8G~0n>](7~IɰZ=VW*Ota:6?yҏlfۆٶƶSZßcuJ ڽ ^ڞ~DGpe "0&bPgB륕jDN es@KMIJDnpŝSqD~pRȍpccRȉZDҢR1 @zu"P y,P -_\*Q ¹lteڎLsATTT#D3m~lOŋ ?/D,NjDN:!"ꫯ瞓jdyXa=1c,UWW;K]f4y6CgG'OE6<[6<2w^n\&K*o÷QTTހx iߟz>u[ںZ㿿}ttիh͆xyy<[ҧɰj*: 2s;2[,)nuBTh;z=ǣqH8\ cǎ}X}jCd>M2sC>;w>ذa+WAFFҎիWF=`X; ʀx> o?굫q)d2D3~jmph.F)X9$$m0ϟgA2lfB5BQiBXD_e gCBJu1-Ǩ(DDF !!1'.@ToXpoelov;?Uw~jk۴n\:{b׮]RLdؠQV l4vQlڴI}}XcܹRLt"u`oD>ϝSQ9 He)h.t.] "ܪt%(pCCzuDFGK]A(N{ l,i+L0fCbj"<+VJKdCPxT#rRe Z3Rϖbiiiزe 0e1ߏ;vHKf۷o٠؁ȹRȉp]]4(Ȕ .#;p8'liiAem%>>j#V{g nik᯽Vs yyy|b  jUXl\!qQ~QaFGGqD΄!(\|5--RmΛ1GN8:":yO'rW z{ǐq$=ʪPYY?gج6d;֭[f/]˸x"cNIGWW s=(..FŏpZl{&85 ?hlyP)҄_ eG'F7AnV.|}|R,6̜9l6"Ɣ> |dGdwq8f|'P(^l=f|;ol=f|1.ϙ_vRiJw:8qg_>qJR^^4 &.߉2 ϓlYPT gsvLtִL@DRWZ,$λヒ۷ ?k4kydJ.aԪ`J`Ϟ=xrǓP2ٲ2MFOƇi'~ќ4(͗JDn<j)"4ЖA9FPXZH]A(x`3-ߦS @=mz]l$ȥZuُm;AJKdÏLS999jS?ʖݻwcwBTIKd٠kgjSG?j.N ,rɢ. {PpdD6 VQQqfkjb޽hmhDO R,K7ފ^^6mi\urg}` Fit9UkV_0t`l4w h@oZtu <0Jo%_ ΅[[ ˜r 1fÈyXCF,#<`Xq9\ Aew CCCЫ4 Vww?@P@J' (Jvcfxx6ewaAm}8wE,б2bR$;Ly\ Hn& /%@sXhooGҢ$lڸ '>:˕M>zWHNLFhH(Op;Yנ|V`d~e]W]򚴔L⏊]NSMӟ'</nHGcXӛ L^gw=+-%i`x@*Mc_4@]هP+(!\l6ޝn{9YFMmeee<õ' v;w҅@rbӱ{visxPTPhSrRT^H)x`v[*QNeMtwǓyQui;D>m P}"i36P`UXLdîB$bPޙq羵Q@ |(Q>QhK0RSR:N*h2똕2JDnS*Hlۺ +|N 裏zJΕZݿdz')KRa4ǿ&,+*s4?я}vԉShjo3;26B^&_Nzz:] Ȕ x_A4DΉFG_WzU!4*%=[hـyxw'? 6>O̞DHL#uy*q7(81cqj;ҋvc; ^|7x5 506#@ڝ{e DLKIIJDnS.5U5|X((Gw-ݻq9$$&gIKZ6ų؅̜Lxyy-6 }MZ\~-x | RRr! 7AP~¢BrEww7 D^"X@(.??E==|L7N/^uXˌ?q>)W_EEEdQEC~^>OgNJ&Et B4\Q9"y"""`/>ӧ g p: }2np t] .'b,eƦF:ųyձ vprtBSgj a_L?z̞6?xOOPPX7~zڿXb XϿβןG#7SSSWFFuk301''gf=<<{Fc| mڂvxy XPkܶq3F*e{)ۧn^k֬܁ |=yd#nK"? 6aog* OpDճw7O7 b7hQ޽e͆eG1իW`AVV̒h-Śݻw*;;:܌0L4e=k6 Q Ot @Q DĨ"bT1*BD !"F@h`IENDB` ͛7Ƹ"8{#+YZd5 p(?)BPNG  IHDR*\2sRGBgAMA aIDATx^PW/EPʠZ<z8-sʈ92LPz"nC G$Z?ġO؂P0gʝW-!y5 `>{//\BDɑBD!"F @Q# y~N9 J VXQkY48::bҥf%C%˗ &W^^.܇OJHHݻY4444@R!"" t @_>e("bȀJMKEJtu(ppp`k& rΝ:$dg⽵AUBƟ3p"I %2`%H%Q#_IH\‚Y XM_@PQQ핹vs/;JA~~>ݏ7WoJ3/U#AҟX́掋?6nd '"> dѥKz8rYv Ei&fRe1w>WuSժ{?~{SkԜD\  %BD!"f62>S/:3f +1iw<bԩDۦE_J'xN0VEQmp<8ʾ)cuj(v*XO`Klcn/zfbj;|0+ٱ_37X2R )26 %B#v܉8Vb^'#=RS0c Uyúud.;&-;*ZVGI[x|QPAe5"<|Ed(RWd'?kƇ9BqX7Hż~O.R"Ü9s 777dff m6F4^G{ ^+؝[}tLyJ[i Ob Yd;-ZNlw;d2l޴EPPs [hmje{oXd;g.ODze'1eҳFnZ<͔999DအոC n+ĠJCM..B I^~&aeUլg!ϖ7^C`xH<{ 4 pb ,z|/RWṙF/mmmfY^nݸ"=fB҉׉PNG  IHDREMsRGBgAMA aoIDATx^ LTW? bWR-uW"n[J7T AcYM VZlHɺ -nw +bEረ( (0s9s`-8#73s|s83K7qf'3c<p Ogx83Ǚ1P((-- + &[,-Gn`WXBiIM_NyۇEZU"oaa,-,Yd< ,`%3ӱuVٱ̌L+pqqa%ٶsdaVg#αH+$8qXd6bd`J꫿pqp!A}g"]RT,2D"aktG8lMil`piҰo9X֤Iٹ8p]8-+ZH4~Z@?NBK+P(KcJ9P(|2-# s,JKiӔJh܎ fdfe"HˊqḦ_ iߥhUb g[tMG񆫫+քAEiqFd@IE upm;JMMe['NiiiXd9VB{{;׆V-tvvQx{ۋp?P}d2Ruk!7/z ׯ_diÞ{٭{E5`HLL,2|D@,BW^̶6i6 .?Gm ~jjFja Y ?^ b[ab1}O+++rS@^SQ7qqb̙D"{h ݨ(@_[ɦJI>^1$p6,=-iv'Z[$,8wmDD{Mx Y^O4[4T*:42K ]Y 7O7?>wqu8Y9vAV%16mɇ"#ޞ#wFzCS+~=ƮG~ vtc lٲ.JYe5t2ܿâzoDPh3aXMMp Yݻ2Jvͺϯ}/y}>Oؓe[gki 7Եש۷@=&oKh P*olȚiև899s89Xu δܹs!"L<;uuu..fh캻g``;P_w~)ُ4\,UРw?0 kQدv&PVVFҥKYփUb޼y4Vr /?|wCˆgl7!o׏vؑNDrׇc fmb+1>)mwb[ppp`מּE74Y8pqw]2?:tdee.E>__vdBnjHOOf͚J4.|nnXd BFFqiiHHq$\<{9`_w蝴4B*HKbZCBCBYknnFNN6lJƦd4V6b_bs`޽:H0PX/DDD /u`[ s{I="?:<u/~)(JV06@й|z}<~_ Y:Ev}eIII1?m$^t"Im|"&kt?Ha? c~yy$&Ĩ[n!߫۫nx?$a4=h]"}cjŬ3ɓ'>ҧB.aʹc+WIP]tt4{)00>gCkk+<" $'zN(2/azp3qŊ,"IYCa "|:X1L8\o-)qzutR>*b45+StG(b5߃oSQ#L<Z\t:n̷iX~=`WL-V l"C u>@322k㰺Q/E &+%Q nU^ لM7!LƷc:>C+G}1" &$G-*%T68R4֮[oz Se= ^:H$JdL$NFGĭl۶MDv 33/-a?8p@Dvg@V 4uuu|Ý\lݺUDB *0.2ҳKnܽ69': ^cz[ WN2;J1J1J1O ~șE~BB}yf:i;ED~^>uH^ ⚻I@❧M^+Wl2pk؝,$&&色28u0,6$oIb2 (//ǂ DkEEEذaȳ*..Frr PN_uWΝE䬣رk^h?>ǙH ݼ1eˤI҂E+o#1!jGV$;dhU9sP+='J-bD/G:@XTTT ))og+!!ocQXs,}KY.]t,NxM?c*&q}u{-S=#**JD"}#ԅ<gϞZgܹ#G3^K/-@ Lt!~!~!~!~!~!~ ?n6 IENDB`ֵuh .8F-Əyχx?|ҤI½U*YhH(Ν :}EXd;W4Ex'W25#F3vyx<_-I]ZĄD8s~&uj`',BlO>VGRB\AJͳP%Kߣ<꺴 NOjyI᫱܌Yf(q͘={6+:rm6;EֹpN:ŢOoKS<%RYNMBQ!"F @Q D("b-uhZIENDB`)?n(0>|MPNG  IHDRYфsRGBgAMA anIDATx^ TW/4-8j" ̠y)829jg'ތ'>wOĈLLHPI1.( D$bˢl6M׫{) AlB7ӧުnnJ!@%L! Bd!2a#`NNN?Gvcٲepwwj!]aİa![l6t@It ё͂׬>K/NިǾ^_DZPr))ظ~#T FŗU?!,0pwr؀pss3|||0ga4!jA '''Z O ^PNG  IHDR@]sRGBgAMA ahIDATx^}PX_1X{8!-VAɤ6m|HqD(qB3T1aPDy1/# jX1pypmr#ww>ә1&2Eh4?JZ#~~O/[ ddd`͚5rLƆ DEc1% %(A7hhh@4I;CI-5&~9ee0/W׾/ }o-ܼ~SlM}dQjj*D5J 0uPp~h/c֫7+r(a ĴM{=_죥DK8)9"ֆwQ6Oz@2uޞ^ݻ}}d2IRGGd6KE%''5)..VOΎdWnnX{cԩqQ_b1psG@b >׋jhxx/*tmٳGTQRRpƙ1"k@\%x @b "cHD* R1<|oQ.ww5VPRxy؂;D54aׯ.W>#44Tyٍm׮]b͵%$$p**X{]={V2Mgg-*4ՑE,NS'rN䠤s~1G>aޏbٲe(-FVn!dIŀ+۷n]]$&&*GR(KyOз^/~[pɹzloxu[c>ut7o{sEĒF,a49>!ơEMM ܼф&c*k*`ҥy8t:۹]D̍9_~nDOwbЬ<}4t-#w߿_ThFxDoF^f"7D"#)+֮xw܍; 8q6oތxmk(//GS`'}GKtt4ZWWWL4Ij(O#lL/^ıcDEO;oܸOOOb޽{7D@{HYhNWW,v hrVZ̿iIQQf03%SY?t\*z)D)n_MLit9e%祤IJ{Riy>Z x-|yQ ;ÖNt: zjeίQkHJJR M&Lx45U1/B _~.,^XYwv/i_BGTL=f#[`[6d}D/nN5 qF?@~'Zi…b/̟?_T#?(js^ ۏ+_^Q]8 HB?b[6 zeq%`NNE庂jjjB~~lgSrx%EEEݢE0}tQ iii|2ҏ[6@d`x4#Н;aS"7ԗ_ R11T@b "c r|!P4.W)V ߍMdEgΜApא*,,Tg׋} 6f]3_ 4i(=W'bŊ0YX>̞=[<k׮s?ς@uEY{˖-Z 4== vGs"LfB߮GǃMx~>"K&Zͥ(2eU+:2(@Qq4f @ `L ؉cQSUY!4VʚQW uUHx@6T.υHΉG^Z~!223fPjW R1HD* R11T@Z'eUYHIENDB`&mZVG@dA00'_^i~֭ﭖ.Yzl3%q/b˗-S3[ zzzpU,&(?%Khljl[BLjWz-p.qʳT*w~~xdzUb?ۭHLHĦMHە?f^oPG;2u!Ox!ez&PU5zFNfSuu5JKKRp:sN-#Ξ9_ǢEXgfbM! C K>, _7Uߌ9ms.=.5 nŹqa3ރjC/"Bf{z*llFI33Lx%d?\ܓ4{+ԚB 1 bM8Uu q PAHGÏë~7? 7ڻZkl'@`'G`^p9=rЇU%~fJ;=A hw8ڿ"l2Vbb"*++Y5!<&Ml@Coh"OjmiPVT']\ƞ X1j[lakyLw=3 2|%^\"^0"bmvA@1ľ ^;wp x8Ux_xf7cz(>!Oc䯇Ł.)N     G !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFhIJKLMNOPQRSTUVWXYZ[\]^_`abcdefgijklmnopqstuvwxyz{|}~NOi.\mX5ϣUC.++{j z*ƪ%̕š5kXgz;-(*.Baa!>x)a< !FcH!F@Q"aH!F@Q"aH!F@Q"Ybkҙ(IENDB`#Ξ9 CJsBlEm͍*Ȃ?w%vV\s 7cݺu(+/Ec„ P*Dآ06&OCiX=~fΞ8 +$AȜ\,AԿu7ٻk:m>"G]p\׸q8uZ-^2ݷa֌Yx)9r3f̐uHH D:(**hQWW~...R !: yCBd!2F@Q D("c1 Bd!2F@Q D("c1PU[Y~hk@YY O T)1zhM9#G@TJʕ+Bm 814jkQQQCSO!-5 ~h19yyyh66#?)=..GhVz2 <;KOnj1?`0^ΎF#bum`DHb?TV@VARl}oii8S(IF\ŭ,.qj;5bBd(66T"g>|SL珕-6Bdy svG t@(&:t|чRI>lEyوƈ%~K$`0H%@HcQv 6CBN9\زu RϥJsZ"CXLߨYS1mҳӡ`BYfa@Jz49vkT"@6l5& ?e]XMSMc}>ڦ1:6e8{S(`7j8(y_zBO?*;^Ŧw7a…{<<KDzE>3~9sDؒ0# P`"> 8?٭WY%maIcִv~遟XˤRz[֭[1h}]-*!//O8pKHJKK [# wjy}grWRmyfij^#/^ 6lwqrvBp>zX!@X4FlXDD/_.z;feWu&cʕRs`e@Bz- Bd!2F@ɾkxK5=ozRHH&M$8qT9Ћtm>@!9x1몪Q?BHE7n \2vD!b:vFW_!BVZ-[bE,^kׯ xBMuoFeU%O ZZV Ɉ~ , (+/v;wPQU-[~z梦55xzz˧ӛ1hG8}4$H:SgNdI$MƎHܜ\TVWlEߞ,{s;7I؃Y<8od2S34NV,K@aRZh9y%m?_.'g2{ 7w7 >7o˸Ysq*&xe4c wcyg^;fwR{=&q`wa= J4J #OVaTa_/.ӾOS)T|v*i N3ޅAFRÒqU[A%N3ӔvYr+ Uf< ^ t6rr|&`xDt_/+ 8\8~/|;TXht:C8|0bG44`Ih65cBmq!h8))) F@YFhT '`l1 '{ΝÔSp6,z ݻK3^Zpo}WWbX"@X?K )Qb/xi,Y!i-~ڿ7[U&=@^ X,e*י[߃mb (i8M J|ѷ}JASAw;vZ^no{gxb$D&T/NHׯ#00Pliym9B$ -Qp> |#~m?NAֈkG@ S0m4$'#lW\4{.Yv|&†\ 2_e8xOƭ[(//ӻN9O|jy889UUU8箜dw>j.aǾ#4d\˗. P,Tȁ#{I|sQZZNc UPԓxRiҰx{߿?~}RJ 6;D^Ajܸq+?@I#>"o1j(Du!ȼL?:<́wM]_F 'HM4$E%a߆FwoDDaab\/4/ aa{TS1gʜ&%xX/?#5jr酽ًw -= {P7]GYGdde[k[(pȓ벎;I Ppy _)ƽ{▀]{_AA\"Lܾ8,Yf_eeP*!?;wƦM(,áCXj aNjXO C>Q]{bõ+߇MZQ+h"OxOF]_JRq-*d.n>Bڵk5TTT[H x\ھZu'58qH*L{~Q1{bҲRl囙 dd|'mnPΔb#v&?}XSృ111ps?r>;u)1^1Q2,'ԙSZ7㻣ߡsXl󑑞c?qD?b `͚5[[[3F5]VV֭[ƙW^E A/^0c fh(Rɓ'7h&`\TVVbk@#Gw训ҢX~Af'׼;UA?3#F/ mC7/?k*5Za.lXDVvVbכ26:L*1a,B>RsY@ڏgE:/}gܡ3_9p3歙=?Dttt>~[Po 6|nNbkӱ`b(WT 8M?1@JJJtDq#; Mrpp*++&-;W8tBO /3U9U݄H$(3ˆ#_@!\rAHNKvokDŽU^ŗ t]\2 ;~'~.$I>=e W ܺ}  qF̙7]t5`؟!Pu>J 9c.?x۾nx=~\\\ˮZrRkD?sLQƩ |yK_ cnޓBet' +TEbK5κNBPLU&hZqFzD4T}MNXS{m_EznK,/#wnY e%6k,~iE@LH/,24w\loy!d "C#qa~1(1a^> BZJ 5 C@=&L~6tI\S? B]Gç7TM@v ,v)~p֭F[z}oN> c)..|ڳAlCZ;A~cc_6bkl!9B$ D(0 B$ D(0 B$ D(0 B$ D]jٟhIENDB`ǐC@v A- P;Ix٩>i:9̖&}2 11jtضmTvFa˳qc256_77a15b15d99037de*"%H256_71ebebd8f4b034c9*rW256_4203016071f8786c*256_b5b87915f102636('8S N[kPNG  IHDR9sRGBgAMA aIDATx^yLTGǿ *Z R4 cD[ci&5VUGŠr)EEʱq9ԀȥfvV`}Eg3oofV!$Jpln8džñapl~ dn1<_:e˨*[ A/`]:n8 Xr%̓H*?/C.Ǧ(.)F}c= eK<ly#[Z-8q  +3 O럢u+K= -x:HU?T"z@S-[hkhmmη9j$JCGp ؉X'L`1D4+1z=AR1I^z$i$Νc0Wk֏O'g'&q,ْ9s[&*`REEET>>> ] yB Gkp86 7 c pu]pvvF@@ӺPhhh`yf̘{{{qzr~c<<L R&Ġ "Eb2i\W[5kֈ pMTVVBS HNÜpBk5  þ)1; b˗-N:WwמW.:}IܦƦFA1'* xI&YM$i6\!7K]]'&έ[_Y X| s2M6mbZddjՁ 1m6̛7i9[~= ܹ+x݌B f=JLL 8F+ip>q;d嗓a n湸9vIS\n+Y NN^lԳ,6Ӆ]džñapl?Ƹrk}IENDB`=1Ç'O~N<盧pB߆ǥ~0 cYg ~Ѧ7Wg@z~ i%dDAH?*=zTس{-$5OLz^طoT3͝MiӦ!w!ٯ _{+("ctp%~.Tju?T>_~%z-t tA̙3G[z_k>}z#,\zU*u777LJ#"\/Dq4Rc.;i69Ci}ʂJHIi Tߪn'h p A=`ˉBhoo'4v]L#TTT^i %s ZMK=Huu5GNN4ZҝX, ci"0?b##AG˖=Ӱ<eQO>]8d<JJ99LLL ."p"11/~T&){LkǕW}=ӧǕ]|yxtQ8r:;IvVnV!>>o"pLMM5022a^ccctk~y!+3 ooodffH$pZ焾>ܹ)gR0n5J ׵^cp><Da$%%!L=.Ľx'Oa3i{;{Z3r/eCL!C #Gdd$[k,vcj|^[k#OLJ%˯_ʋķӽ{+gcyk9ovFw?f7[;}хS(rrrzj6Y2(4f$''cj*W`lb z&_>G^ ;ށ~ᅶ6l8x q5}ׇ 6`h`OtT*ى`ʹr  x3̬MMM FL&Cnn.T_,BcS#J^gp.ΨUG888-VC#*\zF/) ر8<Ӎ~([n!A%),,t"LFK$!&OK )-(%C!,]fzzzhinH:D"9r~ZHɍDrJBTIt핱YښZ"khvhBbHō ZCwDKjvy3Ǐ;bccald(~֟m;^6Bu8oDHpLK ~8^H||`kkPEXo ,%-blڴ "h09J^`՝;4cv8x aB `붭xǹ&&' os'Y<\A|[; ::U,,5k&9}FSkW٭ⷵc\2X%^~QLM^( Km: ;;;_kVnbpp]`N:nWWW;'=a8 |EDB.]GE-k233~d+%;ό&.u`S}Q[G_XZN_j={`ݴFSCCvZZ3<@jjV&o}ĵKAA:4 466"?_sJÇȀ#(--v9r%%%4Z ZKc ~Jٙ_*l7m3 lgij?qcb ~kc#CBzRAA33򂣣T("c@Q D("c1 Bd ݹbIENDB`FzWDFF*)Lc+) e죴O R-[ۉPNG  IHDR15#wsRGBgAMA a IDATx^ PW?7(7ȪqEOM#2eb054%򩪨0Fg?c4jl2XYH>/;υ2svPNG  IHDR!6uAsRGBgAMA acIDATx^PWo0QtXiǎs:rڛ^[Nz:ULee:^[ShNJ2#(:FBrHOn^XL̾Oxv嗷AB8`F"30" È+ #b00" È+ #b00"ԑB:}F1(ZF+/"i&N7}~2fnL!eeDuitN'$AGgy4 Krr2D:usn(6oLnn޼yt*~f#4-Sya;`p]-ʷVҌ+ lv>1yrd,ȀdPBd0hiiA[[z=noyZ^/^bdQ3 ш 9ܡw_fW;)mJMsdXfv> 'jl\.eԧ2@of)ļ}Qx=(Q9]NmvX, 5w Xfa~SVl{=X2>{g=TJ)$ Ω̙3!]GvS'OE]}M݈rD L:|at*|^Y 0F:f?ֿ9E9).(5 j-;`(*+B^A:/u ˄-w?>sw}6lڲ ەۑ6er<8A:Bv:s5)$])ƄHY$t^AZZД{?1h td0AeGFuj`ҙZ#Xݙ^c/.t\shkm֓tKk ԭji=cn6@ߪ"_)M׌-1y ,N { 2a#SP]'# qkGjǸif;؉8!OogS{?ݏYm<Osq;DMm KVF>>#-CQqطt}:-F]m~r;>ف*e.#GuK?*/Ƅi8T=@ܦ }x  .Cs1^ou"ƣz^ƍG3)--c#00!zd܃pF!W-ߴ8N.ߍґ$K6"xdg {Y6C<6ſX5*j* (LsE;.!l`ʵlBq>ЌaRukTbU*=.7:QUUE#_0i!%k% ,$}$95: $iQ]mmd2(tb@c}#91/.LTF` U! D#Q ׻!*6CTnk}Zߝn6vDΟ;O<3ҥKeB#@^ )(. v7Ձ@fT~PIrsk][8{Xna.4bBwvS`lX}11X L۫߆Spp gzwObyr:w+ 2)~ilp+./ 3'Se{5`JJ_žiZ=zF7Əl1cFC{{;E376{l-{Mss=nnǬY0}t <~ J :7Gbj"vB˝tCm*F51VFX`caD1VFn?IENDB`OT~]Eow$=XZ!`auS@-0tqFXiO}KGP$}{addDK,]ĊH9ύFLնnJݝε-==]Cɏ9IQQQ|o׮]tN#222h$Iφ m۶)cF)5,} A111@ee%r544aC.Z*$s...aG@C}\8QTXww\vЈ_Vٯx1=S W]σFa#]jIL.:9994S}SDШ_d#%%ϳ  ϓ%wO/O\xO?AEew˗/Ctܼ\g @P*?;utLw Ya+p֭]{׷o_L{{{?>])stR4p(zj-15-Өs*p]HHgTu&h+q9دGrZ2`fff|4y32O3bŊ[l052x7kVFׇy=&ɜ::PVGDLeBS]f Fl?Eȕ7փI31ƣF¢9`o(D~-rfc,ۯiWTTg4k1~xZZ[#-q_c_'DFD/_Z{#zhi <:;+@QyyByQ9VڭDHHjkkq'; &N2g/lOc>̩o^8ڎp3G1hPp:>;|rFuuua*((}:WgW>qRRɘ'{ Dŧ鋳_};++1ƒ $X{KͥCo***h<^sK3i4TYQ3Νˣ?~<})Ooj59ကz;mjloKFzZC&`yrk$H/ѮPsâq=&9ۛHe <}F޹ &Úi2t^λ}86CEI2f≈'0Į|)w\yaØ1c _o_8;@|,'OaaaléWrᏇだW e ƮeW'Wxw]݂̅3hnDlTWe 0q u 4j;5ښkԡy%TJfϞs#n| ܕ>k:LdVŊZ7R*R^Vlmm _J.\ȷ,{i7p4 %%hmFFC#~)ϻ7= ɗgM,YߕǣЀM6zRs().A7ډӧOٙ'EMm& زq 6o،rsNA@G?݇#vS,||Yl!΅'#Mv`lxtT͝ 03d&bba_-uʩ _Z9* eښ<#ndNb\W[ ٸY @s d @о죣>3n [-g/Odg~LQh瞝TVVƳ;/fs"cb5ҋg<6FE1xk[|ɍ X (( c-PNG  IHDR&+EsRGBgAMA a QIDATx^{PSW/"R(/e*3 8#*Ru256_3cb3a123e0fbb184* 256_3195728e1f6e0ca3*256_d4514303abbe2aea*H256_53b83498bcdd3934*p!     ; !"#$%&'()*+,-./0123456789:<>?@BClEFGIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijkmnoqrstuvwxyz{|}~j;jw|TeWjGEviG Պ+0 +>"jD*hx<ݜR I60߹N&&3N Ø/0&%1a,0 c aLK cX`.2( A׷llmhѦjmmmxa0PT:bD:jq_{cݷo}UƉAnܸav܉iTUU7{lcmۆ6` U s9ninACCJ"@-gR$Oi!ChazXYYaذaGX ___i4667fdĕ+(+/Coھ+W |ɇ - iNÝ磨'MgcxfEւs0WXZY"!!fJ3s'N&^ t'2[#ޢH .ϏFƇ0W`d45RTVT3@l>^^^x!22F%HCc7KKK 2Fݱ;X aLFz9u2ӨCCcd52 C_=+ήp+6[/ӧOuf X<Jo :*^4_Q`҄I4ٳgpl OW,4Ҏ%pmy3&\l+ @D"mݻwVgyZkhYhh(m(YO0 {HAǵ(Zhj cur>|oh9.\ȯEJR -Z0bE-A B^nG豣8~E%E>p;dkx1̋fUzJwbccagmGhm+VVX"~Ǝd˗c% P)ThkE&}R=]Ž^:p aaH:25bzaBU~+x xK07onJKK5]֣]Gヹȯ/}'D"|;DEG֖/ߋ9[p<0 h0 b a\K X3'޽Ky)p E~ +CWR<,XCQ4̉t8`yRO&)) IRRRpqLC`Ma`p]]AF#cʠja4R = 0‰fh4Xv-E DFF{)Uc Ӄ?nÓ'0404<uZ+(,@G{4U!55MMM,3x*)L&;w".]dĉx; zz&= LFBCChhĒ%Eeu%X߈'>;q_,43񦚹3ڽJKKqF,Z<ŽUya§!6o jlED|g$+yfjkm6һ;>y? $M<Ҙu#?kJ%$''[/nkxxh}=6W3lB{Y'OR$IHH)ryyy|` ur`;# 555Tr.KҼh:9y X`fWۿoE700ÇS$yU*Ʀ9B>.q[7>* "rww@ ݖc*b"?gMszt:E Ýv547M22245~a"Avv8\5ׯ9^Ou P$!;wPi|r}N3f\khhH2kM1q!$u{]'[/=qdCJΏOp0wgڊl_\8iiiPT+%V^|TUU-Q^^XTj*1ٷ3S)JIpSyWJέ%e% jt}Z,?} MZvd6!gŋغu+EaE߱+EXXEcJJJpeGn,ɝ+ X[jdU Vtz}Z餲(nsr$N_'ƶkC*M$9VMh;ts2SwP,N_:;9>ѣ`3͜JKDr淜Te;FT4"eQﲚ 똯^!E={P6c#<<_EϫtY|8.&&!Cw;j*Nx(< 6 9%YyzTb0+Wo>O={,EaҥK'mOX*^h\+..R-[F5;v .֭[qugl_ձb ;'&MrTcg+$>>>INLuޑ$41} Ec?aF2rL XW-ø0ƅ0. [DNIENDB`8VcqW^0VЯu-?\3۹JHV`Ø0Ƅ0& /!)+IENDB`mۨV!wE͞O xdL$7 úm됰./MApCEãdee!88gK!#GEdd$ԩS /oBBBn]%?=Q3PWWǾ!X@qTA~>b @(`D+& X1Qj4#4*IENDB`(gK(ea#ps}8iZ]塙 , ϳߧ%˸qh,-- %o0{l5uWU#:}t0vtJ#UH 84h$۷os>-iÇHa`lhp~8͛l 6 օaq^Vy? L>1q10`ns۰a̙C#EXDRPX@L& }b7 q \c|'K%Fi@ʑ"ɥKdeeJK% HEM>*$+[;[Iƾ MέN, q1qdg{|tI{oz*)..0vy"pvF G4PrEǑ]ɻHWO=5k8_xm?<"#% &.%2^Z'J)PNG  IHDR($sRGBgAMA a]IDATx^}PA#BA E;%md2JPG[Włg$8d2rLF*D2vp'wʁ >;;[c>/J8!ɉ=B%B%B%Buj55,3^Xl)1hljdq]⊍Y8P &N|Srr2g4Y8P!wU,PQZf3ȼu ŭ[HJJ¶n<^ܜ\deelKb XOO:;;MVNǞI| &8G_$\5;Q Ul˅֑}bccQ^^ng'_Ꙫgkoo/jV ~ @+C}< gΙm0TTTLz_9sjQ-x_ qD{a F23YizPkԜ~Dϩ5 {rM5 p Es}V>,qY?|kB`IE:(r[Jd@,&&,w2|GL&c5Ξ=+vګQh͛7UVA Kr @@j`ph:fٚ/+A_o,˗Ȕ[0-- My*5c&M}2\Y54_fSTT3giOɍq6'L]]8՜"׳~.JJqoGƣ`3I;v;xE)*)B?RXEP``ׯs,0;lcccYźp788Ȣ$L{vllEE}8.zMyj⸲VWWuAx|H}mXp}tttGƖ{}p<[jV7c0Ƣq--D-Wޤnb_s8CblT܁֯_eHk"֭[*.AJZ yAQGw :h444" wۖU;Ⱥ4>//#CۯE25kI"OM,*|s^y^) L*wxo`A}P6OF#5 q,PoooDwʼn_2\/@)-*7A&T*ɛo wR^UbsG4C:="h6o@ι*yXDjJ?3RլB<..PV )Gl8#Hxy!GAzJqЈ>:ctx#^RH$x5U4 ٽ$:=<]gSo)m\_kIF5R։wt{#gŒxĢyS'N!bc?~~U,2\vES^xDmBeU%4ttw?}Y hP5`믶/?W Ehh(t, ˖.c?ayܭfP(c5@fz&>a5 aDDX)핑">Ciǰq)ehooG`@ 6rҳm[O^cLnnrqqa5<(\![^A6?VctZ`y%N3T)$kYlÀ lM^ɋ3ip?MOqK1l.!1TC6o3w'wDf!V 90eeHh|#TqJ,R^+s ob3 ;i-PoQ\\CѨHPDjjPH̀oJ:%mPMN#ٔ XUQEۛEohjaf&lf@55>tVDvHꉦ?üV1j(ZlժUZDݧOrO]]Cf}YhiiAmFf6mp2)d_Ç's000%MՆ҇=l;w"ͫ4_$(.Ev*WM tú廄PNG  IHDR/BTsRGBgAMA aIDATx^OSg/$pQ3c^a,&,SESL^NqJ"(hPJTNsx&`Kȴ祶=9}>=,V`-M ø!Vƍ0nqc0ca؄^=ttS6u<==i9vVzZ:ŁM>ߟFsuf!l-@OoeVye\t!e EDYzJ&h² Hh"(82FL\qW\GͥhdUUUJEF;4&VMM2[h{*7(MdddP4ܥK(?@ABCEUFGHJ]KLMNOPQRSTVlWXYZ[\^_`abcdefghkjmopqrstwxyz{|}~ +yULXs /F;wh}{ܼq 2>jC?eKo#|tuv犷(|TU_ ՕP*w T Y9o9Z(8p(zR?cGa6657?^ի0G'Nkqir~TFiI) x]ARg%(JfB(b;hiŝ[nd2q7TX<~Q(~֗ |o 50e]Rf_ss36of6M{khZ \_GG-Ŗ[菢"|l?G͝;w@pϹd2.ddDKPn=^Bh{H6҇Rkj*hZ5XbN0DEDa7-;VƧ RuL7؇.$%%AX J ɀ$~S֦@٢DGK-Ǐ#4(=\M.bzfP(^?fI,_N#.WdpT6nHs]F `Lfϯ[DJ" ]* Wd52v^b$1Xh!b|Ev/KNNE@s%WG˗)%JtuMH. Ӄ(=l(^Gg񅟻ԩSBf5k@4x׮]XP"(*HNNϣ^Ka4xo-e5Ӟ?y4a$_R٢nSS6њzrEKuKϩ5;3[W,MXJ 4*km)sKm[aqbdd =۷oCQ6u%9p%///qgܻw/eΜ9P& ݰaÈ=W\$?O)\MMMطoeCb1oud~N-GM(A|B%&L#eGGKK 'LD256_24bce8348b2dd3cc* 256_e333db68c318f3ea*256_37d47c8443930b28*256_9f8a104110d437a8* <}P0su!?#2V~uyznD,DsL>]Qrpp'1=iذa|Ա ǣ%qè*իǗ{D}C=t/%%Xy% $|\ϻL^+(CꡨYYYȻ6Lr rrrXlL;A(Yx <xs$M/#X[Qxo~G":6V-Ϸp#jjxF=P @gMysK#*2 ]lY6r~9f$**VKK[ }Qqg5={umݺrFٌB="!.otGxt8X[#e6mBnn.566"p<6%Mtt4xm<==!Hxt6n6-FFF|'k[|OqꖔWC`5Ȫ ?[0d$R.zz ?o|O\z|$4NvyXZZO[;j v B=z4N@iT}0tml|5*ۇ_((/[3vv6#Vy:}}}%}HSsum_jp9Ʀغm+[7IЇ;x! 66G@DD\#([\~rd!{kWŖ-d-N% M8'/Md EZz-*Ӱ'Ru~ĺĩ#_sڃc?g1p?_EZfUVI 6chjl”S>{" ,ɶ!;_}pym1NNP%XF,?c Np. n ٜGjz*J)ef-bmjbVbX%04Pn~• m=g2Π[XT`հa!;l,k;a&BdI @~z>d}]}e]R $0lKq6,z5 767r'5 m-mbĀpԌT#G`СlqtQX6C&bҸI-&Y|͛oWYײ`1ǏgOMM}ZَӾTv*7 C +^{!kT]o|\`6hW#PH`i-o#**gmߵ1HOddT)AHS=SLp 6 S66c߾}H:ߟ@DXjb8r{=|bhjbcȱpttd*|ptqdt.x=Y$xG$$$@Y&[m066fCp%06|f{8u8tbw ͟lK@_.cqJJ8F2y\}CG\/UT  31\.gy¢e دcYN / ,\tUl;5w^B4^SWlD4Ž”צǾ9ƳOz.Al9XH?O=Q/ǂڈ>i^llo_-! &&&,Ϣ?qXr-lm1|p889nlG*Ȳ%CD,zgI $"ex$|s8eHJLbϼoڶ ^qpr[v Q3S3,!%; f-@aa!{&5yUKlOOqQ4ļ0`oK!Mf Y%>t$:p{ l xlGTQczFoy1Xf BBBx̙3u)QC*)boT*i/333t`͢@y1=B4B4B4B4y9kfPNG  IHDR sRGBgAMA a*IDATx^mLSW?CyCk|AT2eb%9̌_̍}L)&K_3qx)"b$0DJI)](A)P/!2qP 6PL4X/>>QQQ<듚/腄͍L4 āQ FVF5]xZ|-* HLNCaQ!>GK C۩ӧaxdG+^^ J9]))Ш5GK@m67‰':::ᄇcʕ<ԄX?lG^~,Y0@My f̝7Ъjt+0sLvx{%%%R6w1cG/]W^edU} `=Ll߹='LM왳Ynɓ'sN]ih~،Y/ς6Si̼@bѣ ϖcݺupGg鞉Vֿ #lȲ[gFQ(*.e֜WE mmm,7]5OB !'UHJ`H "wD de,Nmأvv 5}t>bN۷GL6 7ndKRE{Jhmm޽{y6W'pyB4&d3IENDB` :;T^ Dҹ:-bO_w|'5=`j"9zRpP0**CQE[o`Ҽ<`ѿc})ik;ߟF)xY{$`tjjkV^٣ )K'Npj)[YYߟF ѕ]E߰4RPaII $)M3tA:'?OOO:ZɯysUWUsח塴2bG ෧!'7Oo7̟UuM5""#P\VY\ФgSN!)5)'NBqQ1޻Or$,׃tLl nV9gOރ$ư;aÂ:Zcz$;ؙ ܈3G~ݒ%alܴii8I|5\Ize[8z(BőQ0+#80-004~}Iwq'~/~WpՊ?> A035CB\ןCzOQpos"'0;vL y``v2UN.NpwƼQ#GW.\!ǞV!6puvV'g.3n8|8a"-QrdLM&JK0f 2R2t]]\\(bq˝PNG  IHDR֑sRGBgAMA anIDATx^{LTW/Rׅŀqe J]WmҦ5h&ZF)hc\ +Ek,%<pZtaLyg`)0f`ǣ,92;s2sﹿ9w8=sx8908΁q's`2    6 !"#$%&'()*+,-./01234579:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]_`abcdefghijklmnopqrstuvwxyz{|}~ѣa{nMUTXㄑE}vlXEQ[Wˢٴa,yX㹆Eh lQWW+VX|9k^LL N>"%''#44ECǏDVV;Z,>|NNNz2l}g6q 'nH$8{,'W-n&>ԫ~LO rr#gif)O8)z=\ATؒ8 &@өA짱AC{ʏn@^Q`bl_ǻ~XB8r^k썀+~Cy_!"E [Ct5/qsSs^YЀQ(\ܠT+QbrYvXUU+ȃB@SSnܸ5 l8\~6U ԝjZ`o_T|I2ɶj;nvfD?k0ٳgƾ8mN44hnT*.^+WҸ_ӏy _FpG}}=ÏxOoDqq(#VӃfI$Μ> :Ik⯫Z l6>'j9ܚMdd$M3ӓbѸqQ(u[nNcfZ˖-þ=C,ϏXR(HIIyZ-}sq!7]GhxuhPjSeBqOy b.aزm ***M&Huo L&:uHF .{ߣ."825ф[c;88H &[" 2)(( `r-)-/%, b00}ʿEEn~l"П|Y%1"`~Y>яYl$ iqѣGdhpFtDHD蔴f ) z\/6& &>mE AnQVXFdedޯ%?tU|[-iܭK&3)-a[|okd,TPe \֧h``h|S ~mc0Zz* =[[JWn&x9%>*:\z2X*)tX$ȒxЮ׋Nndddx@qq1-=ȢS{ϼ@wc۶m,^cc#Xp} Ø/o|f @T"??s:{V @E4j*hOa׮]عs'GL>Νu{O{9R"L!Lho8o8908΁q ptIENDB`y3l qlq @Ӂ %' r 0ùy[?ZiiE XZZb̙t]|ՌFSP޸~:n^IKPv >!ٛ7orfRS'eUe܈@lDuE5}]K?FV0dm.4k 󫭵 VZu0̘P[1yN| ģ ^544 !!F@iiI0 EEEضm._ фlrpzVٹ %Bֆ@An2𿅨ǧ{?GsP.U/;P*lUUU~:ҲRk!ʐ4ᰚY(Z{6foMMXH)bcbҌ 088u8{n XPƙ3g>|||h`$9F*ƫr9H:>z?aCXDnQoW eI;demIdBKk 6Dd$هp5al;rr! ":&c7c2Zl`o?I\o=71&K2 ƺWjJ+ l6F˗i> u|ׯ%N]cǎ!888 CMyyyp>IǒDK%c-q(ppZ>͡oJKIʭ[薸FFs4ܶ6Np/^l\WW<#ǨRWЩuKH6Ks߯EZZiSoo/IǓXH9roث4IKc:u QQQ$=Xz)b,*k*#~+q9M-5NG7n%NFOTyԄ'O,͛7i{.֬YCلV޽{k.Zg#IRɄ;w@&ϟ#6.= ߔZ&'TK$ೊggiujNY$yyܘ}S*܍k7_[j$ z*W5OC܍78i.G]rN-I@+(( `IyZ\󅒀$)<l`QJ\{Q r6OF3Ʈ `~TtwusW]5y[Ϗϟn1ްvEpE"|۠ ߿RRRe0%NfYYY( ]i @Z"###8q6mDK =zsB#,,̏Mr&ݻwol>vh„%BnJ`U*ƫ\]}}}dbP$qW"fcü!or={F`I@FT֭[7Y*FV$I|<.@tYBPר@ Sυd&#j8Cl%}-8U^}Jr+j_( P׀Sp;6FFk%K;^to40uHY Fسw[3>k`jzj|a1⧅жhfLLM 7 Lf+/*CxH8)K> #FbΝz2k1['pO4N]'""#psXz5=ŒW arla _f|0Icxжid̗_| ހq[CעþOҍXY,*+* .hyaì` 0+fJG}IIENDB`H4B6[vϒ31,}$ܚ?4OY=CII a5ԊJ"N緺$66)іt1"Sn:;r a] ̚: AaAԆ ;K@ޤɘQQ/anb޴v 'dHbI I00256_3a04f2fd034c68b8**8 256_2f840d061f1c8b18*^m256_6711f4ad5df6f3ac*(3] 256_f166377bbc662836*7~ ݚ<3|(PNG  IHDR#$sRGBgAMA a `IDATx^ PGu!wH)'U4&X,S1^ #*>x%p4SsT '`(.fz{Eaڐ";=33_OϷz$C @@@#8=FQN0%0LM0t S+Rt1b1SLUXՅK\&gJ;ajjp[AǷ&MStpc;vN}~;ǂNnw,2FCƵ ;~) އϔvdIe8S*RAx0%$"g3WӮD n:lZ!-5 '$Xlh˔v#*:);],ά,d ˋY axxx0K3?=ʬg ehsϤ)Bwz@?Ξ? =~x\/9;遖o{&!\|׬q& ُ{%%%7|5==prr7'28{,Etx0݆G bK?|y6ʫӛ=U`둜*tˡCRq92C9eIHfpm_`p \I )S'F` u+U;ܧQ=`4Fdt$B⫈T( x`pssCPP֯_^ZR^,'7i:-;1@興yeD="PƏp`6 rM M!231j:OpÇͧDucQ_XWƶԄKw7wySnz" zK$bۮm"_1z*&LYvN0P (,^^Ho}K鋝;щp$'%t˒%K]#﬎͛և?yHNI^ l^^5ѬlFLL =wmckDPZY耏_~ym>rVZJ #t-NxMɘz1|Tfhy40,x&&&/ 6bjKbɬyQX2ՉJ~ltވYsf|9DF"(X`2%~M[s[= _?_VTbpR]HT|~sDBHPV:6mq15zژp10) #>>3glT{æ͛7xŋIz'k. :kUa&b͚5h˗/0#ؼj}8w*)^2+V ˉD"ZO?w//Tfp^D]]T[h$_TTիW3BiDEe.&c׏Qfă`gc{{{nuBsegMuQS]]ͬA4m4Okk P4Q Oc˶-n6Fx%b9XpЭn2ōMuҼlSa(#i9CeM%~H] 8:CSd2yRSSC󪪫H~A><EGj_Y]I ELjp&n"r"Hh:5ͥ֓Y t>-C]OJ9B29|r|YEZnZ[I{ޠ5 u6\FzΝ;pbz]~*p^FzSF%GQkh]FB(ߖܼ\VnIG޻Ki{}VѾ202D H4XJ) $))D٧$D*gd[0a@O9;iw`8yL0`ojhsɏrpArg򿴚1cM,W?׌FFL612͋~ŨQq >; 5CCC’@?c #cggk2tpsc޼yXjS****+W2,nBff&SaccgggÇU,&kPNG  IHDRa2sRGBgAMA aIDATx^{LTW/aq>14FknMcCbM&yXTuqjnT| *2PV]#[*.(10p\Ps>̜;{s .$INU\Kd$'& $91Y$ɉ INLIrb#zPBADo}IǓjnZX,""tVȌ}sfAǁ"?ш4w>u,"j*ȹٳ"ɈNJÇEd۷yطrJdffQ^^oooqdddF`„ )m \]]{m yD,:\P͸r EUr@!Ŋ(Lc:?tͨ*~Kd\lFk˱x;x'SNחOj;c:;;%j ?*ƾ} zw4\hxmaaa-EL\ |>S=z7 ۱'LQZ\ znN_kϟ$5{^-AuMU 3h>Ӈ~:8~fsQS/څ*|ϧQ_]uYgCV@ჇQX fLJ7ϩ;cx""E@}^m7rpehq"^{S9Ŵ-}(_urR2@Nl2R.ʿ65<.E1mfjĽCq14n67L6dʂ\ ] ,4w~s7ΡEu(SYY>m!.6+LJQdy? F(++CDD^0T{nL> c -֦Vg.\ _{ hyTq*;UUغu+pxz鳧Z]-"C#q)jk츣m?:^z3qRX}Ķ] BBPTR%uQ בI?C?j~$?zJ_SJLLMTm*.+}]rN$WW:&Jkhl _jmI9]K7u=t,?YYY> uihㆍ$3} K[~ rlHRF d2Hμ),VK׆|ao]3ۓ/FGSSS@9v.h6o,ӣ q9L2U`hOC)fw ege՜H-KU*6WX,tGsC#>:ce ;q"?VqH`G4qDwq1P=!$8l I)S&O5`tD 0|,Yb ; p5~ l2~c8E^^? 2PEEE¬YDqrssq} \R>{%%%HKK?$'oӣg@$'& $91Y$ɉ INLIrZ4eIENDB`@@'l׀ s:ĜNolxÿJNNΘG2sLlذ) %#,1c Ƙ{IENDB`رc,/k,?_@ah?Z0C8|?QP!=Z/YF?~̵Dyy. ggg|1ElʕXx1$IR8x[mdǵk EWկvL놛ܚHjkkDӺtfm6 pyA"HId4 Efy0|pВ&dDE6g4TISf@rhr%5///߰FiFAIl-r;8}AL~-lصk$}MOcF(\&5q˚;AV{<̢k;,\AlPx^fzSIQ^Q赝ŤK>|B|degGjxyCySE 2 %8 pƲ"T%WKSSa H# cݔA&"[Z0M0m`3C(V ~g@jf*Q; >+Fv|؄UWAR m&?777\˰x Xzzz)|u<²]wES[=Z|(.*Fk[+֮[Y@޽şcyF^/<ЩD́bD#;@^dl9fp"±$d>VXAzt=ZzK-Ō3 O򇇇x}xƜYs3Æ%-ܹs1p- u ߏ`HˤXj5\]\ kh@XXwvv7l}E[m]-Զ daHD{%&&ހ6]~~>h4dǰ7*+//i16c3cX`DNuttXԴZ-pƍC'FJO&A|qS744FmHb۷oKS2][a 0c aظ(J|q xxӑɣipaӑ!#ti(C/)9FClݢP"n,`|upi?jyȅMwlGPPII.s4\Rh44.))̗@{8g=>Uۊx׻S(4;`)NۭEΩ>EG}>q"J\ɓHG:uj1ӠY6 wFS)/CeiJ], X#C=8w}///D!~bcc!p w{j5G].v!|^ՍQHLLħI"=; ?BWhsR3" eݻ]v3rc2#o 8磈c$nnؽg7 !#dqZ[/z?!yA"{dA|cbb>yϞ9h>;}pB )))i~vYv^6CP"@[>9 +WcʪJZJΦ-9<+Z-cn>&_8$ldlo-Kr4hd d}:uuۦ0䜡iP9\&M% 9 ]iӦd `#cF(idG֗Y^>R߹u'79k<_:tB>ƭ[IoyƸU6yg5c¤Ⱥ2f1?[ߧCJv\tF/22M⋥ 6hF l2 L>dß9 l6 80vp0%q`,0c aK 㰀xDk) IENDB`fwJYPNG  IHDRsRGBgAMA aIDATx^mPSWy7T^fq:[ʂ۝vFt_Щ3;v?otASE?@b+  $${ɁI%$_s9<$D8AH9a]k1ؽ{7bbbHHL<B-pryl߾kybcc-fh͛eQXXdͰ[aX1&tzzz[W. ) նt%V^ U QDDDE%Eh 'Gnl܀_1(0&2zÇO~<0 Ӳ@jiNjXǬhنèeiKv :R0u.9HLHD*IkmXEBBb h(T{#ߏL!3#3dh1+@6ldSŵk׸M0~.C#Չ@هeHLIDl@Fdfe"mcj 5- n@D||<1th=x xPB{A08u>&\esw"0w=,/,\NP0_ٳg_i7FQl\@^Muu5tvvJ\ !'ЙaY&XX,V ]8o Y0P[W=N83g͟q-|p9w:jEۏm\xU{wuyt9pw1bAWWQR%ZW^E}m=J/ڔK}N'fŋS;ʡoԄo'III(//Gթ*|#~԰Ƕmۦ?Cg^%ks͍}rEU%&z ͎:-I c'|2~ks'QΠo' Ns3.agQQPF)]v҂( Sdt[CI>r. 2UfID$$fwJN&Sv4;$ ӼD]Av8򌌫n-fI3i{n/םnn@AA|Ϙr7 lٲŭG#xf~JwOz9|=ǸV:tɵkY!EƄE`?nMݛ,HϗGΘIFfguuoL&3o2Nb@ocxhgu(5"#">f`CeJE$rܾy5_;Yz[5q?{90sO[.}O=ve;H%Npc]Dv9lrFӸesNAj,I~zN*L8l٫LNJƪU@R#d&ӆN[ѤL?i1j; k=F= dv혺ʞtTaA!J`#ue=)t :;[;J߆p<9tEƢ@UW7W3 #+\1=n\5kYC\z ݎ-[pŴdgecdH,\+cܸq~:OOOh4n256_8f66ff6d29d1d491* 256_a51bcff70b036ce8*,256_2b9643ab2fab1e75*-0256_92423a5049de5fc(cT )      !"#$%&'(*+,-./123456789:;<=>?@ABCDEFGHIJKLMNPQRSTUVWXYZ[\]^_`abdefghijklmnopqrstuvwxyz{|}~={`ѢExbZΝ \1=rrrVb X(//qTVV"::iIIIL&ŋ;0_oVVVYZ@`,b@ dpAdTUڵvTTW+K_ TIy>" qosepj'm-uG+O|U>"ԄTx~+466"<<[cI+ J^ 0k,ܺy v߀*mo!d[\l$Hx_xyxqeuFDds.`츱L;}4rX1 ߇M-Mxmk^׉0 sc:J%-jm˕#cۺmXwnĜx1 @ѝ"qەQTV<& PVà3iiO6Feepp ɪd6;KskvZGYYlآq1q!HMONC|9.aI(UQ?r>lܾ8fJ_ | S.ro07s"tE(Jĩ2u  ^ H`-29\b:k vrL.ǪUpgqyȬd Pǡ7qZ"\摃;ht%#pޫ*[v0{5 NWس2[mZI'Es]3 uH@ض0%˗Ս(*9~k׬=ٷνLގӇ9>jgNڞIpwuYe˰/W 8 ;}ZϢ>cN2c (`jnr< c՞*YY06Y#+*ۍ$f_=Wȡ斆ECI<)']w:NnAFTF I $IHғSCx9ش=Qjka+hi̜9+)k"ՕItwN#05M.Xp'dz$N|:SzB*A#3.F}I?-%٦| )O?a愙2>iI?- em)i)2Kjtx~64 ΖՕ —K~Nߟ[y7Oe\9)22:NI"Tjohgھ"GJdI=ˋGHJRƇ7|í3vX^rԩSҕ+RM"t1"rssY{{@ZV%e%^^ntEJzOtttenu^ڵ{T]Sz=NUMQ`)!92m4^z@ҏ!7N9-:Qɲe1oX}[[[;99կ E"Elٜ cnʾ3fC391 3=NPy ;#"N40YgGg?]\04+yzSM_Mep>< 2W6axo"omhhX#`/GOJ_́<)?gN6$}pI]fY3|n Ž-;a$?A3XCŅjvE8`BwT؎;>H\hH+j{&Lz8pЅѣ;̕B` }GBqMTTT #,,3 o>.} 7}}NO kw90EP `@` X0p#@` X0 _@M\IENDB`o&ykf6 d2S¶x/oc8̻ .S0x1®]p$H$HII,p8h*dőɡO55:ako>wfi|}%PNG  IHDR$f8sRGBgAMA a'IDATx^_PSW/GE BӵZVinu:;avp8;Sa׊A-v`HDIs8ѐظ}2wr'so{~s$!#ygB@@@@@Ӏ%#z! 0@8f2~Y!J¹s/JvbVg%:F7n%jDGG#**JՊDQu`3EۡE]˟nԡIďº01>ZTTCрbM.^/%-1a'yC|1s]GPCY-_QQ Ĥi={Эy"""V@o#y s%|.\n[T[zj}P v]v tʙJʰDvl]ӏlR)/cK+WΎN(@EE_304^R`(?[+-x0̙'0Mor5FG`ۍ v:m6}P v}vAon-/nY _&>1 ^T(v㐕!e &L BKK ^ x0'hpddnX~"U92< GhX(トDEG!,$ cL$?( @r 0>>SNy =(g0pi}!,,LDsk@1Bۡ@[.4Ylss ŚSfHN6j+"ۨ t E 5~%K'kD~yfݿ['Jwjw;W܋U"k8J|(q0f@jj*6o%R(**si'WfIV9Roo:v옘s?'Os󫮮SDdz=mrrR:/5669 t"e߇%>,o wPWW/7Lj͛7140ėw-7C3F0_ݤ1! ѕ,J)+, (WRJF <گkQg??TިZu_~\ |Z).^ Yg HJLBZQu ^_  &K^t] GʆvQ - V#(=]v__-!;x!*< 1Q1uT*R1 {&[n,Yo>?v9h%22R̒u(\ k7 &&~ ?*Bt\4^ϕݰg>?TػwluT* (!166vmaZ{~F5vrmϦMD\UŊHSᕗ_񾸸%n ދno<0:^{ P@wڬºu8_odO06>nr[MS)t}`] M Pȏh4X~-h0"9>oIӄKVd3?>[Įdk?N_/ͷ߱hoT ;Ed+ք4eZA7gxrY,Y-"A@$PTyIX,s}-DFDbMLII2NyԴTxznss1wc?EII o+6pbg"JKKmbYGu?|!8 "~ XQj;$JSs;wt3!x0Jx0Jx0Jx0Jx,࿼fFIENDB`F,"-C)B<)GeeYpթt6ZkwWuue7 񧼼< [KΟ?$=,0`/ J3=p""" *2 30 ݸqν`'N`S~:lذGr-ؿ?w9-w)!A !AlQNC$̖W gBhTJ*v4.mp Oٗ3G`?=bcpdRiO;1{|s@GG@dd$רq>K qMxˊ|P+ NPNG  IHDRa2sRGBgAMA aPIDATx^oPǿx'bZ_D;Ɍyc:M5ѩdbvbjP$*IKcJP=@nPoj2)9(p 8 㶻 !rgg{۽{/YƷ@ c?F8@ c4 X.ŵk ߦ9A"ezNtτn˸!MMFנÕϯp5{ri蜗3 ~x RI, Wυ hjf9B<Weǎ={XV:x黑Nn7WEדzX> h5⥘p8!>s-^d.Wσptπx2?SX eYg~ >'2N@ۤEy-`߾}#a[`]2q(^CmvN$;+:0ڊlYfW7 0;ڧֲS={@.s 9Po%4Ϝ9Hl1(RTTDs *ѣG%MMk.n:\TRD223Hn^.yOA]-+#R|IB€#9얶夤G€0€at2a$fg Is*RC*HUiilj5|:c]-L}/+Wߝ0XwnT$)縷C)/$df!S:bŚL5mT>VhotJ[5fg[%96IFV[7`6wY S9>U"M27fY܂\FJq;^t`)ohhX I&]!?n98xd4fgۥd[ MOpl&-vGaHlfn_dr& ;DjXlMf`f˗C.n,xikנ: !it|D|PD" *Ō͎dz?*((@CCФjWINN W֭[Rd6(J466폁Z-nܸayY 116m!T c@ c?F8@ c;ŒSIENDB`4D3;PNG  IHDR sRGBgAMA aIDATx^[LTG?(jDM>T>H+i1&|0mIT)rWlbSbPE\TTVXj1VE4ԠT@#xᶻsAve*G&;̜=9s6LB"يGBQ D(`Q0J(%B! F @YNl "R8:$ߨ:A [[鮁.-OqBs666E,]yV]EzF:ll-Z\" 9X)ҥKADjٓ'ODfGD$j+))a"`Q{{z=F)!XwW7v//2%B&(FB\択>w,O७ IIGwy*IC 塻aaa?#;g}6jjD缨cΞ9? Axx8N uN_;>xuP~ADppp@ZZ/f΂OYM+_q w%%%HLLD@`.'?ٹ2?hNJ+6h}^ҢR8,Z>tA݃: ۃ epTsO>^t`/z_0OOO?<< #P>=.PNG  IHDR%d7WsRGBgAMA a IDATx^ PW H 7RWJ.!*kV1YjU0U2+" 1&x%D.A 0\"8o'2aPazekf0JI0ba+ X`% (1VF0JQb0caBae *l6rO iF>[~jR_WjjvX[[#b< WWl܂Gዝ_ 44;t}gMMxbbbm߷qrDHIFcc#'ZUԊPXRĐD|k~ۡBX*WE3 HHǙgd儚IxB,?=RS^o(DGGiS?1ғq+>Z#] Fפed@2T3\Mʯ;tghkkcU?H=jps<*}4 ̐m 8D_V4EɌτr7~SjlwdT$**<'q/~-aaaĝ;4{!i&KWGc !LLO=q92yUiou0eLפ 'O3Q?=z4̭͡>LR뿫oЌZ%&Wa46>cKc88 *& lsZEh^4ԼD0s4S1v u9\`܌qPPjtćEQ>l+dEߺ4t,VKK B};za?v`o<ԣ^$,BVvV?Z\^,y|]vA5@Eu u%߸3uUW05@Jp y-ע* 7Kq(o!j2{l` ---ɇNS[rJs dGss3\B#itM y{{ M MŰ2' S//0Mꌻdggc֬Y4MEOFE^ܱe`سgBb)^5wGW1cڗk8 .X˗/mޒyUBQZ%?6yP&*W~b_fw/^|O<&ٛ=wdbhrMWKb 9I 1c =x}, Fo5 ©ӧZL7d3,QFYL>5VÈ@pݺ"~:i&gD__mGWGBnAH~V> @T?!Ʀffv̠G[nٽ{7111Y't+BTTJlB{@G<%\LL@a`"nn$%+N{{%#99r%x"IBLMM \aV63{XD3ә $2,L@‰AL{edd@пuL^jzf:22h69Aw43x%$$...4#www!H,}ǰeG=gaa˲}v66643qcJ,--H+*.~jUJo7=cn9**,fff]A?2ܸ[#$?o 5p_.ח_5oֺELj ~U]Tjvvv}/#m#aimI#FõCo`c256_5fb06c1cb962dd5c*256_c7f3f2660e1fed85*256_3945eeac5447da46* 256_c9275893a1292c14*5136b G彉PNG  IHDREMsRGBgAMA a6IDATx^[PSW X4]0XzÈSu>v:cSqZ\0m1n!"G$ !I";ks99ko~8O g1>>R ???ܱYPi'tS(vŴ7GGGbbbrc4܌ÇHKKc穬ıcǘ~g)ñbhhzntuh5tC_o4 :U0 8FFGPٙ7p86fMhhhw~`Bӌ uuuɐVe+Mh{چr@Dζ!gEK6&l2/^HCn|kHDz?&q+.,F||<!DY #"<6nڏvK׮]CTT2wiCI.LMMQynn ˙fIޡIֽp"(++ǩRՅիWSaD"AJJ i&yH!33i V$7X xF@LJg?3vn4ǜ19FEDcc#FFF9+yǙYYYLիW4SNaP;GՈ 0S wӶ _k 66!zǴ'O@*2 Y{ǩő#GĉPԈrrWxuxtw h]FG&h !ؿo?4:Nd#H_pW!vI4qc:|i8TZ ӰyfDlAFz{K}&8qCBBfc޽LNu'&aaa,7T7>,O}i8;U%Yp,lN)O2IENDB` ]^?V ]UGHdm__z,'i4`e=Ec$8Nv{ߣ=0Jc:XჀ.]+0o 7IR;w.?~L#i 9s`eeE3̙3QQQA#i 74i$[|B 7ɓ4bz&L|"##q}= x{{HUӟܗ+Z$''4ܱd`F(1VF0JQb0ca?\6 H(IENDB`ؚ/4O?4_i G&@?~`o}[4{﷦M6}MLQˀ}}Lѻ?~ltQˀW^a11,2*U\`wfwb 4z]|eѻٺu}X~Q>k'Ffj }0vtS}^`]. 4T7H_n1f.ͰHS$du PNG  IHDR'ଖ\sRGBgAMA aIDATx^ L36@x+L+%V%j&mZ3̤tAER a`Qg4L/`bb+ JP +aҀa{_Bo px91<@ƘI2c& c& c& c&lҒR(?{4=vJY3:} 4cĤO) 100@I2F/H#㓗'z{{)7^0f¸9aC?[^VРPDŽ 7e˴1 lܸj?sޏP!>{އBЦ شy/Èѭϝ/~mz˗/CR\> RbpSgΜ4n9K3/}vYҋIOo+|$>Cpp0,--iFC*CC"jw{8uN8xDTUUg6 \&1r#~hI Ihӫ 8 D‘ ӧ )"N'Jno-OS>W_ßn~%?GoͼEE&JKKE|RP5hvXnn4l暀$! +]N<\=C;b`&8,[}{!p] >Y|0$I:EPVQ4tvuf,rYYZi"EO NNpw-o.yQ2,5~a;{;D_-lmoa#4K];vQ0<~8vi'2?DnN.4gu̝9if6s_ސ?^h X׊i0<<\{?XaaateggV\m۶QuiYYYft[[[J򌏏45e᧦0.0.0.,cE܏IENDB`X k(54& >,<f-[Dȿ"?#'KPpIgn"z7cB~ aYYSI`ggNj?@ABCDEFGHIJKLMNOPQSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxz{|}~?Νa;LB"Y ! D @Q D(`Q0J(%B! F @Q D(`Q0J(%B! f~(590j9vxtࣰ#滞qZUUUrilUNNNr|wAJr Fi٣'xt#ͧ$Q#G!@T*9Bۮp*\\\^ y4pӸɑqi61޽{1riY팥KH3 -cr0fbr鄇x0111l֭rlٲery9B!팡̀L]\%Bډ C.$`Ç>rni }lYuU~ԴPX\ٳ۹dm{Ɖ3'yfh֭[4ha+1o/׋e}!OA^^N9y'L+I3nLyS|G\R0ŷl̙M{6ո9j(!PLjbۣؓXx\k!x2n?î0~xX[[˭uk Eހ %%E: !/|i>^o/_'''c O\GRjzewqe⵲XjiGG5Y<=1fc,YD^ޞWϑ#ͣ/`hP?;pn8v^Xi lmmEG?u) 99()+-?v*;Q/-G7Q/[k5<=p>wKBUK@˲j,|{뒔 0TV`MD6=_{SحWًsl1E. w;lm|zHR㥾Y<i㦉t}=n\l.M#h,m96وaeivJ+W'Wdh3ꑐPQ,\ 60Wx޶{OyE7ʻw1dGIQ45]U̙3n:isXj%tz222ӽ+AHMJ{ 遐gCw4{e-bcck$XZg'/^)]L+c=P[1vXX0Ye8&IM@jSn[rޔ*䧅F xށΝ+ҞkpUxyzҔ#MIS$mFϪ.G>=D0VE7A Lz:uTj8g=O^|ּG XG͇J5f(kװrJ{:8@4/ܨk̹34X0۶mѣGZ b 9ZPb8P=`-Q #؜gIc>e:c'3e[^gi~)f%%1ibRςDE,P?fNcUkY Z]:wkkЏ Ft:N}Ǣ>b,>{wHyG^~O}ԩS h7Ø.['G<|pP߲k׮zYXDvr<|$oY:_ދb c<sqqͬ>\]][Ե)r,BY7. ?#pR;!3EEE+iWp+^}O7`!Uݽ^X炦Ȏ#4b*]k,̬L\G;ʬ^̛-r}$Ϙnz1$oWk(.Bdt;MoiU~PώܬPܹs>VյC}oq>j]˒%bڄiȺe:\m(U۸q#m7ٕہ3N8QG}1o<8;- gSΚ/%"h<񀘟ts9sPec~3O<?KzF:F0 ?7٣3v)8&P€N.?+Mㅯ7iog/ֻmٲE\_ֆA@@4()w+G܉8<=oT'N7v*Gǯzɑ{cpqmMRzΐ@O… wG'ӺG-bz\Thf\7ZPPNG  IHDR0퍳sRGBgAMA aIDATx^u 4#MHFhW5X.Rhp$\O04!(0" FD(#P`D BQ(0" FD( x*Tew`THk ?I"(#P`d2{A~eܨP)u=zT+T+UQ۳Yaa~%kQ<aj#8xM~[z2ϥvxW"7%Ŕ.h]ۺ+eWJ{;~=i%چzVw]0F"AgJ?nd۰Cϻ\&?Dl6=E~]) m)r\㬽jYgo kz41G-Is/$HZkdv3.l:fp)89|rKTbYJ3bPYc ~% Џw n6?ƈzVl8zI_] bf`/[0]=}F+ڑxK6>lV`[f `𡝡n ZXJ{jlSd nv'6:r̹>Ѓ_ <CXX7#`x֞SdƠ$%p$$YMr#i)m 9_Snq8KS'((FFclpF ]͚\?ole` aa4]` c a4%0FzZv1IENDB`CBQ(0" FD(#P`D>_IENDB`&HSԿ؆5f >3OB/GЛrvf^{isrKiaBL;]Nni 8|0Vj8|$ԇNþ}0l09b#,,+~aʔ)Xzi>m&:ܗ4/~mMw6[WߘhDii\kZoKeI D(`Q0J(%B! F @Q D(`Q0J(%B! F @Q DF;&uAIENDB`?.(+ǗZ_RA՞s<T6Hy@TW.֙/r3&16!VT022b__aņ֓Wl{ڡꀻwWXq"vpAV3ٳgph{#bAmu-KnR ;vYlH?)tuukK@7m&1\+Yj!lUrP(p3e.uyTUWAIY |w_ݡ75?fX$'t:߿B=}x"~PVTÏwK /d! V 8R@s_!asBWrE_ȑ#pInٗ!,_`BFѣ_ zq!IxJUp'.{ɞĊcs1v&⓿}|-~O󗸦bbCLT= bN(+. h:==6͑bE?nc&8p5* %lWFrOƀL<88[l)޺;! ĝ3?}v<544@4غe{`?bKo=/c+lvN6Ǎ l,D"NT*,bKJyP—\=Yr0?9k5ID#˗@ff`Y)T_xyl vKgO{bϭes$9,gsssM^Uxy@|3P(eM&B[tT.HRR$ }G<, li.?w}F;ṿா0٤+Wܕ?|p3yRq!Xf fd!TMM f%&&¾}0] @H[qSBĨĨĨ~#Y IENDB`1Knu7@( 4[PNG  IHDR9sRGBgAMA aSIDATx^{PT/.QuTf OI i*BQQ#vb$*3N0`y @ ay( {9Y^vٸszϽs EQFɔ)2BP-eh(#F E1Z(ʈ@ۓ6\J1ь‰dԕ&&&຃[7xg;$3Z5֐Hs D p &$=$ҿBN @Yirښd&@ozdH'Hݍ7~z8::fZ[[؈;vH9sD* nnn$3!((ϟ'5o XL$U@pqvvv$3O+L[[ [@@iMǴHsR%TFZ":ʀs)"ф2 5Չ'HK;W\aH4=zK!Z&G *%Bd CbB"J%Ou]5BB>YGym9TV H(Rũ$3=yhmkjDpYtuvA!WɓՆK@wj!@dt$AK<|$C{!$D@*ƱP{oO]w_FpX0nUBo0"Px)))H8Y 9<==C>E?VX$ p<Zl޼)Ύθ~ //`VH[h6wnPknjQͽ3)7U7|"r?BD|%K #޺`&0sr%+ w]PQ @H<ؿƢ ߃>e+CoW/j ^}Yh1::-)CrEqN1l\d/@My \]_`˖-lM0X>5=n֖P%9$~a=棿 O=҂-oCJX@ajHBN^5f ""q3&6{lFTLD"tɻ0<<~j;#aLe.ܮޡ^X v1ct˺+W\Z 7g38vyAd t=AkXYT.E@@q yb$ WUV@rz h%bO6bnH"ksmKmj͍?춎  #<6/BxmpW3HD_O x8g+g4I>`TK%zp=Bd*@,*N:Yr\eH@.zsZ%5;N'wk",< Asa_~ Ĩ\/Ӌ?oJ[%lg Ǜ|w/f1Y.+{b^ݎdAh9)@O?&}R鍧=6{OCC8(-g?#3Mfee롗CLZzT)SPҘG2Ǐg-R>kL~_=|9f6Ӏoߞv mi: 8azhvs1 %M3s2wI4;]LߩgØE7HaBCCIkzCy{{k+a.0=\繧.+!ֶ 87*mpI{!C{_SQ\ߜƐbh [f6/(;Axd砲lN.((ڵkl21\wŋOp?g`ccC2g|x߾}Xh?sa#|gg'v5|jߧ6mo/..FII $իWm6,\dtcg~X$R]n:ܹD52@PMʹ@7 E1z-eh(#F E1Z(ʈ@QF2ZZYuYeIENDB`SAw;vZ^no{gxb$D&T/NHaZִZ7Sq2HI88˧5엓h2M(+&*¹ێS@xI:x-H\=+}sVM5$Q,$,grm ÌcRh6pUΏ9acF3Qh-ҩO5Вct9ri4ŭ֤F-<-H%mQ+E.%LǠ 5mfz 'q r}>jV6v%O0gҀ7(ek˫{}*Dh(%,k>uj:i(S#996X8#^B\Mln+? [ֵآ-rw3'=Aqu k=ʻx* #ۻX3dƤIE<My'm2ꚬK(c8nqڻO#?V"*/Ƞz_حј 59 Fe%]Ϫ0vPT%R]/U_ m4aanr9>srjm7Zona6sER@Prpz-. : ǘ1̈́UIq*EU|!PҚOk[STCaQ׬uK/`hhh{Pv /EoO[05θF48͆A4lٲ"͛iA@1wcǎI5z)63n '<bZi H23)(pK.JDnp㗁Q •K%"7$9N2 W':u@h>FQ @/ B-"\vv6u@[bT"r@s8hn@Q(XC" &HZD8up:A>1 @i@ͥ. p+WJDnpR`""Ab eee plw"upjDN Pr țD28@q XGrCiyC"3I dkR%&'()*456789:CDEFGHIJ'2PNG  IHDR0sRGBgAMA aIDATx^kPS?"S^>]gש3~Xwu>N]?vݱvntH ne 0P < $&D{sÄ9'{MN9]SP dMEňYCSjh  I*Қo=rrrh-xq@ x\A_@b3j16"|(rfD]B k49tttS4y'H Z+bL` 518a\̗6ac|LK~߽wg{Q 쾳ʔ =1wlgBq @nw*]ڊf9c5 ׯ]gclNh,^xwrd簠Ѭ"Z_777^3q_Ay SAQ}T"zG NY٨bHww<Ѓ&'߆Fjz*[q h4K/+%!kc\EE 7Lޤנ~_B{};l5F88j5&K̑CyI9oGoKɷ\ NhnnfJsda~ݼGE0[z|~_,\xTdo$#'/qsO|(YJVvˋ@CȈH dC@ Q(T$%%a\ȑ%1***&%O"53Mݷ>Dư;T `횵nNC,_y&/dw~Cl*彴4",$ >>;OTXl oo6tepuqex<}4'Zܜ EvC"#;Z!!OO=^[QRVʪJ:iK/ĥɇrFDDpI GdEK/ETL.Zdd"rj*k7g7f;(!u;9Pft8Z~ozu nS)U(--ei3G?<Λ7Env.RRdQ.W;OdddHjK֖-bUˀCC@t/84 yﳏ>c)h`2X3~wWwIT@ycU=oQvvvg]yK3qmAttF tv3"9~Xj(0$u`<`jQ P>Z :X7^J ui 37=uEpo բle"vI,yk@jplذK92k1 hk+~~X`춾u)_UB`i3o 7r!3`r"'¢,DpI Gjp*qwyֽz "7BXaPd P`;(r@`qH0vlK"mDz@y#XC9i&^qeZ!=z(/%#%5 ,eQYp_y )C= wy!M%iHMM%\!݉Kϙ*d(h,*̑P^I#/7Eq8/Yܼ\VP* 999(]ϣh@WF !reB|Fem%RyQ>/O/|~sxyyݘ< $R|e^(ܧW)̞T|eO {{\t --,쵃]]CBBt=:{큧'Gl;{;a3"M,5p;G;x{8dle*z'1/-]-l 6BPJy>^+5%\$~m6KYl(eĥzvV߲ިRiwtOs]eYpLFkxʑ]a-3ϰ+P۫Q\V n:;1ԓOvmϯK-e}FJw ưX&zkj+jjkX"yrT^l">|;wtH= x1l߾K92!@P#6ưR'濻|,چ }74dfXf~:bhÝK9bͼ޻x/sI`)ƒT!%`Ll(,4 :I"3 P`;$~@ARF\@WK"U%\ lg 쎊l +`\P5 P$#?; ,eA^M1{44Z@Ko8|bʳY;=ppI*'V .B0l*|?d?v۶o@X39LdJMw{7ݝ$#Vk$]OO<<=2E>>AZzT 0Ɂ6mĺn prvBqI1'<2 ns b~l) \<6m%A-kIPSQGGGll^K}qՕ()eputbl_[U {{{vmbg8iԡm/7@X }{g{Ҫ{7\\ hkjߏꕫH^֭[_|'v>pxٲeptBWGAp/tF/ fxjFll,k-m-?>BCBq$8?G[PNG  IHDRxt,~sRGBgAMA a$IDATx^흉S׽K @;hG$KNT)W]W_p[uq$mX-Y%Iþ 0 ;- n`` p>Vsg8=w~^gI-9kN-?9{nVtXytowHMM?ʙ8z(+ϕl9rD-= Y r6ۘ3S>{%=Z=7Vv>bbVѓn}>T8| .}s qk|>W kV#wbw7,߀T7O:}vsկ`0DÐC:_ *bɳĒ dee'ZBaaPPP a t~![!wϵԷVSS#-3{;OA;::rܹsG,-L4p'>S? =#g[l{Yy1jkPTP²B/]bcݸu3|wܹ{ii ?vXmVYw.7"@ں&tݴt֡|q>됕R|7(-+NJ)PP-~j~hiieee(.)[Dȿń q?~ &xph#2.¨ 1QQ'`ϱ2&Гi͆UhlmAlx,z  g~~PyW_uZTٳ8p+Aw}fu5ع3S-_wy ׮!4,a+|Х""2z}~&~yΟ?[2ӃڲNp^xp5a| 55_*M= o!5UX3,~s|زe QqپݺumOW#`3Or}VZk Mn4Ij؅'p -@ғHj)˘zdX2bvu5uLMYGˈ&|$NezgH煱1ݮ@hhnKș}o>bq^uҹ:jFaOrcsiar 8hn-&RMzNL&0DTgmg&@ss [i&@[['֦GQH'k9w?A=)FMJ˗3 6cbd@ />{[ݏԷ/">>^lLgg'{ꑛ95W~_5χ^t>K/$֞>3p☼p8@yPpYp,a,Vf 6ۨX\{opp +#`e9א?dٲDGGmxxf.q[7e{2鄾Ң׀{aeG#}=EOuQGwju?t9rXlLaab9K~1l6eVojlF9)WUWJS"t]:ۋ|ojnf7\ayyhnjFvV~Bh4egssY{I_T}J<MX%@uvQ&<'>|x~erTWձTGG# ؘ4"M-8|(ͭ 0YQVYrMfXGh$ؘh ɾT5v# z?@Nv>JJp WS[]+Ǭ05gP42e`LabF te(Sj˜ .-"kXݻ ^$l4XD CmC3LC&Gkg+֮[ _[!V yѰ7L/,.Oض{=oIAd [ASks-7v%J\|+GOhE[o;+Ɗ5gfz8S@1 ''G,= R_f8brssq!67o)nXbmʍ̯[z ֭[֭b==ׯ_ʕ+c׮]bÙ.{ g)ur8eo|]p<E0ͧXp;\p0Shb,Z ,v bG5`^n`l6#*j={oo5,ǎ7B#lل4r\]\x{-4f &)+АeHLL@qqZ188r"2L<g_*zf劥'កsO@Wkc4r'J[{'FgVE}} Z2/ܼ,!ؾB\(䢬ڊ= uM#m&P4R(Nሔ$3;N7ʏ_ĽDxd]3_׮^DpuGe8?^` &**~=:EHځPr>O&[PTi6)zkDD:jCDJay~R>Pꋔ嶽C:#c}s]TTa00+W 666\(lwٗUp@)#8UUHض*o::x`¦MD>cӖM7#]:>+A@L))),'y\7'dv)\g:?{t|ȝo>0{\ dqDGG5%((Q޶fAUq :6nq16/@LL::!'ﳅK&Z %-vDCfEn']qI~SQcΝb .aGp. gl8KL-o]۶M= -E-|\f#Am8 &A e9Ond12><㹔WU׉%Er"F :|p8>`O K)//gхAZpf* ~Oc/}$}\z mjȑ'+q&55;::F/޷EP?:p@~~>r#ĚEߚ: zVv:ǯ&j+lÆ%n_ ߃K.}}fJppvii Zͣd$`J_ݻwqi6РhRW^yϝ;Ç=Tgn ge__?]o߄'2O<88=IbɳQtd>=f@n0V/O@O@ IP@m∽`i^.S ӌf[[z]q Ej5ꟈKΖ2q-ւa-qumRy^ jwvkDII12҂&Üwl"琾injbOIWvͩ j JKp\VZ6ɵ./+eY :S(-#r̔ xP4RS'ŏ~#Kžp=g7/c'q Gz=_m,?r~H7V biz=緦.+pmm-~7Nddp1V.((F/+;2668 cFuU8uY;w 6G|>ωegf8;H+:;QDEY`4 ۇ:O@:3߳}92#['\X@RCn@]ΎNEP[eԄjduLt55bMr^p-ըkqsE Kt --lF^hHMKLzӖOpǦMcR,̇ul]>AChYm0al /!  `d{_c&s8`&y(*(߱YtK{Fn,7ƭ(.*TWĵט/4UbIjM:CX;҆Jq/P[gQ4{?~Qly 9~طk/.]0q?k[F"<<WFc^תgϞ}4wFヒQ(jj/d7;<S`X@Td4z8v(W?tnB)' Wz=6.\@̒ E1MɃMJJY}:&p_f : ]ZA 5B[2 ½{ʾ˕( \-&3ʄ:6qаP\\ V ]:063A 78u&7+V`3i'{qqq|##Â6oڌQXf}q}**%6oދ1)) Xv B{>$nN$O$]9*9E< o>ٷ4 ['sNZjTTTr:tsssڝD[n=2BbÙξPtZp8se^>8"AQ&/i  buDG`(@g.xbp\f%Y( Y`288o>;K/>E HT3/F>q+3(.Q믿۷B'6vy =~ӧvm6WC}CR~𡸕Ù?rpdr[YWʇi\T3R$N>RʍطsKϱtGpq G_|ÇŚRW׀_pFTT$+;bM{LYnxWC/n[RRJRlcc Μ9-88+c2sل"A |$ B{̻5U5B%` DnAѰX2a`h͐;[M ByZ>X  +;`LsXp&l,[6&>KK/|57oŸ>oۉ>Mڋ\[7_'{vk! Ђj-6oI^Go >{7oDP s]oy4.um~Wz]XZyݻ\dR|bw+**XI.Xŋϊ51ذa_|PnDAa؉Ym+ (8-0z҉XCGlQ,]TT!2: #m]\?9Y'99ygkq>2sQl/_b8d/>7tܿ_(/k󏳉A<IM.3gYʕ+k ٗR԰LfA||<֭S;A@:y5W8G\`*p<׹s8E g Y-!igX\q3 % (DGN۫[=?;wn['348μ? g( p0UDžhC  /~~^ǘx뭂J"jO3M F!@xD? @`D_z{ $<=u| o466>I O4]݇b4NÂFPzn† ĖkؾSAi#B+GP[SFbnc$^5q\(֯_v8nN2X `3 @UzG:>; @9v{M>-&/:8"mjy͍c! 05.O>۶Md:OOLAjGʎvʌ> VA?c֭bdŮ]IJ5g,AӛfP}aqCSSS,{b2c\ YP!5մd4Hp0 ,ap0\p8K.8% \z}XJ參CCbغuBooYLLbWFU*?r| ]luGB[['Y6בQQb8;8+G a&7S3[bdW$K{ɾ*Ln? #",5-ݯ߃əqYD3b58kA,s0SիWOZF#[w"$df/ݧ˃I_ÖQׯ' 3dddyƍIނА hu9c4ifvV"q{"mڊscC#~jfHG=>+fFFdTVVK-۷a8_+VFa9_Fueyh;z">+[ރ s*PĖipTZRS 6M{jRSSd(!m֮+OweX&%q\:{%IJbڵLOݻw>SRR^zbOkWCy t#**岣}pus*++%N<4tjj>J gq䙉д4P&|1-eeJ.AåS SDMMF(77ldxS Z#= u`" |uۍԔDFb=l;^|ɶ &~+hח cZ|tgSlcb*2_LfZ-;^K:Wr*2<|ƃ\gd%%%g$48!puuZիWQW_63"**KKEIrI G$ )s@Xx뭷c.<{n.Y/gOŖDP9c g*4%륧GD9Vǰ\ֱU|ɸtrE(dDFD@ V^a3,B)mK3vP@e@`#z,F(`Q$VIENDB`;utLw Ya+p֭]{׷o_L{{{?>])stR4p(zj-15-Өs*p]HHgTu&h+q9دGrZ2`fff|4y32O3bŊ[l052M3 ]|є)S~ٳgO4jԨd0 P&{͚5WVZUٺukeݕ7|[T-[&g5${]+߯j_+O85]~iִkʶF4  ~w]zWvhʕ!ڹsg|=yO|lڴ)zޗG\٢+VD=P4~zc4y{xsnv9crqGJF( 0oK_7׊[f'nEUޱcSo.G:oذ!ھ}{tGyHf;}Eg_p caQ "[ wy= (j@ ߯ze;|R6((Zvmg 6Tx )y>~&'x"٪TΝl!Y!X` ݐ^n7Mig^8p 9R߬Лv ouC]Vˋ,0 I+_tWFӦM^nH;$#&?4(Ztm۶ML?'tcLYdhUY֊0:02PsT}}f ||$7ȴ~~6!}ᇻ xV H3䞘7Ғ'gy γq|0 ?9&Bs=ai8~# mE]$"0|,WӧK;8?Z+CHxp~ s_z%6Vč6M<& e^h&@i~hOq~> &C(YqԹN3u|я5x>tQ,82 )b- !P( Mb>T ltĭa 9`/X,c} 'tGX&}ZZWA?/uGq_iS*!!(Tf υ|*9  I\g -wҜg༬f.)v ) gB;8qH_Tǧq ԵP%GM.@,tKFӭirUw}6{%qŕn.@8$[ sʇ//j%KӟT⠴Y>hIniZ 4qoZD<]7e܉'6eS, ׇZI+j恦LSh4hrx!o| `h;b{! v4Z"aO&/dp(OPtb%jAKf hL4r dHq#!lF0Z*5A^ՈOZm #L1jԎu ̟'.ggl҆:|ߔ+W(*?cz]l(!Ə ^l0Ba,P4>e#e)7de>]ye|SZZyjhs2FghV> ``4_8`1X. >lf@Huw;+|=0mq4CA@!GV7ׯ_)Yߺuk5xhѢd'.3L E wc/T, 42ьէ)JHC:0b++ؓ諭PNG  IHDR!sRGBgAMA a+ IDATx^\G+łkF1Xb5 b/#=V%QcDŊ*`ADT@Hvoyggg>!HbH8 Ûʻw{,iPTI4אY҄;eܱ3NkVa4Cٸq#ƍ')`kkK2K>Gpɑd\zYIO-q\<Xj='8p'G޼[eĤDx\.zb n߻%];akB> u-[u띐Nb2889uLMѥ[]m7!*+1zxi7?Eeڣ+U" 7cYwymiS(ow CЫ ALBW]{bђQ\:$ x5wлwg@^FX;v;w\p(io]oPT'cʔ)T[tIFJFhR=.™ (U'oS[nhV%VZ000a;zzz8p&gٰa ϙ% f͚b_Ft,VMG( @߷mŇ:#>1:zS]} n]a|艏#CKɞ˗ƆYrgĉpvvf'/2K>tߙȰZj1g΢UV(S KQ.+VtfΝ;1l0hkk\v ǎc4022ٳ;993frJT q$%%Ecpi!<=E\\$"!N !7b)-EmӖ? @ RQLWԉ`}* //ٜ@:1}ԱZl%ZW!)%忭Fc;V5EF$}T Db8o76mtՀլ1&=7n24M.՜9s񴣨 ؿ?\\FvaldRgT'۷ bGbS?޵k}S¬Yx1ڶۏ!7o,!8w*Ve˲!5HJ4 _oB왳GXZj,cPAشoRRxb~ +Wpgj`%=k644rVҥK%K0KƑNc(eeеk5krgXnqpY۷2|0o4 ySHM}n^9'aK/ iyV-0IXLޥBN-y'PHׯjVL|AۣTR,Elڴ ϟ?g|;UHG8ף,Ñ0p8;GpH8 #ap$'FLCmCՆk:ø~Y۷BSSdf7g|YseGUՀLQdEuC up8 G%l-jQSn!W68tMOH*G\dޅt$''^O,F#U K}7<>. ,4U -CD Ο?FՁ>Jӊo>2K1[w<ő*8}4J(RrT_^FMhXN~s07mMm|]5LjB+Q Cбs}$B^/;D*ǚG<ߜ]!-^8KQ.dk.=wF=89m͛73Kƻ!b[fGUȑ#R"U}{ <jւNqXϴy,-f`9@n=^?A̻8:;ߏ^^(W/O~&MVK zJ0 2ηŰØwyfɇ.N ,-䤜prtBl\,䣹YstiۅY PM9s&Ga-Ll޼YHN}%ĉYWr8#aTlBfV-[oeKq*IKWPug=.??=F ٳ'O4X>Ŕ)S`ecH_M ` 8^Cѣ=yq>|Hu izAA^XUun޵ AHh"> dG />>xY99Zx_~v-"##l2j? A& q]DE!1 P.ݯ7>-'xy|l MKK0i:#]۱UG4iNk@ȫoѰqC,X;5U?&3z J'gaa=cof ,Y#/E}=GE7n߿cb?ԡϞ0|pحcWSߚbϞSj"UK(Y$r';M{}]}/uXӡ'>L]­[hڸ)R5Sacc1eT/WOßBf45UδW~ X̰"O>>V٭筳(&4DРbūGbDzKӦ#߿GZM'Yyݻ,{_uȚ}z/;3R<8TG0f>WOwлqy45 E]\PjUԨ]훶=u³m@7YjVCjP}#yMUƇ]6000_]Ab%_O>(Wrx 60K\a1:`#xCb0^W,_IIXdk~~i8zTDݺu?ݻv-fZ#91ou􃦁&jU5~]6T(xrv)iQK<zSnhڴ3ވekj({zK慼j)1*<0ZZ7od1dÝvb欙8tO>(_*~S?@4k#wL711yIx&۷u0u-<߀%q6fN1׮Dn&͠ bб9M#TZ kҲv]]]Zh׮;ˑ;d:K!/N0+wrLGuVu$ՎF74j\]'۠s3:ʡn۵*U=ۢm[7ܹ@^mג%hf t ק7w/+q qHKk_+0>|䎢#*VXD [Yr<A/(f)t45m byPFFj &C*UadLr8Q CDlR*/dDeYr%5f/dg9sA1bDMh!]Ax+H{N:;aaat ҠAۉd[)E0*r? &W#FFF#0֪PkU`S8Ñ0p8;GpH8 #ap$ߐ~X,UOLj҂YaǶu#m(ߗپ}"] b f}bHLId|D'Gcnf}* f1QU'Lb`1?>IѓGѥ[$$%P؋8xyyc/^]h"[j {)}!F3uO䇤$=uSait0dJzD K7/q Jc{m&t)i 䪁_esWat[$ۯ۟k$^w#9%Y!Ns G?#;3$&;³_*4ZIlɧ\^],ժC-Coe*VEoˣ},jhڦd?/#G`媕(S .Xvf/(.Yx%ʖ-K5)FDaaa2Ј(lqގӰNtXsQ DvȂ+ ,ѸYcپ};n߾cM!>>[la~z}#,8e1ư?FCWGRfffTz=+O>ũS%}'e,%{,--U;.\rj_f%19QK C K,"*9B<(b 6.Vppp` m\О3TOl ՘+/?}Y9#(y"O5Vte (ӺXCdVQ̄֬#^, fxb4.ٹ'Rmp7*oX?G~/!MjU])xg ~2NkPV-]zUi ֬Rj!E*r b:9ԱD ]~DƬ+1\t.]qhp1#(W,= >[@T6mڰ#&&A"sٓT`QβMUT Q%<[n*pQPGpQPpp$ wÑ0p8;GpH8 @Dz545Yz++E##_g%5.[ ٿsl %-YOZ1j(f}bF2K>Kc*pQPBeEA/V H8 f5knO~z%\t'2\&tϞ=̝;,etK+ ;GosF#Ds֭ ʅS'\8䵶le1NA@_6l'''ԮWϐI流Zhժ'2\r<-- ,17P% xbZw> |ѤJ99f$^G{. 3_r CG3l5 ;d@OO/(htl4't &L1l09犺&-QbEXϜ ,/wUV- ax\5i z}.W6oތ0̒v ڷїEACBBr 5&fx\1blw݆m:j9mox݆<==qQfɸ>bKɞ3fL2*C1KЮ@9P(@\B0axf B8a |AaȉnǢKT1ySGש#ǎ-~<>}0h?tb*:|_A&X G٨/-31!CN:,h޼9*HhѤ6mZ0kkKF+̔/Sz[)Ʀ1040D^}аvCvDu>1Smtc*VHEPjfq B8(cǎ#{+{ĉpssc|׸iӦG+~QfL@ݡVs֮]ˬWp$ Wp8 ;GpH8 #ap$ wÑ0JDߴc"Xz+}>/o&UPiηFÖ ѵ]WfqTWVEAܜ'sTVrGeU+"""?*" ? 59UOl< D<3** oC"%UFhh(='̰a4]݈(E!`H8xt^Ļwذa.^HoX ޼¹ѓGXdC{߈0{M˗/#.!sZb+̸ݻw3K\7o3;UPz' Qyqppȴ}{L8?4m>cV< ģhݦ殴 B#9:tc/D6lހa{D*x9ci{4¢KPve4iZZZ01U+kOKmsMg|'331oΜ=#,]THMK+}?V 7.yc1g~{ \,70~՝UܺsKϬހOg]fVQFT6 ~S&P|I vz:#k׮Bކdʟ^F:$Nd<&tq qZCNRRS7 1,%g(a65Z ,&mXN HUʔ)Co*fʟ^F:$Nd<.IHSN>( b5O({ӂSQ)(y0jz kkk VXYqaL6tcĈ;w.wPjQ[QPRիWkN鵎`<YkvuTRhР8s8s8#ap$ wÑ0p8;GD b,YvhmV0-%/"55(Ѡ 8Bm'h .Ƙ19x>WXYM/1hPf1edhkǩ5 o*%ⲁYUUUDQP|9p-p8Ge鋰Ÿ;$sǜsЪU+,]!sx ϙ3gb8N;M'OıSRi^u$19#-U~(He ?DU9E%h/8ĬYhhߥ=fϞ֭[v-;KFLlWvC 02!}ĤDDF6)o4:} 41n.H|u:u*OD>3$`ᬅ+nhӺ3U_s1]՚U ©nb-^GwڥK>{ccc44rV>00Pׯ_Dž %+u'QЀ4z5D)w +Kɞ]ҚG<|Ga=rN5NkׅV&O, >>>BTt,L<ġ|/B^'fϝM]|Z0p蘫p%ZN3. ~ʙt 8Ƭᝀ" 8|2J/ #̚9S'OEBB 0c)uLM4Ai>"=v1'-̬+vnߍf`hhHKNR/ \ EB-X GhM67r͚5iƥi;J*Z[BO UX*UBUhDz(S<&w %(.iifq@^?%PT040Tx)H}q8p8dFyDWٯҥKps˼5X^!qٲe9NW&III̒Zja̘1 . H. pwÑ0p8;GpH8 S R ]m]XLPr`^8s CG[,ri&DFG2K4n{ugܶC_3K>jԯ?O1pM@!uM—5Ͳgd159Ñ0*s?XQ# K v S9*ssv[oŋ4U:E,^=Bߊϟc`>cs"rpQp^>EE'N"1>YE8uy|@֯_OC%#($4ŹSQ1 hB -e6ł 0gOU*+\U+Q',HU7m̰ۙ9n$<o+V=`%Ƥ)q\D69 c VدՕZ+*E=/uβp.C`iYBi$$7CiOVxNv5 ƿjTXL? /"baΜ9CcIx".[Қ?=%#d@-;ߋZ^}"< ֭Ϭܹ;אr}7 ׅ#iRF}# 4 K4[s[_cSr(^ Lt[ys֢UVx|&K)~3ͯ.`fMK*:wHMf_ADu@QjG2tȰUFţwޘg *Vj;y%: mf}"RBfSB Ej1(UŒ8 vÒ%|+#Ξ9 Ӗ4=oD2Ħ!!#$%9=dS~AOH aO0,{o_eMM-Vz ~!O[fg(~SqШ~ ބ¤U B}O:L$ޢXZ"GOѱ]<z>|XCa|ﵲ%>'2aҴr|Y*888ײA5XL=@^&JQ@.K)))Xhي2oش1ѣ-#ՙt\eJBqTo I 8~8jש#c]=}`xjϼ?v GSLU 1t*=[X;VuH*<&ďC_!o;b^AfHJo`sxW[ZTEA h;!Ae%lR7rDbs-=Dc> ' G Q- (bx7J C!ov2ʅB h`w^Y).tr,|Vc!Qy뭷?>8#*qŐmq_Wʁ$ 3O+PqIcAѝX8ɷknWέ^WcA#pqayY郀o&{ŁmݖubH^]f„ XC NX'MڈIiذapyQ J= ] 3};h@[giF >\[ZQ0ZXsd)7]-1VǺF\}žNV3bYoc&fiSD 1cGߟ\ch9.12@s11[256_11f2a04bea4aeafd*&.256_baed89ecf4a57e3a*SD256_5a792d142ceedda9*R 256_ee7e0b08ae4a7f20*M8ƄM&ؙ-е#7={vdjb+WL~i/ `Th LaIt&7\ @D)RAT')/^!h|8J1vC8e&CV,[Uom3YЍPg41Ε8wd.(zƍ;re3ƺ/~*i rPTb@2ovJX/{?P@K'~Ӫ74upˆD(oIW\GP!Sĸ$ߘbbʺe1c_փ{Ow;}7 c~ip$Uٺ&^׽~P:B95fغqo=͛lǍlKI| W/_Ii8ѪL>={)3^FjHa *IDdtXKODZR`d?>6|I/AHb/$ ,}Hzĉ;'/[hEllqw(Z!jŭhP֧RYB:h )830ü-B/8_>@bJg2 ̵ܥo@ &f@a4Cxf9?in#Txfb o@%ukU>.ʴSUTp@ww*ޏcG k]tRzSj2}gezN mpg o_vw'IxtE۴HQdvER P=&[]b@cyD[zfv#.P{'+K$H~bCh>X4TW"nz52հhY%袋d;+dWoЕPCh=#FmȲwEgЄ&TNcӀ[0:0at0& )}WUtg&{Łd%dTw]7VN>yJ(o`݂ff:qb,l1y0('C[҃_,6# U+N8!9<9rdW,gE26PC_~YW\)Vl۶M P'T;*֭HOۢ ܸ>0ٸqcWڵ+:D,dzܷVܴgmïϹzF$jbw \#I3yAAs79餬!ܴ?VO\_ʀ~TNo{4Z$]Ʉ^`)x%HM +&E.8?uM1XLo7 lFB6Ҙrq 70ba<9'Gy -0,}aiX_ܗb]|Œ4na:[50% h ?{3i\mAkF`4FI<cG ˜ܘ+ "iJ󓷪zrҎ ih)1p_ 5y|7}h(tAtg+4BxRi/;QƇHACe*-Q|h!RAn P9O,g^I i#4yI b➤BJ!!PH.*hv7e3Vz4 %}* H+\Q it R v;Do=SkPNG  IHDRߓtsRGBgAMA aCIDATx^ tTוk$T% I`88Nۀ'id_w';qwc6vl1`03h籪T<ܪξ\Ri=NݺU9{<<1uxaxaxaF->|}k`=nT{9.,#G煎渷Z;Zaʝpq5hTUUAGgx^[:X+ ~8utv×&l 77CZm}c=-;hGa:xEjkjjWZ ~SV^ tvUgNgkN;a;Rvqف/BK/6g{?Lhki3_詮f[L6F-RWVU N9M:E8}x" #tg:$k%6MüMA ^WsN2q04[EHϛ5=INy!aͽkv ZP_mjlS4ŶlZAhqbλ@@4/->(TVTʚښW._ ..U Ӵi`1:(%ʄ@ P YY@X!#5L&J*pڜPOaO7Aь"Ksgؖ#xg4---PPPSlE@GU ?zW>p:;AR;:E"Hy@d^v\!ojlڜ`EyGKÇnt8s !9%}u"Z˗aܹlvLJcM,0ʪJZ_nDw 6M_,=]=]+vmo}|ڮp8:[~u\[_<8y\ /x;_:gO3NLJa4Љ63= zCĹp",_\MMM =} bMϕX+;m.[~ efdeܖNCS{h޽ڿ̞Ɯgܘx`ǻߘ_}O>$HD?!}F e"J{1d',$O?/-,0?gpX֙fKA{={᳽ٟsU׭_-(g3^L  Zۘ8Eb0#cZ31N i? YYYli|IHH;3-܎i!k2_NU039'f'f'f'f'f;vw}&Z h2i&1:bKǥ 29[3~h4Xd [w%FƤ1P={Vە`葍&8 je1(OXW_P-]G|_Y*DQ;w[e.3:Ҟ|RA4q{ z8f>PLzO-fm[^f_:u~2L';vG<\,UypѴfzcp:cEEa$C5M96 /#Hs܍ (WVQʔ /@RʥR)44IXcM8댇DL,eee@z;4~ HѥP0m<,o+A,Z{H9 }8wt藂I1?>"pl'pF!*la 1*x wE@4&G<|ҳg'Wx) gaL~)&l?xڑJI尔WkĴ9C>O7pNWH/7DzB% h.^hH$/)<T_6ș;vtp=4yUW1g,v c3ڝv~X.6ܒb?#.]r r M HMI2޼C3KZqDl듶u\)l32}>:=+=\:T+"~^]/])>JzųgII BzXN\TԗpXl$'%&#W>2j=}=PpH9l;4&%$t:ʢ>mXs1G;YTXpBV|Ey /r?SYHL\0@;N[Xvt8ԉLƼ0fP& !,e"Z+L%%oyY9$c"id62%+ZÚ.Dnm6cެyG<ZtJUUx|X~r8ujjj`޼:vFE ~LǮ.$>mee%wÚk >&~?R"kCnL(J;{TR'>MF4Ls;{;͗/\>#L)=uw3r<9iI)\T{V[#3f`~_C^ZbXh1KKK{?+[`Y gT***LbvJ]Ђ,X =k6Y{Δ. u _//&BI~;ߵ.FqئX[~󊙺u3C#[_gz+Ϝ;w./)!\K,d ]X`8x~Ώw^0 g9|0p;[:!( A"@]Stv@Jj |;߃W^} /d0?_87l.?Y sɾF߳~z4y,pzЩ='t9,1B]C&k-!AH. tEEuZRP`37dbx1$k}jit:u|Btˇp0 fhHπ3@zf:~wHLd~pZog=}IKCzF:ӫl.( Iop1ڛ!QVrx\ %@ ڭtKKܱF;=YOBAރF*_d69[Z}z/H" ,ZЯSM'5~ t0DfG&'Czu:i'mrú 'ʚ/OSt\"7Vgp*xV3' 2LUV͔*tV`[NK/T:hA+L74Q--du.^AͤQzW(B5IVS<`P^^^&n9i'_\Kqv,M ns|mm: 2IkC3!Pp9ϟOR z>) QȆTUb 078~{&ˤ3 R%0c*hUZz0%93~ N#X-.b![~W,)٥)[ӎN_}ƍ?X,E+8c fk LKMKՕUO37U IM"z@7{Bܵ`w?̟7_cOd,]T0q*YT )DR LPژ4<gaK}'᷽M]P})՞*e%$[wec'@"t%BCLLLdf\H2QiVޒ>FXi}’EKBMWHD.ہ`тEeG(QH˖-y/#׷^ܰvCi (;w- nơ-djP]x'R@zZ3a0}{Ha2x23UzFt DQbgaT)Tu O$, liAi gaIEHFOgjYt.b-5gn <X;[^mƙ2qdb{قf%"3 ǑjQSTRA%P8kID6_ЧKP0{C ! @$(Z.)? A!on/HTTTtB&!Sej0n߾֭H\l6b^aFrm0)>-3b8KWÛx".<<<0-ۧz&v3plriÏ6̝a2`M~}](pn=|C= =gkp>$ ̒-_wAs KcHM6iya: J-Yv%/τyܥ(*ۧ(^ga E^~'pFXjdyx"gat{39qLf&-rriG!ZK^gHUDο4d<FLϗo7)1v@J䄳0*䊦HF4Cqӧ=d>t8N ?>?v옵|3f>\!vtty-Zgg^۸~,,v'`v{"7M6S%Ke⅋9bƹj:POO L p^v$$ Vnh4VWv.5^wwttɺVbj1{FoJbJBHɫ#I~{: <>{SKSp0S(jȏ '&&"OSw^N^D!j3oNR*A_YQ5?j.ثWğ%KVSj3za/ETZ?t^iBBB t0#N񓝟hӲXw,^Wz۫7۸_ti4> ^۾us:;:R%?ƾt<)SdLU%&D6s-m#P8DmcV,,KO {ùԔTR0߾v儴YBI AБ۽[~ YP$j "BM]aFQ\ZMO.BRHO`k0@wH%c9 #7 ,?YjI]p.+k$"I Ap:B55|IoGWGB5&$&{i.3!C2yN*`vlP&\w{ϸeKJ֌?x)8 Mt8܍B)ɧV,ZK$+E^i'1MA .৴"3Ӧ,Z4Zʹ 邿oP)CYغF,~Xێ3gΨb]S4e$j9I5%H&wu*?7Xl9w-Sf^N<2U!oV$*FbmܴqV"J`]!.3=)D yJZJ|pS|XL[sc Fw~|bG+,(+ 5ۜ6TUTAbS]??Yŵ/.J'j~,C`[ӯnyeK #MX; "%DƑOx.Xq"YosgR <l`̙7d%,lnMy  v: J N39+7KV:TC1W¯S574maF" U+%'#ǠWf4:B''wbo]vVdeK ^'?b[.0sLSrv~h:֋*il/&Ts ڰBF2?fqK{Kg_g_\)0a/OHLI$Fsz29kkRRӬV+eegyP-cXdRPʥ7joo7C+W\.!Bv;݂^coo{K"6m΢Eڒ4Iqqu?yr kߣ=?W~{,8,{J{=XL\{#Ȧ˨q@\Dp>KgD.1i99uB\୮&X8a΍?ژ3tmO?u.9p¹*MIO= !)atrS@2 ?*dtP`~fʟ_Q.c(+' (,Xג pĪbE-[l¶.rd0-wսvX69s,YYQ ͜kq( rtw/;W@WEWT!whfJdJ$7#׫iZ滖ݥ-;VRvսfc}?\P~5';+V+G:Xb%ٿ֣wz#ֱ~{H!P`.X23h#DTqy\irhRVM88L.x(uۉ0@qVᄑ+tV&Y åQ8LUK JG5}& p? *T*NSJzs?%:b$ bx023D>IP*AAa5ZΛے/!7 Ahh>>wlՄ=cII H62L""k*%=g9A-d[VԚZ6őޘRUͶ3ʇD(l}c 6jDJt04ںZePTUj'23I IT/#.$l_bZ-ڸZ:(|:{FviңGpst0=c;K3i0#7!oD {a,& [ۻz P"kPhjIž90Omv$*l1!- 2 4)ZM36wa,0=h&(GUY;QL,T͍>`09'#gDB[mw8Få''jͺ0?'?I>7`ta:9z6da7q,H5K0|BdE[m15!})**+hkpLFMFx˖ %b9y"&Q, STg'-]tA-%בrÁUUp)޽{ Yf'>ebiTI`r1 #A;A;8ѡ={,|\uE-'&)nf8LsrF<x' 0DbUj*J}_ö0'#-E"uzrF3XlizǬdfN: Ӫxo8=-c_OۓŖ1M IͅmolJS;}h/́`ڐܤܭmlSUQE;t =#cSˀ?RxR*'CylM 8|#1vϭȵo=Rd|atBBBD3Tq~a4<l)2ύׂK-](13D'Fa–׶l<M~|yhŖy&=`"-|Z[{0 f9ƻEfX-7ꙻjBcS#ӮϞ ^&(b٘v"nȐfƄvDߧ>Cl6Rr?c(8~ʎ}?)?pX1mgns{w`04#kD O?6a /g>tZ8yFTj`A:f{pF!lB^^ٷGYPP߸k.ǟc ᯻]&= @m]-NFCook >l7W;t왳~!o럟7ç?fN! z#"]q⯯r3sq;_=c> SPOb08iSp]X;pp ,ib1wf74^]dJIꤐP&4۷8F^ {+_O=r!bX/:HCCCww,#n+ F7HieBJ,b6X dm2ohQ)#jHXf ܵ.+LOK﫫3>u`fA{G72 $+I0i1: 2(O3^=<̗5ǛOv_ _k.eEbj֬YIٝ:dzM Dz `Kե:ѽw 0gڲ{n̻:_sWWsqҥK:{Jp:儺{s2/[ԥ΂\cNEr,ePlF-go> yoZn tg<~8s=îS"'OMl)23>"k0(ëWfKÃ***Rd]' UuVU >ǎ0=L&-M}>/$bQQyeFv7^3 L\\ga: 1LGgݨC2Ca´ 1Mcܜ׽8h"˱茧O] 6>X|U`wp=rpp#.;c,YDe7e~pE%7qF& !k,ˆ s@{આ !C aB"%3Kؚ k5M5Uw̻#j.UpIn=q,EByW*򐳏e;n ü=2/=-EfP8 \& 寘iO (70Y>o^(4uMW_NK7)LX~\CBzdEæMR@伒yU,D#r1]j'\9BUצŴ8r`MC_ĄkH~m0[r x|GsU g>vo oonh0M=sư(,ˊ zJ7vSSm֭31pڝ̨w~ӟO?n_FWū3槿4S3 {mw3&qFoҧ a$0AmH4zr9{JvUJA .\~;-+).,.Z.Eԗ<^zuiC{XZHS C*.fڧ&GנCׇhnbpFTb.-+WB85-Ո1{l~esx9`Wb)ks1K庵ϭ)3NS={pbԑz;Jf1Qʕ!l_WWǔ#D {H:ޞ׷~|,H^c 'V ʖ &+9!y*qb8wD'*w'|RT]G>B޹{gG2|S'Ϝ4c_=u;0@0JRX8z&DTG9*f 7ҥKu>h6f_p0%mnmI4Hѥ@SKSEii: kr``4:9 AlHsڝW+/}ԁ|ސ[U%c@VK ;r6-sm*>,--efVf>[q>C=V,_%;03/35ج32?Cފ ϊW| kJA:h7f0}(` jCF1G\.#W"f%C>sGbPFt]>x~ Ez=sg( +"Q`OD SRRiii^39991(i&wRG]jN2R*Jc $c6 aP$559TRQ{Fr(7}K72qgڭ{^xΊ'qA-E"?z-Eahl>1xnD g,Y 7oFby3N|Љg1V ' qPos^Dsg(#1E1vPǩmat@pq3500:n*ga Â}8y0a03@gS2Tǔ0l4zs<r_~/g8U= 7Kyͷfڵh\'sϞ=]Bo>?.03Kl)zषn۝lՄSYU 3KfB2a c͐eǴ6=צŖyαĽ&ጉ&;/0g?{;z;bEǾf"~sxO/;0֑;@zmE ?t䐹|-?ۋ_/©3D0MZ/ ˣ գ1i@h  њO~jsaxG1Dzĩ5`n\ٳg+项 *MʎaQks[CQe{kcVEيvLhYh6Нɀ?!?D z*.Yѹv,M3t:̩&lSL8^8AvnטJ슁)F#ԛuKU`('ٷK-)Q؃A8͓˽'ه dxEgS5d o -n_4Q6& n\fx`Ͽz^݀$%%]}<㲧zJ')((`fefő!D 嚇/H,2g]$ 00߹\aKK7oL$SuZ-HRbXԴԤ{ݣ\|9 R^ʻV8,;5;.Aqe (p:>K4AS!URT٪ 3?$ѕaA _%lvn7J}}=G1v;F ހ=Tj0M'%#̙3{krZ@~XHJ4̈k7nژ'^y<# ݷw^z.?Š-EZh1[UpB=pļysŬ%q f,ε&)@ǏG=}{٣3L@LobzccptDx%)ZD[wsci'ZgX'%uGC`kӘr 1"`vϯ[U(Wdr/1nc啺i3YMge=VM8P2ّy(\vy^t S;v#7d}7d57`QrkR0 Y#yD@M3Ĉy,b)!D"X;2J҃ F7҄C$MRtӵ5(qgܺyӋ 1`x'465Mvޡnݜ@ps jƜCápc7zN PgJ\ sܱsE2''`^v-[`v/ fH(JIDֺDY(!aVGoG߯~Lᅑ€?xZBiZ> G(PTX\ t:) )?};S]>e^(!LU(j" i/\|T(6U\\@(:g&0fdfL|}kp8KT(6vP^QBZ(Þh钥L;D!S(Zz[~v܉*嘴H@ ċ.4`w]`WA !gYI$ϊ+'x<Xdpv"|}hSa`=&Ds]v#ionmkk{==tOOm6?̈́d3ǁ@\w\qk; ~sȠ7uZB_?saLΔ7`0 7 x1+_|dddMuu5lfĬ0^F"9gFH #cZM0 07ߥ_IENDB`tKڐG-㊋,h}y jnT+ &{ h9EW[O20_4} 0at0& 1a34Mf`3H!)(rxbβ,"?F`Q.]*FJJKE9 JU RXVEёL2E.b DAmVkKfX>X6FGI\5ֆO/aV);a1Aƫekۘ1cļVX SFcli1Wocfƅ8q[԰Cav_::sCuEU r.6hJ-w2+bw`?ЧE|7~d'|̛0B?X77m4x͇ o 0(ᄌpw#Kq>Ѿ8 -<:*W hOߋdBXO|qu',ӐUEI(T~xqcFE N8Їӷ&FR8e\IiCHpMp&J޵|ƒ{pm_f0S$"|dX .CY=0cb P8s=b:JRAD#.4T\XvZ~K.X7uG(M3(k-Q|!;Xjyfw iiz£6 4™Uwh1Y̒ӱ ?[l0:05!CŘ&t6S_̅7k% [*0ZlCyo٘K cШpػm}#cЂ ZSua!aYh0>3 Np@ɆآE4,ou= X4{hQAڅ'x":g޽[Vٲel⋲*+Κ5kdV^VaE7x Yiڵ"[{CZ 68~6kq]o]Q,ãMWi1jN >`N.z/OwPY * 6F"BWTw8Ơӧo8\x!XODAHш<ǂfͪl޼Y~[ Qg̘! jN>]XBz֚߶ml+AD}ޜOZ▶sNQF 圭[V>aj.pN5S=.kG,LG;❨,ΉjHZL??0a|3@̶, wOG%~ns Ekt\-ѕIVz㖚GA`4HCP`tM͠!VZը\ +V/ I9ݹ5^),**!|]2u_P-'~l#N:$ʏPȳ@$䫻ueu$މu]b= 5ڄg몔 xDwiH4E&䃙9sA18@Tyqt!\իeǎrn-o\jH7.O_^|\7Myi4 6,WVg[Xh1NptNJ;vLձʬYdZp4hl'!LqmC yPqXbr@>:+X Q*s #ÇuC =06l|PF50cz)L`[jib-ր,%E+1 }QYA) 7ܐ\!LܚP֕c+b _v\!0?xt[HZ RIk:{- 07F̟?_lxaWP0ˡe&"Pb!P+[B]zJ(u4 ew"֕ipI0c Y\0~?h>F\軴,a哷!at0& 1` & fҡ<[+pA&Blh m& !YyVKXp`Ȣ L5Mxc9F|{ꛘh01,:3i*'(?ӦMJ̧XVra%$c]V#GΝ;70`l+Ѿ6`JJ? 4z8pT`*?-=a O1bE_Q]?vh3JΣ}b7Z8?~ ;>7{e = \p"s49JߗUpx kmVmt<7I(4F}TsZiv]P>N-h>y9~7nfqz+۷o\pa|852V\hҥ4ݱ0֜gϞdh6Mw5* D =,ʎc v̛7OЖVV)kSv{1[>?{܁=8_@M'}G}i xyp/|(&y;I?׊+DsF0|(yUae%`{|YH^yUf OH`Fpb*xmœN:I/‚k?AN~}L'<ɷK/TpvJ˗/oxib%EͬvW=k6nMX[Jx]e I %h,a哷!at0& 1`LcLAreg^SO=Ħ̙#Ӝ>HӢ S'%YM YI)dÀEh}r! 4 Qm0M錬4`%`balkJ!d̝;72ڑa]apEŦ#cceW4c T pŚ $(p;/q%WhHB+jF'=DAX3Fw}w~ܺ@AH.]UrR/?V+X!ƕI&ݽ{XငR\+ bw^7 Ӥ]"ib!UIzHI.ϕƺMzSzZP,>{s? \{u?5]v9vh&_ZZAP48ƽpB^p9҄$=G5O2R\y|ΤY8 3h4vTDʁ2AUoD,dz5f,#-ꅮ j?„+")a?3240ZAD, fK$%2X(V^z_ 1'0j x{11P ##B!MO(th-Lt8TPbyWo="=@+Lj(Qzx^|9i]"k`4;vѓ(iwqMHXTb!"ї1Fˆo+W6y:L1zRI7`|M7t,[|e7Lt8iЪXʦe]w%+ }ƍKC DG?;Ch G%*Zdk.W),Zeпo4$B}uڻw&8w8Z~O? DߕO9vPxz^7HK=4whU|icۆ dN?p$W0*L >U8bO-#آ?^d&N(Bj;y{>~"qtp?^8b8 +-7Z1 rGPB8^җ^WsxH'0ND#H;UU{><\w Oy?{>2B#ׇ '1e/JRX @RAwaVҋXHV7afU uUi e]&3 h7mY*%BIW("}!SC@?joۇƴ$O|)/.ƞ@}]{WqBH O34pL"j'2OFfg?,r'G0QWn ` %S.YC}.4NúF[텺b|}`o4p4 èX |Ee"cp3WHP.@(F{fq-,X *\T*z3jjjM&a||[X=AGɻC9 kjj ǏsQt(`\ذ)njJWI ^xۉP7~ ťbw`V^ :*((p;E׸8iiZb0ۗNJ_zeYDzn:1vAvk6\}Hz@SUDΕìOJ6)׉큉 9!armr&w~GI\ym+)|FzJnuYZ=$+($6Hi1)y_R4 dqmzIa~9TM 9K &gi68zwnӚ;_כu%ɼ@k=:ܭtprj̶O ,\!!.)//v>-~d&lM6gyZ߮e%{kط7) nHIII4{tt&bbbk.rk |ػw\v F&Ұm_q7)::wIZů{+v܉?A'yIENDB`M3 !㑐'H#£ۅތ:닰gg~v~Gf}|w W}ʣ/7|Bj{R_#OR_ ^ WȧH.G"R`}<$V!XȂ  E8HЄ 4Ȋ `i6FCb""rv@ 0 $!KrW2B eB!R'=WEp{ݩΓ&"hȗpbXp"iur[;Fc@6&:|r#)jjS-udz Ҧs^")!Fb\jBj)`{HX Y:!RH}MkN`*IK.: jL"h m*%4 M  fE 88qo1 @h K!E2QN/|'N7\+/@,ӵ_Co~蟯~~/= :9 C:Pl`( RK6D iu!J\QVuBZa=Kl/= w8̰5 =LpHdC~ȍ a)nHQ1YS-5DHцU cm8` (6ifF!7qC56GnhDcHBz7ԣ"x+.#AJZҌ>&7)IÓ (ErrLerJU$,gInɲ̥Io^2G0IJ,2L.< Ih6Sf1Dmzӗ7YpjÜLxvt؀; yZÞtة~?*(~<h'1C:3jDC3QNLsEFUhљHђrԠXfHR:Bi¡Rձ0HCGaΔ;}NF?u)IԦ*uc Ԡ:)-G9UR5X kWy ւJ %/:Wc,[^R P,X;V>$0jbُp%"&о,+D*"UšVV &ue(UfŒm;[C]ck^x*`t[ӖQ.a`*YCV Ep.jfĵ*!W6-St-x%D +#mn~4_w4IX`Ae6M;'L [œыL@Fuml\}rWPW8ujaZ/-wa|B(LFETmѫ꫋oLW稅H,HFnye*"bAMv쏛ˇmyV+3ckVr'ŭV˨A,g@fvн}*"Ni:X8m&wieh.=7Hf[d6s8*oѸfa^עtu b۩&l^njqxڻ~rmcLFQ"qkD7Syۛ*&Fo[|'>32Ix N9O}{BE?Nr"(Sr\/oU!1Eoss׼@σNt"Hm;MӧnؓS%֋n5W\((C Оɨ!ڈd{ Q,N[!",MOJy}!ŋ8yY,eAz~ذ׈Lz;ژOM]zq|H0V~?}۬ݓ?ϽxRGoo1?7Onez4ȇW(+;--7&Ѐ022PW8 0€bH vg |%R*I2.699YBFVjؑ9Mp:s6_#9bUf:~9cA9!咏Xb p$XVcS34"B'X‚Y.jw4I!8x`g;6s>US$?օM[sfC$쳜liֹes8Ȃ)i4d-?6%@}%I_'0B~$qK.V@6A d)hfw! ÂIY`֖67X9(+X]Ix}8 "3R& 4h3) țX{>Ը.Ң`YV'wRM⣂I6]B68ZH/iL3W8H=\89|<(y𑯀ghg/Vd{{GB))6;ٛ"kvʔ?bB5ЧoeVh*%dKic5 Z862[R~i_7|{(% ƙ~kzi.YƷ"PJFGȫYWR ê+`/j=~:i_]׫ yۊ{zzQ6r:}Z04}Zz aGJzjMX q^:{kK hjy +'J;+;ܪUKJ+W9)k. kWkCx^tHfPDvl ni۶r{9`X| 緀;RW{X$;H%{*帘{v`2wd.QGg-[yl!+mn1+ѻ[u{{Oɻ(x):*Ika1p]:$kܻG Nڊy{Njx~#O0+Ep'x J9+%Y;w)-N -˿ț+=x HcGbWy`6K"lb)&I.2%2^c¨#7r'3 1%໖k> #HJ#N0 c,MQ ~G(Rr{a֘VRpeEԌJe>fǺEx<`=|<2OSlܿPkr*ȟSɱKɥlɧ,]v+v6ʞJ]&Qˍ ̑.ǕPl̮`WAͿlK\ܜl\,|0UQFΰl||4ZN͹τLlLK--p\Ѧ].й^WW,0|"]'ͳ yZ)<y( ݣW-+8RMӫ̲k8] G]a@MB-![;=Յ;IuEN-:^[bW[FV ӫ(ȑ׋ 1+| RVgnZ w~g֎Ԯ؞.6J$:^oJ^^ٍg^Gd]pKv _ {vʣV>˾IA- u&'%IXMtL/I1nTfNnL-N?,2"Q}*!5&eCۈ.i3/uE؃=YGX>WnI\1^gH[e 2ph(4x=x'_֩0_)+VPg_H,bߘ^&,xH'ݏ:_9hB?,߲Ji*O7%u8*g$~=DZo?f7+I!a™"r._/"!08Hpx(9Iiy *:) i J +:[k{ۋ8`8@XtJLh1X4 P$% t8]#-~ 0>lH>~8ꜯ0 <0… >J `*ZDDƍ;z(+#t4%Io,MРt/dbpFO(ЗBAPIm;{ z#:2Z+Ԭ[f}UD}v5ݼ{tT[pߪ?\#Ĵ;yҫ[=R>nW~>o_=ʇn~|oH{XՀu, 6aZUJLhax jZ"#z*"F2BXb3^:;.c( ҒN> %CIN]&RI!Zne^~ 9Iffncfn gr&uΉgzg%\gJwh.h%:NJi*Bni~iz~Jjʨ⩊j* k(k '82&>" m5,m;(g#,W} [mk"HދS^IKpn({2lp[U.˸?>Kqoaȱmyo,c3. 3#0#mL0Et41v4ӳC#/Y@p$, Opz9qOx fLnP[0wp$w1Ltpvs,p%d`-gdAP1̏oB==0$ m1PZ nn|"DRm1zJ7qch5B6KƐCRrx$h0yM6"rQ t)?v0U<$X`Q9!l&n\G~YLgjL4+K`6)&b3lg7LssHz'[)v2ӕ:¦> Кd,!*ԁ R@*${EEDѴd6jt)WLJҔtE(-J_ S\4+3MotB&1v/pп̴:WiZq? `~7|WOV,D5#df2qk\)M;l7!ZEi9kN$^.c9=?=Iml}Q:E(}enin/nՈ@n(B*p@Z@n3Β@9lgVs٘Td'a=o.w4}:baƇfL@9xOd'#u{]Qde,| Qt=9(WXu^Z܅M[W*{?7 'y{$u&l7,U& X~H2_8wyR_w_h~uLiHxu͕"gByEXVB؀:]tchgUk-x7lC_uXs vX m_B*FEO!}bSsՈAV$V(~kʼniKX_~ǕޥUhh V{%7 ̖"HZX  f<eHeChvh}kdf`:WC!9 h֌A  cD1 Z$}H/QrDQяGGt%:gv'}zFIx 踐kln.1G17Fl2WC(A~B7:G7Ie1KtOq 35A9Y>f=GyQBՔfPq p37m6Iz#zTEH9ij(AUL K惫:@!B99k=!?yGqC)H`whY6IVg~3xMY_d;0{ 䌳UIM$Y4H5T{霉ɛ X%FHd)U g9Kߩ PO…W ςNm%BX ג : ʠZ 2Ȟ,1(衖x! ك+:hQYј_&:x,Z)0ڐ!өvIӉeC)<@(ܩFx!Yښ6)[Aʥ]Z"z餉LO( uI9HThJRzF)PU:%Vj{}:^jus) x Ah44@̐@ZD{F|1daؤh bZêVbJScu*&Vq*ZuzJ. @vӏ $ 3evfKzÄvF&nډ MdRmIZY^7*eZ:$6vS CWDfP׫~H9gqFgch}W'Jv`<&pv # ڮٺTjvW 6|D51js|9y\")>8 e9ho! qA`(ab91;7VuǮ|{dnys6r ;0YX~amXGo8'vRLfA黓`bA!s3ƒYJkbs9M` P^c; 4< pvZl1dฤ) ܄" ӐcaNk!v'a7C#q' ځ9}6~v8q V *HmˑM :4d릉E{(;PFh엘 MnY}MAl)2f@6O`8cwx  ƾ-Q}1qy1:djܢ+i|w`|+ƌHS{Vᘅ0k4KO&4:G4)?Z 3rܧ_êCF櫆T)8L'ڦȚz yͅ#|78nzN,Ζ/=,A˫^< l м=\zΣa ͹<5ѣu* kuÎ| 댛#ËϮq5 8 .Mөzחt)% ޞ. R@A-.'*CP`aA t֩pqt{\& J ;be7NoH |sLt070lP4z^[?KMHDM Ef r~ndd* 05ხS;s}ǰ@YwKkc-Ӥ>c`gFu!Kq0k*-ͫ^~ 5.{O?w6v < .Hrezۄמ#_˴PJi(đ9 h5Gxٮٚ`I;I5^%-4$Hn{-2KMo[U\~Նw@k Aw>\&[#yH?tLlbjΧr80'35 l$|y w3\~GYHNCnP4`Iu0ƀ>s*,k4v7_ˁ0 OV0qG1O) mCrkA!BqyԊC7jYvo|0~ WuGۙFSC_Mx\QMR#O5EOORRɼȲϹҚݡۆEưO S50 4}ֵ+UР|@iatQȱǏ Crl5|F2ʃ{k@\rΝ@ Jf2, ZMTT>sFӊƪ]ÊKUVM*K*Xe|k\tu6߿}D_gw`_v:~5˘3kV-B?CDx^noU-rc԰PcYzirͻ  3+_μs.u磮ͽzOӫGV˟OuϿTh&-uF(mVv!>$h(2"l+0ƨ`h8X"@)_>jVH&LF)T&]%eUf\>tek])dޅe$i!p)'nUxg{w瞀*(3j衈6@1ʖVjPJv駿p*j^)ꪬ]ꬴB*T֪뮀Z+U&A1,mVkmtump#­2覫.rv&^w'I P dzjk8ġֵ oF{8e-( ɬ--od$q!\x9?b([ vsAsEWK"Uw=8GM<++sgE{ag=6P۽B}Vq*}1y 6i7Ə`Om'IEGR!O~Bm6KkB߱rI$м'R+H*d%8O=yX;ᯞ Uxs8I /@ &DL FI\Fd;B{Gw='(`a.[PAy$۞T9s "fk"&ԷCak ;!OvA` 1Nxu" v|`_ Ҭl? Ecӄ!#P.}3"iPR7"#1G-l6 K@1C,RdZ@6M ~*70+ P8tljPҁ *.H AqseiB,Xf> Q)fd'c%:&#DEތ%!A B 3|yyD"a;>S||)jId1%tKjR~MX"|R BYJ 1GE .JCupGC 0%iE |{ЈTCHҪxY`?)>W6= CDX'kP?BWg]zڠ3b#&F;ύ3oh by܁qhVooQ7v?!xml蒲tw&{II!/\ 8 q nTc"29+~zmƍ9[r<P'Rgm\.bAnEg֣~7>ر8S)[})Խ+bOt'/ t%~|nx}57*ۖ}<`ћ"HPIgO{ϽdLكOA|j Џ&[?ϿsOF2쏿ut>_O5~X2r/(y hQB1's5ht:E'(HjӁvz'0mX1x2`w5825N<ݓ|&@9H@a׃ԧR+ >DUv-H4 Dp$PG$GS„K`07]IIJj 7xЀ 6kYk8֔v . 6} Z!rI RlI@vĘ.8uyvd9:{ cYqB!{)r/*SGi᛺Y%9G)*x_iUə2Bhg#(^ئGgP<<=Z"nYÉp|Z44qa=AoFYy"LIx5 HuiHK;nGTGdoDX NEceNDڤ1  #[Jr>gY9:0$q1P ]5U >%:ti]_ 1 dQVTuv|jZ:yРwBcG% %Fq$dl %ZFsz _3<6QY%PwgH]Ɵa*A`a^Ku.`ΊY:% E 3E?tm Efen]Q;d^eeM@@^ A(4SY,ୠ)׊MD5j4 וzH{T` WVGl9mMԣu D>I0tS{|ծaJ0F$lĮ8ݵL-p:ȆhZD5Xu}qS 뿭hE#t(;s,ᏜQ٥N9gfٍ4Lz0->J:{3^5^T>{;^6-M-BP]v,1zCVm*惩d>Elpqt^[x~w|N>瀞v~^舞<_.׋萮B^阾knn^ꨮ闞N{.^޽ofnɬ qɽހAʹޜNy?R9~7LҞ=^Ϟ ˆ/LI~ߞ.l ^ B$Q=X#9ۣi`֭Evf?+tOG0ҭ}?}׈ 2=U&~$oKDAb `jXDޝK-Ļ %*ՆNt?V{_ѽJZ%4֬OMě.l}O}0W;]o,D6PIH튣m#{`0w< Q&DDb/QɅcpZ:#10?Ѵ_j]F_ c%dgRL`6Z Ѻ?^m(Bh Enl䥯W@?:6iqkIv㉊P!T)9IYi()9xY):JZjz +;K[k{;;[+k8Cj9k\8\m} >~)^<A~^i^$+i>L}0 gBb [-\(JĆH1ƍ;zcT!ExKIk]\ 3̙4k:zi"ɜPVKA=4i7JTe?1J5֭\*ɦQbkUlۺ}kP,\P$ٽ7޽| >8b 9εL9͜;{>mϤK>:mY~ ;ٯ]eM;ݼ{#ċ?NN8Wț;=)ZK=֩v>C%>ig??1`FH` .A9`N9YHan5ya"H3Hb*5%2Έcc梏fOO MFdDIHdP GXj &=@ eIf}jrcTfi'\qygC̞CA;4(`6Zb&3&@nJKj=R S5# ",B" T)0J@ j*0J1xRٮ޴[jU$R,;k b!dmz:+cɢJ1 ηH!.FTO'HH`,+O!sH(,ӑXxD lZr:2M \H+' q;hBQszuՖɐ1hvg'tR{ݰYx Oޫy_o3^jؐGiوu6n#z룧~݂I榬#윫96bN{_xp>Ͻ#/|zoOF7 ,OJ`JkEȰql4"@`ʪ(SJal{pHe\'$b)I5sj\$_+| {)Cq=_d? ЀFz@Є*t mC[EE.(aV1,(uN.͗d(Q=jKʬPj^':шgQ2eשHF@e0XcΩN14% }JHTժ:S,^A(Mi iL^R2Y}̙#^ZV4ZS"5NcuX`k 2MSd% Җ6iBu āK&g)dZĚvK)+g{VKR?!a,6#j[vD l,vnp aol>&Wׂ!靮l&zg!׵-s7V]W] ap^7aQ`J}x$6/xKG*nx+ Ah(:bcxD$krJn{'Kyw2e29\rc%0 <)3ln8͕D6- lYt`ݳ|<;ϹAzFЕ3]-!8ZF=S&%3Qt/MjA:pK>|%DLV/{3[䯑 ]RMvqqظ^OT/ko;S.7_kq_CJVmŽ&ηtYkl"yk#$9Lԩ-lG6Nͽ tBK\%[K9I1b`[=z튧[@XF5Vh zRc(Moa7"^ $Kp!G%ٲ>=#Mfem BcB'oz/\o.Y bh/*̈́/Sp3L4!gu~|^75Pp'{pLr.Ps}i'@05"sjTgr'kPyӖu z j!8n 8öeG#CPo;8)+3Xmw~W`7݆q@`:fu3xX(X5؅N(PdD}exioc(wtx9khjh`{?}Hr(AZF8nA/vharx3aXtcŖh8(e83Ȍ،uQ{;:ex*džfn_cqƍXqp^g`؎zx r6WxcM؏(H]YȐuLa/Utht h6r8bU}vZ #u-b`FFWt7|nP-=)b0y% 80+Y432,2M, WINK1ǒ,)lHYJL -M`NuW(gC+45bvKO4>Yg(hY>4wҗ2OS)F5WMI4FDRch(?0rY)Z*5@SrqIeɏ26XI/hK-bC?HZ.3NOd03w9bR8J&h*rzO3}*QJD13Ğ7F3֝s?=hj66c}* ʠ4^9Ho/Aӛ㹠b!$#Jʢ-/B( 3S.Z?ɣ5&aP;ZC C*WdT[i ⥅ W4oDyKYN됝V'[G5pL*pPzD^UثBFBIDϹT L,ZrТ\ZH'ylG7+zk,q6(jX$Dg0DSG-L H,u7sD4H0T+C+u[5* @`9 \H%: 9BVٜB #3Ȁ]RYn8 o+894x'luQiv0 р neX'C, R+K 0)aK`.p/L.+ 5P˺뺲 k˻ۻ +␱K2Z:6#KkڴI {";W8$1k \5`؋(.)PQkDRk0 1(,,[Ypn7 ,! #\%y/,:jEu)y;tTtfxUTkW=~HtR@GZjg+L"M+TawEBk 2C'3wE`LSM&{:WRy{{*.s+l~65U2UlJpsP.uXu,7wFJl7tiĪ8Ŭv<~+ъt :ʔjXRDʲf&\4Hsˢ',L&3D[-x\Ѭ˯JČ ,̼݌\N8Q,{( 3w1==#Љͪ_Z]!M򧊱E}dZ!m#M!%d^"NJ-$/d1->BHf7}+]'  AM WF"R#0]L qԈ@RT \r?\=PrWae~d^+da=lnM=p)Eum׽a!xrj=&Lbr%׊uxFtؔm=ȎcكhٟΣ إ=XZMg٦m ̲wn>=|Q۹m򓩮ڸ ٶn-ܾ-ܢ&b-͇խSݷM-K}ܲީ-`mތmޯmyM1N ^^Mщp ujۋMN_ͮ&8(ϩ.2'6.ǧj6>8i3vFΉ@މB^hN^HVNnX0,>^>-MB]4h~0S9 1E2it)+pC[r~trE[)|˔*Py1s@CacZRoz#_-fL93/Fi9CRDg*׹Lꩮ h}ax/+$C)6cbT2.:qN81 gLG. YM7Uq0Y5JN52D,IIU(3ڧ ] 'S),z/*X]IQӸMSy_&ء!. ]NKPOT>?ļ:mLODO^_,>OnJ›>]O4{YIOKoaqo9n: D4wڔgpo:G};_1y9 iԼ#j>i>Kb?_o˨}??OhM\OiI}'@r՚fuld;ȓ+_μУKg سkν;(b'MR#@KUB ]Z~!Tb F(T4V!yCh:Uj8 3ӠÎ;P߈Wx"|*2R㍶#d8!&FWB܄5$Ss :RCm`"% ^եTidm&<%ޚp9"fك }{f$.WPrʧGKr4[LFcf#O駠2g("藎#Z`<֪ZHVJH.6[6+Z*aR ղ:- khF:z[j;n$k/cnj6. 0|*lX-o^\ טp_l0Žm‹rz,]?0lsv:\< DmH'L7PG-TWmXgK\w`-dmhlp-tmx|߀.n'7G.W:ngw砇.褗n騧ꬷ.n/o'7G/Wo;orafce-VERSION_3_9_0/doc/orafce_documentation/gif/VARCHAR2.gif000066400000000000000000000037021362147214200236760ustar00rootroot00000000000000GIF89aap!8,a3f++3+f+++UU3UfUUU3f3f3fՙ3f3333f3333+3+33+f3+3+3+3U3U33Uf3U3U3U3333f3333333f3333333f3ՙ333333f333ff3ffffff+f+3f+ff+f+f+fUfU3fUffUfUfUff3fffffff3fffffff3fffՙffff3fffff3f̙++3+f++̙+UU3UfUU̙U3f̙3f̙3fՙ̙3f̙3f++3+f+++UU3UfUUÙ̀3̀f̪̪̀̀̀3̪f̪̪̪3fՙ3f3f++3+f+++UU3UfUUU3f3f3fՙ3f H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ`ÊKٳhӪ]˶۷pʝKݻx˷߿@Èpǐ#+fбˆ) cg[68zcuOgT-I׮-Fv6E/q{M-oE'xogq6W9}Ԟ־:ٙPj]nz7&m=n^!Lg13 a1W|p]k>P_&ȖaAHam )#1ࠋR֡)4~f(|5Lc@b` $ q)`q' >If188a> &Dj &aC e"1 (l&bɩ E #iYIfdRFEr&hcs=F榉vzԧgj642JjQr AXk*PZ'JȆP:mvR'VSE+.DJ%íe+Yt.kR/zn0M^WQȫ cfJEGqo3;1Peq2P#&sL?KFS*ט21 jcRj"FPVhOdLJIMX*2b$)/e!!4=@F=5:8u4G|+a - W`%@@7db:@#NR骣|sڳ-4d=܈MX~ 8)x'iBjz%J#Lfs'VMapj}\X^B#~afnYgv/9 )B9v&A 029&D[M&H ZBH(Fs [g&!BƐux\G8 [ļ@beBD:u z O$0GĊ;=$+Yłň#hIXY I9lTIԈf<J~6~<͏T:SfDXxPC>Egq@" $Â) F^F!8>T8 @xL8h!@4(P>,!Gg>ORZU%UWdA,O0}T`y*xFx F)nIP0sssc&P>x ը&Тc>V iSNaAGD)tM-jT'X &`Az&&[˖@* ѧmT>z"OF')  Z ¤gj):h.NXp0Bխ^4@y>ާornZ*>qo ,&PK)kXiAlG@2DW,SM1/ T>!@.nbѮ-i  >IN]4ȯfk( 9KF-AA-)B:痟 0ɓҡ,!|_T'~NW>bZx"咓6KL:3wG|HͣCG|'A\gF, "ƐN :NSo=593޳,{HNӕD55 zH$6E*sQH%QTƖ<;'M џC N0<<1:OLTܰ'BLʆW{. URCZ՗6;k\7~HD<(OJ]Œ -=q[y A"l10@ ?rE,.PPF3`` 2E*~Dz{`b\U4C*a(09Ь1q{#(3 k>"G( Nj{[X:"8S BbS*8&jY b2qԒ/"=5v1Gj"AZ;gZ}|y(g9Αtؑ]QJ 'Z/&,<'ρlH>}2Plk3"KPriiH$/ޯza.#Q4t_wcIUAC" :_T_U}cWLHp;ece ^(]Gqт-|"+'*dRJ@~VJ<;ݷOmͤ ^LyL$=,t1&Kb# K.9i֬x$;soSϞ-x4٨TH0aEƬo*4,&*Lsz}9G$Z[\9"I=5H :1z8$N͘GIY:=J~>v t+y5u5( ảbvnDH .1"գxKMu0'AH|)-{oWQYK|) ;W"Uyv!z#>kk,[ 񉬣8W4MIݍb% 8n.{{Vȕd-{ª՟Hw6a6gvݔ۬V>e^Œ`+Y `Gγd]yXbe.$xL X/ŕFKdw$f$VZ'Kh ェm$2Pofx%M7jAFqh3a)3QB!`~5~3ƿIp&N-rX<^6ZP(b5+1HɆc%vYy*RfsF+hIBx\6vshё\'"07Z$7R7"BzyVj~F0AgPrpp;l206z#Z$3i%OW41'abr?BcYskAZS; JknDgGeQN9<TkLgg'؅T],Y!|Ц@9q wioTu(P"xy7ld=al}^TG%,r qlWOa61S196_f s s=2Q+"Fu8|SC=‚s߳ssr>ߨʨW"y&4tx $w0'jrgGWL.*pBXA yY` 6XCAZP6[|RE#Ca}~2);#&uɅ3X_/TRa_g0Ԩz$'gb6{t͈|Sw}7h@F׊v}8,Ig k)Zo\Y_R06Me&cmgV8,- IA>ƨ{O}8 i9.9(bMDs-m(a^99 "1艖X:H6-Ut NJpɜǝŧK9Yy虞깞iȗIhPMA :11z9 ڠQ:J  Z"ʡ 1 "z(Z@ ʠ+ 2:3z 6<)ʰ=QBZFJڤZQ:RZTzVXZڥ\^`&ꤔf0bjڦlnڦ1 gZtjz{:(zקbg.䨐:Rzq᧘ک1z1Zz1yګY\4 ĺjvѬAV֪IF9pˉh+=ˊGmHap'e{'vW=9k"'rӈϊl8 "+&RE !Fr!T[UMŐww)2 %jV!iX5Iku4FwbzL;˳I(dg*lv}*4mH+u:kN.4?'(e$aĆZK][7`[@m-a㚲嚴>kzmdMTdCU6(ە淶gI`bs2X9k+rjQ6=IJ DaWJ:6u6X;%3MIkiZf82nKݚl۽4q֙g拃ouѻhr+[N{ۺ%i`{&oZ <[ %Vp &`9؇#L* )Dtb{t 7 sv,V3oh"I"!03n 3ECě@T{Br09ByR8̻^% U<1{qwC֓i|";|Lp˛QIX*DŽpG.f ]A}˖lO88zGܼ ka#W&am.(qD&ȵLvJIu쀮YE ua_n%H~Y&KC88 CF<\Jï{6+kϜ\/hA AgFЉi0mlٛ5#,,;@~MKm)Q)=' .)7;\`YCi&۩ 39IgBMUD0_ 2?7 I^(s"Cc\!}۽۔mS]rx:9,D18t Ft4CwHLJG8G6jȜY¢RTY^WC?,| N}""E~0GkC$Cf=31E;/-"~vg}yq)Z%(^hY7ń-FżNNլHo=̒ܜfW?ޝq>-!Zz(Y[paNK/m4x\w+A:u|,KkTpϦ^oݱ4=>|9#jM%Gsus F(vб&-51`sLxl7 U0#-Ԃ!О BDۢv"Xm\E!qsәL=NQ{ <IWkl%P/MھKσU)&VwKM#B^IJՕЈ+6ڛ=_RUð4]11:֤}r ;&ɴtAi٘-tكtEVޅ)uD(up:ɽD\3M 1-j^\x@޼m-Y\wU^|eRMѵ( [ڭY݃]'1{K0e0ٛ-4I^~}(,C* ]>Yx TG$rw,DY$|xbԈgHXpfLDŽo%>&&@PQ>U9Ry,"VoFCaXdžHDRJ-]li&Iv xs_PqЩ(NDŽtІ ` CY2V]~*A:{ϛWCr1"g%bCv5`…r->^M}TW3Z^$uY^V:3pa֭glȼ"έ@srF+l͝?gȜ+r͙m~L@G;]sNh,bC]CK0JܔI7 Of-.ZoNA&n}$?Tk 9FB ΋p=hA300NCCLǙ2)I "kIө2)0!r%醋2vIrI,".!#RL$3 ͽxyRbdXFc8'D<gygz OV<"CgD B+@g.5` U@/-2/骭kAumh g->CN$$4cEJVY{1 MdHMPCf={s;]ėoL=} F l];X/Ae v3 UDj UGtCXi@Yq"s)| e!NZȄ\*S'Mq'7ac%,M+BRf AO0zbH`@h@@ԠEP6ԡ:C%:QhFQvԣBA:R%EiJ5 OԥKe:S}7i;9SԞiPLըGť20 4@ KR:UTփQjVŦ&r[kXȘլg}VgE)[:WXUtk^Sl`;XְElbOo{,dX72V,f'K1ZvB+BLRD{VcK֯9WXÁem841 r7 #eU=m׻0yZeˍHyᝃ *'<4lzrmVR; 9R1ie2yd;p k%B 2 +}D[BLVxDa0x[Vk̒T Ru.11dH韃B"G@.*9V[o<)2[#M3nN\5+j h%PB`"!FR.+>EMP[ ԗÒ O)"v]/ Bɳ?Va.KY˺&Bxd^K \1{EڷMwm$'siI⥏ܚU"[f!ԇZ9E!хP EÍvw%.q\& zzc(p/z9lE$/Xۉ|Nѫ rG/zJlԼ^ -(G7fܜs#2Uk|Y)S},ra Xs6w͝!9:|Wes>|hn|qrkBd ꩂ : `/?81$JRl0[; ac$Nԟ\X5sKU*.!~LwVj~ۓ3 u9HF~ֳXuǑ(sϋ\cڂ$XaF ]T[bs ]b? FK@03 ɽ+ً[!Yj?C #g jr @h Űb AA;X<.6WA u EH]8/q( Hô.<'c 8X Ӹ K rȷ8 Ø%4h@; #˸;l%q1F<9)lQ!B@>8+2?Cމ i{aOH p1 EsZ 5Q;_d@5K;{A'iCö 8ıɞ1[` 9+ŒÄk|1 TC;ZL,?ѼLʱX$59E55hAd̔Jk o1t IscpS0³A#;Cʵ Z (C ZBD(TE [8ȶr8.͛P ]ρs礏`;B}=tĻC|Q-p8 pD̹E|HGjPK>;QK<8}肶#IA11b82  @+M%DRыc 81EzEQ W a[ES2F :<5S7eQ9@C۽):[ck*xuُö d4t3 6!+ 6LIPK'; E͙ۛ袙# + 1}퐬ܸLK̥`@B@(4 p JȝWqH,PXBmUfݳ4GVIL1( E%]Di8l]PmyT|eQEiUe7^uH֑dELu\-xU\*_]FԏX d\5:}T]c [ZH:┵ q\]}]>GTaaQa bT"6#F$V%fp'()*+4,-./01&263F4V5f6v789:;c ;orafce-VERSION_3_9_0/doc/sql_migration/gif/STRPOSB.gif000066400000000000000000000042351362147214200223440ustar00rootroot00000000000000GIF89a0Tp!5,0T3f++3+f+++UU3UfUUU3f3f3fՙ3f3333f3333+3+33+f3+3+3+3U3U33Uf3U3U3U3333f3333333f3333333f3ՙ333333f333ff3ffffff+f+3f+ff+f+f+fUfU3fUffUfUfUff3fffffff3fffffff3fffՙffff3fffff3f̙++3+f++̙+UU3UfUU̙U3f̙3f̙3fՙ̙3f̙3f++3+f+++UU3UfUUÙ̀3̀f̪̪̀̀̀3̪f̪̪̪3fՙ3f3f++3+f+++UU3UfUUU3f3f3fՙ3f H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ`ÊKٳhӪ]˶۷pʝKݻx˷߿ LÈ+^̸ǐ#KL˘3k̹ϠCMӨS^ͺװc˞M cͻ Nq>μГ\ƥ;w Ć=vţ/^(j}濸`yVH!ȔS1 yE x!D6`QMB 6ubG%"$n!)~"G-J 1Xh0z8.$R7nP& S@1P&erX%HMjC7$Q/Di DѓgH@@|'Мw 2L"`>h=0 E"1CFd *gi`dZy`AwK $Ƭnrۘ3zn@[ ʌ:n)JH@ 7 K**j : Z۩A7:hz6(f[jBAk %'0 e $>[L)UZ' ;ss,|i۟6,#@'Мk$+fl-joJR 9!8WC*ț~"cHQ x+;E_rq@_zM-[w_깯Y# r0o"r 2l21h\O7D]*a ALlLP @v{4P<ylbo{A ~֓N1?F b6bV졓xsz@ZZ4rMLQ^\@ 2?8)vsa֫2HU9ˡL2pyϑt"ɇX"s/m@6H ͊9%"\2'#Nj_\b|/#^%l\%.je4khDEdIrg#$ofl$!F$N<2)umOf%4j]1ܠlE,y;FAőqR%QyWur̥+qr#aERΔc&!hbfnz9Irԏ9Ip#Ͻ3"_TgbЃ}i]30F7Nюz HGJҒ(MJWҖ0LgJӚ8ͩNwӞ@ PJԢHMRԦ:Pjf;orafce-VERSION_3_9_0/doc/sql_migration/gif/Staff_Management_Database.gif000066400000000000000000000207051362147214200261730ustar00rootroot00000000000000GIF89a3f++3+f+++UU3UfUUU3f3f3fՙ3f3333f3333+3+33+f3+3+3+3U3U33Uf3U3U3U3333f3333333f3333333f3ՙ333333f333ff3ffffff+f+3f+ff+f+f+fUfU3fUffUfUfUff3fffffff3fffffff3fffՙffff3fffff3f̙++3+f++̙+UU3UfUU̙U3f̙3f̙3fՙ̙3f̙3f++3+f+++UU3UfUUÙ̀3̀f̪̪̀̀̀3̪f̪̪̪3fՙ3f3f++3+f+++UU3UfUUU3f3f3fՙ3f!, H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ`ÊKٳhӪ]˶۷pʝKݻxk߿ LÈ+^̸ǐ#KL˘3k̹g|E nNU-5jW~n_cz6m"&Mڪ* xmmwOY1;n3 yy_Go(}]sS}@5_z'P aB>W>'AEwaN$ y ֊Cņ<ͅC u-!!GL)vϏArHE;F##6(P2 _9 ^^DJxKo ^>*<8>28(Iq(X|$OwZФ>Pg)C =i'EtRx!< &Y`@Hx+tRz"Vߡy.6Npۢ^QbexHlgUr'bbo 4.ZjЭ<,٭z hܪ$oYkE i (CMez@ZPk~0ƅ k)|Ro&;#"+}|ٞZJ)"K_}0B%GnQkI.Lqt:_E'4sC2|oLy!#ݱMkR'Ig"!6݅1DqVBl*` ~S>ݙQ2W!B|D,O~$S3/a4Uon"~L!츟Z q5Yim.VLeZky(sy#A2Uh+,)6EP|kBpCJ5w/uTe vydKK2՟|tOO>\S @Y#׼QQpCU]pk=e(zFpcRx"LmْZ'o1'G|c/fH7goEz8BK<FJ?V8%v[;9f>I tZ%$-Ȟq·8]x qe򴖛)'KPKSqA,2|7-F@Z[/0FZAwXΝϤ[G;rU=W 7 OUY- ږ];a_RՃ`W kIFȶԁL6+VdZQ"B;jh;iF1Z[շ!In39M$rG4qp&SGծr T}6-Ȩ*^.M i:3dcB1 f[qj?W>bϸ?}rnm 7+'{$}l1u_"xԆju%yN@3>r~]A; {V󐁕#L!8 .)SSÕ".wbU0w=Y>-t]]FZYܴa+RJbq:Y3e?IX}4]jb>eXT}AO{"*X' [Bha_1-u^F%KTU˓kbXrg.b$3#(^ ec`-l2p(_8c,52b&|cyb'cy'8V'~B"CG&vL*xN' XHpfJvDק-7RtF-b&(I%3gEo8r=H7&t4f8FӍI1Z~Sja35c%Ƌg5Qi4BBx\=Svdj}pFpl6pQlxTTIhX "HajCGoEJ:8dNo*ׇ b++}BlfpCR>Fe|FlIe/ICcƊ%?0F&$"h$aĒMFy3ADqj,7t Y&@1yjN#Bd ibIO+TEE,L{H1Tr/L̄^ I9VgMqu߇srg3R( R()g/X)a7Vi!9h+Yس_Yf*5/U(xUi/@Nqu)6]SNONs[ 7Kgg H8BSZD-mU2"F55X兠cZeO?_}ixDO~T9qgu-R]>q| $t0on #nj:Aq h\ DXSPs]SY} WW0>()HQ9py;JZ)b 8)U]hm] „ѡ;;w3 ׄ=oTc)Wc*2v%'ѡXiz&&-ZCm V Fa:R._|/&w@.xeY7) hX}B"HIIegyFEɎ Sh Ղ6 k!~XvɦP66 U_Lr/9i,Pc D?ʭ-YAZ#間qgD5zznnp2w[iضPl40p եR'U.3pG0(%rq~Ě!|H'2ISsB8Q3wi7:$'5κ_Hw)!\U&sP^x-(+wY֜o1n7Ay[0zNc>i, 4&ڴz-{)8ut|?67ۨ`y;HSa Jd)۹OKOAYOOoK$O"IG47⊨aFl˛&DvsQP(c;O:?BxE > eAYUuxeѾ5Z7)|w!1oTW!?I1N} DPaB}W%B#NF=~RH%MDRJ-Иp PT -籈0Av,ѐfDKS&ͅ SĤ@H 'QӮ/+άIȈͭ"elFuśW^}[dh.0` Fт)LXTt_ofbl҂O[!)qQ ׈tXHh]J=Opō4lmܟCc &au.cqav/}.Q) jƮ߆|_G> BAMXs ˢ7+C 7CK2o< ]"jӖ[hӥ'Z"(Bmzh:t*]܊]zr'yHnڬ3xTdžGia2Ih3,Ƀfh3`Z aWBc]N4y>ӟ.j5^CӠ2E`zzߪz:mh3-tJ˦"ұ#iRJ: J>448 6a)~,D^y=9}wes $F &Q³f8JLJO!)'эWNJщNXj N ]YσN@7ZL2QdШʇ͐=N/HPU\aȮ򱩥M8'g$YAr&qgkZX 7KeeqHOm2sLkZv)Vɝx\&n`74#Gp>ګ?Y(>@-wy @Y=JHǖ/}/E T1uN2b7ZJG xsAW!_z@TIOCu̗zw>vnIsbȪlH#'U?G1!^u/"^~IXP)75xNB'TʬT{%{i5 k$91h;o@g8)D:Obh<:`l0|HIVԞ1=u#ӆC!kyL .IcW.Cw?~Gտ~?<$4DTdt $4D ;orafce-VERSION_3_9_0/doc/sql_migration/gif/Thumbs.db000066400000000000000000000650001362147214200222670ustar00rootroot00000000000000ࡱ>  !"#$%&'()*+,-.0123Root Entry]Q/256_712dc7f1b4f7f0d(256_88892e1f72faa1d3*256_f3674027d7ac364d*   !256_71ebebd8f4b034c9*j.ܞۉPNG  IHDRRC .sRGBgAMA aSIDATx^4Il۶m6=s϶mٶmx15]Y<ȞB޵v8ȇ6ߎN7>c#(7>=^NJm 9ۥ!|;^t rͷĐ6MCvggnk%d7;YBNv8O7v=C.rkG%o;!|#hg\${yzȕBo!_|3>!:Bg3<6s!  ydOC+ϳC4C~pȿ6>7Cw6/!?Z}#s6߶CyPB' D="!' G-Bi!¢h?m|/m|rqː3o_=!!P!_ 9C9Bb҇LB} d!,h*!! TA)1Bx@M|8}! >0:dCo&TF xxNt7!' nbN}ͷP.FAC\w  Q!lNx03F!o 9a{C2COB J:oCC(1' MT[Awӆ0g YZbT Q :Vߨ)C UFg3s c$9yHm̂0V ϡ󳐓0@Mg FF3! C%~\ACh #:v+$tt#,Q!$kO _K[% ݔƒ C=頺 Wx)?E8VHVKYB>][Ƕ0O6{c]C`A0jqB;DP8Bd蹆\Ga-<8T.Ũ| %IrY"/:1Zrom؈/S \d_mf}$>"o$mS&"g%woFR״TVRNE=X_aDu:Z̒biq1SKbkx^XH5=mA 3GI+|a a(ܓP_yY!fD6PV H  z4*!\NI=|{wa3^-IY #|c{0DrT'i+˸2:rK*W!! \J`RVq*!F|S0 I\?!Pn]qƆ2'b̈/<賎F9e O{1ʨ}:4w(_ʡ25?SFE:,yQ=O2♌F^_h>`34N~*DBPdJ#ëO}Sful4g\BKE+MAe|4 h,:Nh4~}hD1}91RR`n*#$ye!jHcbJIG3} !FQF)֭(ft*ԑk! 3#c7v2f !gB0'S5p/!RBSpu״pArsDCc9)h# KM)dpu: (b&(9'0 #\;@)W@czO)SS5utVT*3gLٕfԉzSmgEK@ހ1*gJ=>ĬU@jC sVݛG#ovM}5!72xRkӼe (K> F>tt9UBfgMv'+s!t0ZX4^)MQX2V,. kbGquPX3H1 EJ e šI U Bra9 K2{} f%.Ba`%\X^|\ږTKp-) kkحR4Ui_@PX3إT(̌UJ"X0s+fW ˘lwy6evEcwY:+l_vPہ2lޯY){S7 w A@pͷǾAXawep5HL0.6nbg y 'zCDVpY_6:;7$GŇk=lS d5^w}!A 0!< ]029E X.EF_]{3hXZ o:A':CN#oP[7|VV*0awf$k&%t"uԝgB *9 !h`w~IHՀ(YA>Uu0V(T8/-` WjmƵjRzU0:h*OB;OQ# #n(<%C9 M.=`P,QML'1<(˶bsx6Fo -:2ZzJ1V\bE@E>.d(hkH܎PM7oG%J5oә;jN}нpg5YOh:iN:CYљޠ4+<7ÂynG:q"UAYPL0-ʯd9:ob}^%of`)cFYA`&XdoPG%tvh&Zbף&SYAwc׺'cb.ɄtmuW` uzdsd \ [ z36=k]b)f~8K+Uq4!t _lgrDlC ބ$JWk'$r2pF7r&miQlsO\«ё;hKpl$OBH1(.$%9ҹ}A{ )lKƲFmlmж>yD;WszFSן[~9 Rl^`$]v]it^xhbcQt~ץ~]H]cQ9΄ɦ8N)%=r dܔ4 o@)҉U܆wReKu@$B$lm =TgFy˵I$E7UWy$/`:G?OQs<2:jhwYm8\mS|L*&k$@9lEu:lkYVjKIvw"dCl@k.}@*Ȳ{"+G9U$ܶY³S _ft. 6QtJj4]QFh$1 F!P`a#eMzitxXh`Ҵ0oQgDyPq)&2<^P{3kgfy&{^d\ 3O7 )? A@&F=; e',PlNrF2CY#tVu,ΧY '4Spiy'<ig@ 2hy!bx^ 29(qGʉ7 gzL[Oqf"#i42{=VHL7YOf:Ud 1gJW cƣaxLl^o ^SxNIrL)ٝ˵Xh,.,%`d9YoSFߓ.9+N*V=-MDZp,rQhыVEUl^LH;RF 0]$?a̞6\CFd'tvԁduFc-Ba8utj;M'b+oAWn1Y`y3C+mYxS:azۡk~7 | fƋ%簰YPbncEFEcƘwQX^M` {}S.p*1q_ri]\BaY6Z;("WR+ tHe2LP(!*FE( #ABaQPXc(e6Lc!BF~zujD%@Q( B#[\^\(M[d2 BH( * {}ڲyȖ.χ/a;f QHXV h YX_h7^ zؠ y0-BYE9Ǣ&' {eGWL<U4F<)8\hI Fl'0Xs&weBdB;3 A9=z21v=-M=DL4~}a0Sa=F{`aymцK.{_\-Tw1JUzhЖ1p1iWg0.O ę `jCYPia=f`FkwahQ5O̙x%>yTbdUJ:Yy5y!S^!nA9]p${bLͣkǢ ca2>Bze5pe52ftėFε|r.t80O|*9 DY9>!A}6ȌKIb[>pÒ䵫Xn)/$*J:P5B5V_l-[Fm!Wgf6$&FAH3ˉKEF'%"ޓhQNB1CYg@BL@CAh44R@XN+֌0:ITgcߖt0$UoNU|s)SfsL9yQyFRTA^ $%l!0K}ewr1X= O+O7rXNq n4ԌSR5Y/`X07=bt'0:kPZi;f3N0RV:2[d>lעyF=>c`݁iG\YfxO:Ԧ<l10tξ[C,;c#XIfωPCv\ ~ )L ;.B Sf',(}({q}~'R !І>•&O:5-E̪q=D}E@ %ؑ`:Юl'];D2fHyǕpMZ$4Tmе>!&Ol'[X(.z65 t:BE-fQN4vϤN6s5kmD@LauAYҵ]P6vK1 *@,jXaws'WcOFG` @.<)FBP( BP( BP( Oަ 7{ N KۂK,MXhUdŠP(Ð6`s;Xk1G_ 06xb-Eg'6̖!Ψ[N,RU {C!Y=-%-ηNF;:6jj@!dBW Țrښp#wۉ]a"X[c&_Rжc)^ +Xa!slP%|ԞTbgmc_ٍ(c`^mXIENDB`;^A PNG  IHDR?)sRGBgAMA a>IDATx^ }i=KB$H Q0BM+Ef$S)ӔhaA͠X*riЍ2&BWk˻yosgg?(d?*O7B~m '"zhF=!+C73d0еCG/>wO}IB -¹c aWga !ao u 도?! V!ƌfmXKBkBW~ TxnI"N])[Z!7 qpשUбվB{gwuC_ӱck^.伷;pȸf*VxCƏ] Bw՘SB s b`?o>;i. 25Ү;s>=ۄ:-;;d5Dv!D Ŷ.(3) (rո\?Zi!B?_r:6!!q0áohW0Po U^zn) m?(j^=?LEjx!a Fx/do֏ QSƭA{bPJf=y])!U85Tڪs$-c`8ĽA8BVMiVnrAE(кPB核ehxZ!??qP[9@4$ǂx+cW?J|^\Qunk)X)+ q8;#sG{%9.QEoMP׫jW]5aY.{;Ne. B!xao i?07~%$ЗƖ"SRn p'x0@am=Ӭ3`7}ZhS #4Pi% `2:+wt 0EKwM u #]9 ɳb!*6#坰wMR7lyT^䕤XY:01B)f'glxX=%`vn T`MZ"ҪhIA.$ה+ȵf -/)zk[3hce\˵eB]Ŷo 6aPEMHEpƪpo)U\!!a4[ g@>sݸ{ds:y:<֗y7@bSr)$š/ =9dVCd ^CaźJE86PNx ӧ /+6d,ɂl~/~ed]*A7[-dOZ1rE; 0n 2hw2 A7'-ĔN[܂q(Q"tOYmf08zuӺp0q^ q/8GoS, Zs082j}P[၊yB[JZFym2L!(CؖyAx4=!^ZZ13e<֖}*ZA6BNS%PIة@yG_+)OD9x ۗ ^`ר`e%11&7+H)8b.P˻p-U48llڟƪ@j}¨Q<ٔ6Py豬S3RBZJ9wtYX;liT8Ҙzc $FW'18@GGGG{-@wttD~{ki82 ?4D~KCwt Gi/яQ&:{M$)2Tǎ`_m궩f¦0*_mePdPbPcy:!T$WUUa%R^|orJ&{Ԓ ']g B*xQ=OuIVR̵4𪬔幪xpQkz'!֙V׬!&x`AKSlPn )W #*<%)ʔfrŮ qRcP@n<6NBUFIV6J.W%L:/B˾gЮlThF۪LE}ST[O*H 6PMYcI6BQȎs͏b8vc-WJ~FU`9!g$Td^zw)SQ?"2 *!{F:}:!3'1_fp*;)p%Pרs\ߣzO1XE$ gF3(4V[Иճ KRփ@ KC3TVKU>e}"QLRɨ)TIJ(yixj~#JS+ȐurCk3d[h3cCGi#c X\z[aJ" YJcbTPC!G:0Cw^ %›y A"xRisyH3h]mB啹M1y 00mJu˪]YTR?ySG''FDUdy8jU^Ӣ7ƉZ-?(mϪ{K=bo(%1 W%yz=?G{)>' bVn>%cio256b\.!Ɩ[bjxQ00a];~V_݋h?T>`]t0*SNeYіQ=Īd`% U^0 |yMfmslwm.Ʋc ].+ɽ JQe=P'CMԁ-p-j!J1eH Y %ĢbZS<^ >ʇ+::qyŦ Ki (2%`pJpeg>%$Bg#^<)U!gqFbsIR ?[mC^ [xPSh<ޔ1v F8JW}_ujF1*R TB-\0l ^Iz~ JebPL\̴ T @Oy?bH$_)Ĉ2Υ8#E(Hlc`P&Rqcf+{oţ^8Dx=wOuMBA9F!Rq.EA=!lKygL6 |q]r]q*VЏ.+ާNYK϶7ˡoުRY{KYRJC[1t!ߙ* 5 rYf9%.BQWBBu( s="UjgD۫+8ӯ+}l+_-28w/=*6hlܗd\BCI ?(#`Q` $i,#!# l=Wl^h./&*cTg (iHa<`2Z]LY.<B@A+BC^G$BcɫWx_F9cnkMDHbj+aG6\\m~"<`g>ʁrE2-QqnEo6P|YOVcodۮ%Ήf}ǂq}_h?/+s=,{_~ǎ˹[=IENDB`e*xPNG  IHDRCssRGBgAMA a5IDATx^eAAZP E)U&4)!H¥I "pixA H %HB"H"# Ebi03qݻ?9s̼~oaذa:tۺ[o +PSo~}߬O~7ʻ'Uy-QDD6W?n~Ç~=ÕwA3fRtiGOg?*tӕM7to\ꫳ 6 ?lȑoUWͦL=c/'?n[o͖YfSN^{OIr˾d3O-;A+{%Yob&N=:ا~sUW~g_djkƵZ˜1c~7'U5zuWO>VYeC fov({-3l~d19^|lv M?8W}CEx㍘xLO^x!  d.mJo}k<2dHd ;' /o&a(׾;4N9[l0>筶*[|Ð/ټ.B|c9&^|0"w[n%[h믿r>U0x'`ٳ>;{o@){Yc5"bk3LN:)H#>|x+K,Ꮜy8vmٹ_lw= 0jԨڀJv}Ŷ7x&nyQ!M r<o WX`ՀAnaeOup<ۮ;&{*zx/8k֬vCpFz\ %Q,!ԉq"Kɍ̕^{"[ 훂g>ꨣ* ۵YQtM6->7^[.9sfs\D7 z`袋ƾRq=\ m&J9aeOmds6`Kه"k |6_XV6~c+`X!иVDm-AXUxꩧfG6JFmhD"UmhJ@.w|o}N~.3fL( .UHWY WGTM/ϖ_~\sMT{lرjviLXhuWfzvAEMChlvk?AwS4;âp&wdrLJ!L0!m.(6Jtr#c(殴Jg9.C)'; J?·rXX.<5D;$+w\hD\&?"-3ў4f/qkݞѷX~.6O'aD$0T~)=c"[BEO>9<\WN{GDg-ڃSO=5b\^_GB]r%1w{@xd䨾?j2˗SKM();qbtcZ]{7]w`qJ) fm=k瑍I2o 3ј6"0j^ziDVs my./Kd[|jͪc^Kh";7[D)6M򘐱QQQi5iBAMTK)Tgۀ(Ga)EϘRdd\aŗ}1V`ތ1"6l1K'JB 'Z2$WK󁉤 & H99֫(;Cs'n\o6ghH!nQGՐgCԆ4mڴ4){SK!)QC X&UաH0 IAJF)ȾdJ7NhH4yRʸdw^T[$N_/'eLל[CG~ D!Pw0 Q50M}ߢ]Z՞u<%M'* QA*wՆR֞Ep>EWjq\a/~(2=|͑BicoF-@.QV8rZh l*vrt/ZJ0@P~oVUR&-BSNڧpz*)$ʲp Q."E9Dv<@CJB:drbN c|6y)Ti)i>:[ƗC{Ph](]t:j'iSf#rizLZ#XvzjYM\Ǿ݈#>Lrpq)?(чQ%0Js^l%J!ϖѝv(Q"VK;J(ѷ?o,QqOnF <"FРf3WB5q.QG-L<9d1Y߰eÜX# t'ԺG]٪o{QJ(GQGȊWX[矯H[6ulƌC=T+[mMaV V^[|o jeqCަä?C#"^񢌌#8C j,(:YҜ`*mGp5d|(rJ+{ve즛n̓;,[~峉'8 0؊ ڒ {tpk`O) EfM&&СC 7ܰrTzz .>rִ6mZ\`{Mڲ +d[lEkϻu%,MN)7H־;̔jj %#R 8p+&Y"W_=ƨ%/ZlޠxQܛA.Ly[8c#-Gr˅ď cmV3LR]|ZZ=:@d ?wE]4<0dҮ;39b<1viw¬Y"tИ瞋ǸIE%_/ /|py8Yc5bCR=%w^O&LIAI*{nZk?݅δ-m}}<kwϖe c_RdcZ?Y&6 rR4R[̋ʺhpks)TКzy-ظq@fmC r>≚C*G5߮=Μ"Uqh~*p9I,/gJps̜)ώ/DK%I!EC΀K5|Fn c)kSYTr8G@kh @N䎕I$xx~oE}~19Ux@#J6smǘk:޹%ȍ\Ax~::9??`x}jjcVՋ'х>Ht]]QsDV}*aVS剈UwmnDH;1+xuDY= U$ RRnۤЋ4_Bx&*IXYasV&`nmXtOz8:cX{^Jgxjզ(TBN#FOoIO7SMⓣ0hA7]J0|w1s!xn( |2ch[R?P-K(4h.1MeLVr"QcN+%?^M P 8ƣ9ZuuDg%ڡ5A.@ܨ5OQn)(TAN^P YДdc( ="w@]-|δ1X6:#QCؗ?yLHUMh/S c¤. Imt j K-uJ!4x`(ѝa:W#vu,Ϲs`u +!j>={cc|K,?lfܘ())A^^D"Ayy9 ::US*QYQ W+k RUBlÿXo2!33Geuded `-擕g|\[YYYl͸fkXeYSKfl2/_vvvꉌ f={k޽*uE}؂@IA vfDMM >#>O>M6a׮]x/=j>G|HvIpE"3-))PQao^~۬YdѠ VMߠgql B ֨>ShʷY R1_>\.gd Zq}v$&&x}HJJ‘#G돮.DDDСCqG~Yw#P)R&j NVAP枻Y#|P{Y5w>N) T7T)AiE)^psf[ O~ع8q( )= 'p*åVB~:+N˽HklA`||9twlTBkl&"yk2FGKLŶvvK~/@0`;$]@o_/B-ojnh4X>>Xt%$E| _xxxzHV FxT8<.]f<5>~,iV44Fp}N6NPp}x?  yٖUYjjj2؟ZfNYxhۆhV5ӈw_wHsu(E↢en~YU-S  ٞU3?2/RbcF& &s9#:`oooXE`@ MFX!![wR߁sqgg#_tW5}ZU 7{ &P[3MÀ{Xei)bFa-ƙ{] kkkbz{/%ꑟoU] mK즿]7af 999ӎL@nf.Ye<ǏPaa!X5\dq2k1upr}ܭ1܌4VYn lWaC889wbܕ+W3SSS*P]]mL7o`ժU+t3 My<UUUP-fOK\vYOOOʐ0L`^O55e*nݺ}ZcdO5x7 p@f6_S ML ذa.Xla]Kqc{1Xl9.ܨbV 3=izR Γu Dh D(0 B D(0 B }IENDB`orafce-VERSION_3_9_0/doc/sql_migration/sql_migration00.md000066400000000000000000000023431362147214200233040ustar00rootroot00000000000000Oracle to PostgreSQL Migration Guide === Preface --- **Purpose of This Document** This document explains the actions required for migrating an Oracle database to PostgreSQL and provides notes on migration. **Intended Readers** This guide is intended for persons engaged in migrating an Oracle database to PostgreSQL. The reader is assumed to have general knowledge of the following: - PostgreSQL - Oracle database - SQL - Linux **Structure of This Document** The organization and contents of this guide are as follows: **Chapter 1 Pre-Migration Configuration** Explains the PostgreSQL settings that must be configured before migration. **Chapter 2 Migrating Syntax Elements** Explains how to migrate SQL syntax elements. **Chapter 3 Migrating Functions** Explains how to migrate SQL functions. **Chapter 4 Migrating SQL Statements** Explains how to migrate SQL statements. **Chapter 5 Migrating PL/SQL** Explains how to migrate PL/SQL. **Chapter 6 Notes on Using orafce** Provides notes on using Oracle database compatibility features added by orafce. **Appendix A Correspondence with Oracle Databases** Explains the correspondence between PostgreSQL and Oracle databases. **Version** Edition 1.0: February 2017 orafce-VERSION_3_9_0/doc/sql_migration/sql_migration01.md000066400000000000000000000423701362147214200233110ustar00rootroot00000000000000Chapter 1 Pre-Migration Configuration ---- This chapter explains the environment settings that must be configured before migration of an Oracle database. **Note** ---- - In this migration guide, the migration source Oracle database and the migration target PostgreSQL are targeted to be the versions listed below. - Oracle Database 12c - PostgreSQL 9.5 - After migration, verify operation and confirm that the data was migrated successfully by checking if the intended result is obtained. ---- ### 1.1 Setting the Server Parameter This section explains the server parameter required for matching the behavior of PostgreSQL with the behavior of the Oracle database. Set the parameter in postgresql.conf so that the database always operates in the same way from all clients. The following table shows the server parameter explained here. |Server parameter|Description| |:---|:---| |search_path|Specifies the sequence in which schemas are searched.| **Note** ---- - The server parameter setting does not need to be changed. Change it only as required. - The explanations in Chapter 2 and following assume that the server parameter has been set. ---- #### 1.1.1 search_path Functions added by orafce, which provides features for Oracle database compatibility, are defined as user-defined functions in the "public" schema that is created by default when a database cluster is created. This enables all users to be able to use these functions without having to configure any particular settings. Therefore, when using the search_path parameter to specify a schema search path, you must include "public". Some data types and functions added by orafce are implemented with different external specifications in PostgreSQL and orafce. By default, the PostgreSQL external specifications have priority. To implement these data types and functions in line with the orafce external specifications, specify "oracle" and "pg_catalog" in the search_path parameter of postgresql.conf. You must place "oracle" before "pg_catalog". - Before (default) ~~~ search_path = '"$user", public' ~~~ - After ~~~ search_path = '"$user", public, oracle, pg_catalog' ~~~ **See** ---- Refer to Orafce Docmentation for information on features implemented with different external specifications in PostgreSQL and orafce. ---- ### 1.2 Example Databases This section uses the examples of an inventory management database for a particular retail store, and a staff management database for a particular company. The explanations of data operation provided in this manual are based on these example databases. #### 1.2.1 Inventory Management Database ##### 1.2.1.1 Contents of Database Definitions This database manages inventory in a retail store. It consists of the following three tables: - inventory_table - This table contains information on the products being handled and their inventory quantities. - ordering_table - This table contains information on the products supplied by each supplier, their ordering quantities, and their purchase prices. - company_table - This table contains the company name, telephone number, and address of each supply company. **inventory_table** The inventory table consists of the following four columns: - i_number (product number) - Code assigned to the product - i_name (category) - Category of the product - i_quantity (inventory quantity) - Inventory quantity of the product - i_warehouse (warehouse number) - Code of the warehouse where the product is stored The contents of the inventory table are shown in "inventory_table". - ordering_table (ordering table) - The ordering table consists of the following five columns: - o_code (supplier) - Company code of the supplier - o_number (supplied product) - Code assigned to the product - o_price (purchase price) - Purchase price of the product - o_quantity (ordering quantity) - Number of products ordered - o_order_date (order date) - Product order date The contents of the ordering table are shown in "ordering_table". - company_table (company table) - The company table consists of the following four columns: - c_code (company code) - Code assigned to the company - c_name (company name) - Name of the company - c_telephone (telephone number) - Telephone number of the company - c_address (address) - Address of the company The contents of the company table are shown in "company_table". Where the table names and column names described above are used in this guide, such as in example SQL statements, unless otherwise stated, the tables and columns listed in "Contents of the inventory management database" are specified. Note that the data shown in this table is fictitious. **Contents of the inventory management database** a) inventory_table | i_number
(product number) | i_name
(category) | i_quantity
(inventory quantity) | i_warehouse
(warehouse number) | | :---: | :--- | :---: | :---: |SMALLINT
PRIMARY KEY|VARCHAR(20)
NOT NULL|INTEGER |SMALLINT | | 110 | television | 85 | 2 | | 111 | television | 90 | 2 | | 123 | refrigerator | 60 | 1 | | 124 | refrigerator | 75 | 1 | | 140 | cd player | 120 | 2 | | 212 | television | 0 | 2 | | 215 | video | 5 | 2 | | 226 | refrigerator | 8 | 1 | | 227 | refrigerator | 15 | 1 | | 240 | cd player | 25 | 2 | | 243 | cd player | 14 | 2 | | 351 | cd | 2500 | 2 | b) ordering_table | o_code
(supplier) | o_number
(supplied product) | o_price
(purchase price) | o_quantity
(ordering quantity) | o_order_date
(order date) | | :---: | :---: | :---: | :---: | :---: | | SMALLINT
NOT NULL | SMALLINT
NOT NULL | INTEGER | SMALLINT | DATE | | 61 | 123 | 48000 | 60 | 42557 | | 61 | 124 | 64000 | 40 | 42557 | | 61 | 140 | 8000 | 80 | 42557 | | 61 | 215 | 240000 | 10 | 42557 | | 61 | 240 | 80000 | 20 | 42557 | | 62 | 110 | 37500 | 120 | 42557 | | 62 | 226 | 112500 | 20 | 42557 | | 62 | 351 | 375 | 800 | 42557 | | 63 | 111 | 57400 | 80 | 42557 | | 63 | 212 | 205000 | 30 | 42557 | | 63 | 215 | 246000 | 10 | 42557 | | 71 | 140 | 7800 | 50 | 42557 | | 71 | 351 | 390 | 600 | 42557 | | 72 | 140 | 7000 | 70 | 42557 | | 72 | 215 | 210000 | 10 | 42557 | | 72 | 226 | 105000 | 20 | 42557 | | 72 | 243 | 84000 | 10 | 42557 | | 72 | 351 | 350 | 1000 | 42557 | | 74 | 110 | 39000 | 120 | 42557 | | 74 | 111 | 54000 | 120 | 42557 | | 74 | 226 | 117000 | 20 | 42557 | | 74 | 227 | 140400 | 10 | 42557 | | 74 | 351 | 390 | 700 | 42557 | c) company_table | c_code
(company code) | c_name
(company name) | c_telephone
(telephone number) | c_address
(address) | | :---: | :--- | :---: | :---| | SMALLINT
NOT NULL | VARCHAR(20)
NOT NULL | VARCHAR(12) | VARCHAR(50)| | 61 | Adam Electric | 111-777-4444 | 7-8-9, Shin-Kamata, Oda Ward, Tokyo| | 62 | Idea Corporation | 222-888-5555 | 1-2-3, Asahi Ward, Obama City, Kanagawa| | 63 | Fullmoon Industry | 333-999-6666 | 1-1-1, Osaki, Urawa Town, Saitama| | 71 | Stream Electric | 444-111-7777 | 4-5-6, Akasakadai, Sakaida City, Osaka| | 72 | Tornado Industry | 555-222-8888 | 2-3-7, Higashi-Yodogawa, Nada Town, Osaka| | 74 | First Corporation | 666-333-9999 | 4-16-16, Naka City, Kyoto| ##### 1.2.1.2 Relationship Between the Tables "Relationship between the tables" shows how the tables are related with one another. The inventory table and the ordering table are related by means of the product number and the supplied product. The ordering table and the company table are related by means of the supplier and the company code. For example, the product identified by the product number "123" in the inventory table has the category "refrigerator" and the inventory quantity "60", and is stored in the warehouse identified by the code "1". Then, the row containing the supplied product "123" in the ordering table shows that the purchase price of the product is "48000" and the ordering quantity is ""60". Furthermore, the company code of the supplier can be confirmed as "61", and the row containing the company code "61" in the company table shows the name, telephone number, and address of the company that supplies the product. **Relationship between the tables** ![REL1](gif/Inventory_Management_Database.gif) ##### 1.2.1.3 Example Database Definitions The following example shows table definitions for the inventory management database. ~~~ CREATE TABLE inventory_table ( i_number SMALLINT PRIMARY KEY, i_name VARCHAR(20) NOT NULL, i_quantity INTEGER, i_warehouse SMALLINT ); CREATE TABLE ordering_table ( o_code SMALLINT NOT NULL, o_number SMALLINT NOT NULL, o_price INTEGER, o_quantity SMALLINT, o_order_date DATE ); CREATE TABLE company_table ( c_code SMALLINT NOT NULL, c_name VARCHAR(20) NOT NULL, c_telephone VARCHAR(12), c_address VARCHAR(50) ); INSERT INTO inventory_table VALUES (110, 'television', 85, 2); INSERT INTO inventory_table VALUES (111, 'television', 90, 2); INSERT INTO inventory_table VALUES (123, 'refrigerator', 60, 1); INSERT INTO inventory_table VALUES (124, 'refrigerator', 75, 1); INSERT INTO inventory_table VALUES (140, 'cd player', 120, 2); INSERT INTO inventory_table VALUES (212, 'television', 0, 2); INSERT INTO inventory_table VALUES (215, 'video', 5, 2); INSERT INTO inventory_table VALUES (226, 'refrigerator', 8, 1); INSERT INTO inventory_table VALUES (227, 'refrigerator', 15, 1); INSERT INTO inventory_table VALUES (240, 'cd player', 25, 2); INSERT INTO inventory_table VALUES (243, 'cd player', 14, 2); INSERT INTO inventory_table VALUES (351, 'cd', 2500, 2); INSERT INTO ordering_table VALUES (61, 123, 48000, 60, DATE'2016-07-06'); INSERT INTO ordering_table VALUES (61, 124, 64000, 40, DATE'2016-07-06'); INSERT INTO ordering_table VALUES (61, 140, 8000, 80, DATE'2016-07-06'); INSERT INTO ordering_table VALUES (61, 215, 240000, 10, DATE'2016-07-06'); INSERT INTO ordering_table VALUES (61, 240, 80000, 20, DATE'2016-07-06'); INSERT INTO ordering_table VALUES (62, 110, 37500, 120, DATE'2016-07-06'); INSERT INTO ordering_table VALUES (62, 226, 112500, 20, DATE'2016-07-06'); INSERT INTO ordering_table VALUES (62, 351, 375, 800, DATE'2016-07-06'); INSERT INTO ordering_table VALUES (63, 111, 57400, 80, DATE'2016-07-06'); INSERT INTO ordering_table VALUES (63, 212, 205000, 30, DATE'2016-07-06'); INSERT INTO ordering_table VALUES (63, 215, 246000, 10, DATE'2016-07-06'); INSERT INTO ordering_table VALUES (71, 140, 7800, 50, DATE'2016-07-06'); INSERT INTO ordering_table VALUES (71, 351, 390, 600, DATE'2016-07-06'); INSERT INTO ordering_table VALUES (72, 140, 7000, 70, DATE'2016-07-06'); INSERT INTO ordering_table VALUES (72, 215, 210000, 10, DATE'2016-07-06'); INSERT INTO ordering_table VALUES (72, 226, 105000, 20, DATE'2016-07-06'); INSERT INTO ordering_table VALUES (72, 243, 84000, 10, DATE'2016-07-06'); INSERT INTO ordering_table VALUES (72, 351, 350, 1000, DATE'2016-07-06'); INSERT INTO ordering_table VALUES (74, 110, 39000, 120, DATE'2016-07-06'); INSERT INTO ordering_table VALUES (74, 111, 54000, 120, DATE'2016-07-06'); INSERT INTO ordering_table VALUES (74, 226, 117000, 20, DATE'2016-07-06'); INSERT INTO ordering_table VALUES (74, 227, 140400, 10, DATE'2016-07-06'); INSERT INTO ordering_table VALUES (74, 351, 390, 700, DATE'2016-07-06'); INSERT INTO company_table VALUES (61, 'Adam Electric', '111-777-4444', '7-8-9, Shin-Kamata, Oda Ward, Tokyo'); INSERT INTO company_table VALUES (62, 'Idea Corporation', '222-888-5555', '1-2-3, Asahi Ward, Obama City, Kanagawa'); INSERT INTO company_table VALUES (63, 'Fullmoon Industry', '333-999-6666', '1-1-1, Osaki, Urawa Town, Saitama'); INSERT INTO company_table VALUES (71, 'Stream Electric', '444-111-7777', '4-5-6, Akasakadai, Sakaida City, Osaka'); INSERT INTO company_table VALUES (72, 'Tornado Industry', '555-222-8888', '2-3-7, Higashi-Yodogawa, Nada Town, Osaka'); INSERT INTO company_table VALUES (74, 'First Corporation', '666-333-9999', '4-16-16, Naka City, Kyoto'); ~~~ #### 1.2.2 Staff Management Database ##### 1.2.2.1 Contents of Database Definitions This database manages the staff of the company. It consists of the following two tables: - staff_table (staff table) - This table contains the name, position, age, and manager of each staff member. - attendance_table (attendance management table) - This table contains the attendance time of each staff member. **staff_table** The staff table consists of the following five columns: - staff_id (staff identification number) - Code assigned to the staff member - name (name of the staff member) - Name of the staff member - job (position) - Position title of the staff member - age (age) - Age of the staff member - manager_id (staff identification number of manager) - Code assigned to the manager of the staff member The contents of the staff table are shown in "staff_table". **attendance_table** The attendance management table consists of the following three columns: - staff_id (staff identification number) - Code assigned to the staff member - work_flag (attendance flag) - Flag indicating whether the staff member is present or absent - attendance_time (attendance time) - Work starting and ending times of the staff member The contents of the attendance management table are shown in "attendance_table". Where the table names and column names described above are used in this guide, such as in example SQL statements, unless otherwise stated, the tables and columns listed in "Contents of the staff management database" are specified. Note that the data shown in this table is fictitious. **Contents of the staff management database** a) staff_table | staff_id
(staff ID number) | name
(name of the staff member) | job
(position) | age
(age) | manager_id
(staff ID number of manager) | |:---:|:---|:---|:---:|:---:| |CHAR(4)|VARCHAR(20)|VARCHAR(30)|INTEGER|CHAR(4)| | 1001 | tokyo taro | president | 68 |\| | 2001 | oosaka jiro | sales manager | 48 | 1001 | | 3001 | hyogo akihiko | sales member | 28 | 2001 | | 3002 | mie megumi | sales member | 31 | 2001 | | 3003 | hirosima taro | sales member | 36 | 2001 | | 3004 | nagano motoko | sales member | 40 | 2001 | | 3005 | akita taro | sales member | 25 | 2001 | | 2002 | hukuoka saburo | accounting manager | 52 | 1001 | | 4001 | nagasaki rokuro | accounting member | 39 | 2002 | | 2003 | kyoto hanako | general affairs manager | 43 | 1001 | | 5001 | okayama reiko | general affairs member | 33 | 2003 | | 5002 | kagawa shiro | general affairs member | 27 | 2003 | | 5003 | okinawa takao | general affairs member | 30 | 2003 | | 5004 | miyagi kenta | \ | 23 | 2003 | | 5005 | aichi yui | ''(null) | 23 | 2003 | b) attendance_table | staff_id
(staff ID number) | work_flag
(attendance flag) | attendance_time
(attendance time) | | :--- | :--- | :--- | | CHAR(4) | CHAR(1) | TIMESTAMP WITH TIME ZONE | | 1001 | i | 2016-07-06 08:00:00+09 | | 3001 | i | 2016-07-06 08:30:00+09 | | 1001 | o | 2016-07-06 17:30:00+09 | | 3001 | o | 2016-07-06 18:00:00+09 | ##### 1.2.2.2 Relationship Between the Tables "Relationship between the tables" shows how the tables are related with one another. The staff table and the attendance management table are related by means of the staff identification number. **Relationship between the tables** ![REL2](gif/Staff_Management_Database.gif) ##### 1.2.2.3 Example Database Definitions The following example shows table definitions for the staff management database. ~~~ CREATE TABLE staff_table ( staff_id CHAR(4), name VARCHAR(20), job VARCHAR(30), age INTEGER, manager_id CHAR(4) ); CREATE TABLE attendance_table ( staff_id CHAR(4), work_flag CHAR(1), attendance_time TIMESTAMP WITH TIME ZONE ); INSERT INTO staff_table VALUES ('1001', 'tokyo taro', 'president', 68, NULL); INSERT INTO staff_table VALUES ('2001', 'oosaka jiro', 'sales manager', 48, '1001'); INSERT INTO staff_table VALUES ('3001', 'hyogo akihiko', 'sales member', 28, '2001'); INSERT INTO staff_table VALUES ('3002', 'mie megumi', 'sales member', 31, '2001'); INSERT INTO staff_table VALUES ('3003', 'hirosima taro', 'sales member', 36, '2001'); INSERT INTO staff_table VALUES ('3004', 'nagano motoko', 'sales member', 40, '2001'); INSERT INTO staff_table VALUES ('3005', 'akita taro', 'sales member', 25, '2001'); INSERT INTO staff_table VALUES ('2002', 'hukuoka saburo', 'accounting manager', 52, '1001'); INSERT INTO staff_table VALUES ('4001', 'nagasaki rokuro', 'accounting member', 39, '2002'); INSERT INTO staff_table VALUES ('2003', 'kyoto hanako', 'general affairs manager', 43, '1001'); INSERT INTO staff_table VALUES ('5001', 'okayama reiko', 'general affairs member', 33, '2003'); INSERT INTO staff_table VALUES ('5002', 'kagawa shiro', 'general affairs member', 27, '2003'); INSERT INTO staff_table VALUES ('5003', 'okinawa takao', 'general affairs member', 30, '2003'); INSERT INTO staff_table VALUES ('5004', 'miyagi kenta', NULL, 23, '2003'); INSERT INTO staff_table VALUES ('5005', 'aichi yui', '', 23, '2003'); INSERT INTO attendance_table VALUES ('1001', 'i', TIMESTAMP WITH TIME ZONE'2016-07-06 08:00:00+09:00'); INSERT INTO attendance_table VALUES ('3001', 'i', TIMESTAMP WITH TIME ZONE'2016-07-06 08:30:00+09:00'); INSERT INTO attendance_table VALUES ('1001', 'o', TIMESTAMP WITH TIME ZONE'2016-07-06 17:30:00+09:00'); INSERT INTO attendance_table VALUES ('3001', 'o', TIMESTAMP WITH TIME ZONE'2016-07-06 18:00:00+09:00'); ~~~orafce-VERSION_3_9_0/doc/sql_migration/sql_migration02.md000066400000000000000000000525411362147214200233130ustar00rootroot00000000000000Chapter 2 Migrating Syntax Elements --- This chapter explains how to migrate SQL syntax elements. ### 2.1 Basic Elements This section explains the basic elements of SQL syntax. #### 2.1.1 TIMESTAMP Literal **Description** A literal with the TIMESTAMP prefix is treated as TIMESTAMP type data. **Functional differences** - **Oracle database** - The TIMESTAMP prefix can signify a time zone literal. - **PostgreSQL** - The TIMESTAMP WITH TIME ZONE prefix signifies a time zone literal. If the prefix is TIMESTAMP only, the time zone value is discarded. No warning, error, or other notification is output. **Migration procedure** Use the following procedure to perform migration: 1. Search for the keyword TIMESTAMP and identify where it is used as a literal prefix. 2. If a time zone has been specified for the literal, change the prefix to TIMESTAMP WITH TIME ZONE. **Migration example** The example below shows how to migrate a TIMESTAMP literal with time zone.
Oracle database PostgreSQL
INSERT INTO attendance_table 
 VALUES( '1001', 
 'i', 
 TIMESTAMP'2016-05-20 12:30:00 +09:00' );
INSERT INTO attendance_table 
 VALUES( '1001',
         'i',
 TIMESTAMP WITH TIME ZONE'2016-05-20 12:30:00 +09:00' );
#### 2.1.2 Alternate Quotation Literal **Description** Using alternate quotation enables a delimiter to be used for a text string. **Functional differences** - **Oracle database** - The alternate quotation marks q'x and x' are used. The letter x represents the alternate character. - **PostgreSQL** - The alternate quotation marks $q$ and $q$ are used. **Migration procedure** Use the following procedure to perform migration: 1. Search for the keyword q' or Q' and identify where alternate quotation marks are used. 2. Delete alternate characters and single quotation marks where alternate quotation has been used, and enclose strings with $q$. The character between the two $ symbols can be omitted or any string can be specified. **Migration example** The example below shows how to migrate alternate quotation.
Oracle database PostgreSQL
SELECT q'[Adam Electric company's address]' 
 FROM DUAL;
SELECT $q$Adam Electric company's address$q$ 
 FROM DUAL;
**See** ---- Refer to "The SQL Language" > "Lexical Structure" > "Dollar-quoted String Constants" in the PostgreSQL Documentation for information on alternate quotation marks. ---- ### 2.2 Data Types This section explains data types. #### 2.2.1 Migrating Data Types The table below lists the PostgreSQL data types that correspond to Oracle database data types. **Data type correspondence** - **Character** |Oracle database Data type |Remarks |Migratability |PostgreSQL Data type |Remarks | | :--- | :--- | :---: | :--- | :--- | | CHAR
CHARACTER | Specifies the number of bytes or number of characters. | YR | char
character | Only the number of characters can be specified. | | CLOB
CHAR LARGE OBJECT
CHARACTER LARGE OBJECT | | MR | text
Large object | Up to 1 GB(text)
Up to 4 TB(Large object) | | CHAR VARYING
CHARACTER VARYING
VARCHAR | Specifies the number of bytes or number of characters. | YR | char varying
character varying
varchar | Only the number of characters can be specified. LONG MR text Up to 1 GB M Large object | NCHAR
NATIONAL CHAR
NATIONAL CHARACTER | | YR | nchar
national char
national character | This data type is internally used as a character type. | | NCHAR VARYING
NATIONAL CHAR VARYING
NATIONAL CHARACTER VARYING | | YR | nchar varying
national char varying
national character varying | This data type is internally used as a character varying type | | NCLOB
NCHAR LARGE OBJECT
NATIONAL CHARACTER LARGE OBJECT | | MR | text
Large object | Up to 1 GB(text)
Up to 4 TB(Large object) NVARCHAR2 YR nvarchar2 Collating sequence is not supported.
This data type is added using orafce. MR nchar varying
national char varying
national character varying This data type is internally used as a character varying type. VARCHAR2 Specifies the number of bytes or number of characters. YR varchar2 Only the number of bytes can be specified.
Collating sequence is not supported.
This data type is added using orafce. MR varchar Only the number of characters can be specified. - **Numeric** |Oracle database Data type |Remarks |Migratability |PostgreSQL Data type |Remarks | | :--- | :--- | :---: | :--- | :--- | | BINARY_DOUBLE | | M | double precision | | | BINARY_FLOAT | | M | real | | | DOUBLE PRECISION | | Y | double precision | | | FLOAT | | Y | float | | | INT
INTEGER | | Y | int
integer | | | NUMBER
DEC
DECIMAL
NUMERIC | Specifies numbers rounded according to the scale definition. | MR | smallint
integer
bigint
numeric | Integers from -32,768 to +32,767 (smallint)
Integers from -2,147,483,648 to +2,147,483,647 (integer)
Integers from -9,223,372,036,854,775,808 to +9,223,372,036,854,775,807(bigint) | | REAL | | Y | real | | | SMALLINT | | Y | smallint | | - **Date and time** |Oracle database Data type |Remarks |Migratability |PostgreSQL Data type |Remarks | | :--- | :--- | :---: | :--- | :--- | | INTERVAL DAY TO SECOND | | Y | interval day to second | | | INTERVAL YEAR TO MONTH | | Y | interval year to month | | | TIMESTAMP | | Y | timestamp | | | TIMESTAMP WITH LOCAL TIME ZONE | | M | timestamp with time zone | | | TIMESTAMP WITH TIME ZONE | | Y | timestamp with time zone | DATE Y date (orafce) The time can be stored in addition to the date.
The search_path parameter must be specified. YR date (PostgreSQL) Only the date is stored. M timestamp - **Binary** |Oracle database Data type |Remarks |Migratability |PostgreSQL Data type |Remarks | | :--- | :--- | :---: | :--- | :--- | | BFILE | | MR | bytea
Large object | Up to 1 GB (bytea)
Up to 4 TB(Large object) | | BLOB
BINARY LARGE OBJECT | | MR | bytea
Large object | Up to 1 GB (bytea)
Up to 4 TB(Large object) | | LONG RAW | | MR | bytea
Large object | Up to 1 GB (bytea)
Up to 4 TB(Large object) | | RAW | | M | bytea | | | ROWID | | M | oid | | UROWID | | N | | | - **Other** |Oracle database Data type |Remarks |Migratability |PostgreSQL Data type |Remarks | | :--- | :--- | :---: | :--- | :--- | | ANYDATA | | N | | | | ANYDATASET | | N | | | | ANYTYPE | | N | | | | DBUriType | | N | | | | HTTPUriType | | N | | | | MLSLABEL | | N | | | | ORDAudio | | N | | | | ORDDicom | | N | | | | ORDDoc | | N | | | | ORDImage | | N | | | | ORDVideo | | N | | | | REF data type | | N | | | | SDO_GEOMETRY | | N | | | | SDO_GEORASTER | | N | | | | SDO_TOPO_GEOMETRY | | N | | | | SI_AverageColor | | N | | | | SI_Color | | N | | | | SI_ColorHistogram | | N | | | | SI_FeatureList | | N | | | | SI_PositionalColor | | N | | | | SI_StillImage | | N | | | | SI_Texture | | N | | | | URIFactory package | | N | | | | URIType | | N | | | | VARRAY | | M | Array type | | | XDBUriType | | N | | | | XMLType | | M | XML type | | | Object type | | N | | | | Nested table | | N | | | Y: Data type can be migrated as is M: Modified data type can be migrated N: Cannot be migrated YR: Data type can be migrated as is with restrictions MR: Modified data type can be migrated with restrictions #### 2.2.2 Examples of Migrating Data Types ##### 2.2.2.1 Examples of Migrating General Data Types **Description of migration** Refer to "Data type correspondence" and change Oracle database data types to PostgreSQL data types. **Migration example**
Oracle database PostgreSQL
CREATE TABLE t1( col1 SMALLINT, 
                 col2 VARCHAR2(10), 
                 col3 NVARCHAR2(10), 
                 col4 DATE, 
                 col5 NUMBER(10), 
                 col6 RAW(2000), 
                 col7 BLOB ); 
CREATE TABLE t1( col1 SMALLINT, 
                 col2 VARCHAR(10), 
                 col3 NCHAR VARYING(10), 
                 col4 TIMESTAMP, 
                 col5 INTEGER, 
                 col6 BYTEA, 
                 col7 BYTEA );
##### 2.2.2.2 NUMBER Type **Functional differences** - **Oracle database** - A negative value can be specified in a NUMBER type scale.
Any value that is specified in a scale beyond the number of significant digits is rounded off. - **PostgreSQL** - A negative value cannot be specified in a NUMERIC type scale.
Any value that is specified in a scale beyond the number of significant digits is discarded. **Migration procedure** Use the following procedure to perform migration: 1. Change DECIMAL scales to 0, and add the number of changed digits to the precision. 2. Create a function that uses the ROUND function to round off the column that was changed in Step (1) above. 3. Create a trigger that executes the function created in Step (2) above when the INSERT statement and UPDATE statement are executed. **Migration example** The example below shows how to migrate the NUMBER type.
Oracle database PostgreSQL
CREATE TABLE t1( col1 SMALLINT, 
                 col2 NUMBER(10,-2) ); 











INSERT INTO t1 VALUES( 11, 1234567890 ); SELECT * FROM t1;
 CREATE TABLE t1( col1 SMALLINT, 
                  col2 NUMERIC(12,0) ); 

CREATE FUNCTION f1() RETURNS TRIGGER AS $$ BEGIN NEW.col2 := ROUND(NEW.col2,-2); RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TRIGGER g1 BEFORE INSERT OR UPDATE ON t1 FOR EACH ROW EXECUTE PROCEDURE f1();
INSERT INTO t1 VALUES( 11, 1234567890 ); SELECT * FROM t1;
### 2.3 Pseudocolumns This section explains pseudocolumns. #### 2.3.1 CURRVAL **Description** CURRVAL returns the value nearest to that obtained by NEXTVAL from the sequence in the current session. **Functional differences** - **Oracle database** - The sequence name is specified as sequenceName.CURRVAL. - **PostgreSQL** - The sequence name is specified as CURRVAL('sequenceName'). **Migration procedure** Use the following procedure to perform migration: 1. Search for the keyword CURRVAL and identify where it is used. 2. Change the sequence name specification by placing it after CURRVAL and enclosing it in parentheses and single quotation marks. **Migration example** The example below shows how to migrate CURRVAL.
Oracle database PostgreSQL
SELECT seq1.CURRVAL FROM DUAL;
SELECT CURRVAL('seq1') FROM DUAL;
#### 2.3.2 NEXTVAL **Description** NEXTVAL returns the next number in the sequence. **Functional differences** - **Oracle database** - The sequence name is specified as sequenceName.NEXTVAL. - **PostgreSQL** - The sequence name is specified as NEXTVAL('sequenceName'). **Migration procedure** Use the following procedure to perform migration: 1. Search for the keyword NEXTVAL and identify where it is used. 2. Change the sequence name specification by placing it after NEXTVAL and enclosing it in parentheses and single quotation marks. **Migration example** The example below shows how to migrate NEXTVAL.
Oracle database PostgreSQL
SELECT seq1.NEXTVAL FROM DUAL;
SELECT NEXTVAL('seq1') FROM DUAL;
#### 2.3.3 ROWID **Description** ROWID obtains information for uniquely identifying data. **Functional differences** - **Oracle database** - ROWID is created automatically when a table is created. - **PostgreSQL** - ROWID cannot be used. Use OID instead. However, WITH OIDS must be specified when a table is created. **Migration procedure** Use the following procedure to perform migration: 1. Specify WITH OIDS at the end of the CREATE TABLE statement. 2. Change the ROWID extraction item in the SELECT statement to OID. **Migration example**
Oracle database PostgreSQL
 CREATE TABLE t1( col1 INTEGER ); 

INSERT INTO t1 VALUES( 11 ); SELECT ROWID, col1 FROM t1;
 CREATE TABLE t1( col1 INTEGER ) WITH OIDS; 

INSERT INTO t1 VALUES( 11 ); SELECT OID, col1 FROM t1;
#### 2.3.4 ROWNUM **Description** ROWNUM obtains the number of the current row. ##### 2.3.4.1 Obtaining the Row Number **Functional differences** - **Oracle database** - ROWNUM obtains the number of the current row. - **PostgreSQL** - ROWNUM cannot be used. Use ROW_NUMBER() OVER() instead. **Migration procedure** Using the ROW_NUMBER() function instead of ROWNUM, perform migration so that the current number is obtained. Use the following procedure to perform migration: 1. Search for the keyword ROWNUM and identify where it is used. 2. Change ROWNUM to ROW_NUMBER() OVER(). **Migration example** The example below shows migration when a line number is obtained.
Oracle database PostgreSQL
SELECT ROWNUM, i_number, i_name 
 FROM inventory_table;
SELECT ROW_NUMBER() OVER(), i_number, i_name 
 FROM inventory_table; 
**Note** ---- This migration example cannot be used with the UPDATE statement. ---- ##### 2.3.4.2 Sorting Records and Obtaining the First N Records **Functional differences** - **Oracle database** - If a subquery that contains an ORDER BY clause is specified in the FROM clause and a ROWNUM condition is defined in the WHERE clause, the records are sorted and then the first N records are obtained. - **PostgreSQL** - ROWNUM cannot be used. Using the LIMIT clause instead, sort the records and obtain the first N records. **Migration procedure** Use the following procedure to perform migration: 1. Search for the keyword ROWNUM and identify where it is used. 2. If an ORDER BY clause is specified in a subquery of the FROM clause and the results are filtered according to the ROWNUM condition in the WHERE clause, regard this portion as an SQL statement that sorts the records and then obtains the first N records. 3. Move the table name and ORDER BY clause from the FROM clause subquery to a higher SELECT statement and delete the subquery. 4. In the LIMIT clause, set the same number as the ROWNUM condition of the WHERE clause, and delete the ROWNUM condition from the WHERE clause. **Migration example** The example below shows migration when records are sorted and then the first N records are obtained.
Oracle database PostgreSQL
SELECT i_number, i_name 
 FROM ( SELECT * FROM inventory_table 
 ORDER BY i_number DESC ) 
 WHERE ROWNUM < 5;
SELECT i_number, i_name  
 FROM inventory_table 
 ORDER BY i_number DESC LIMIT 4; 
### 2.4 Treatment of NULL and Zero-Length Strings This section explains how NULL and zero-length strings are treated. Oracle databases treat zero-length strings as NULL. In contrast, PostgreSQL treats zero-length strings and NULL as two different values. The table below lists the advantages and disadvantages of using zero-length strings and NULL when performing migration. **Advantages and disadvantages of retaining or migrating Oracle database zero-length strings** |Oracle database zero-length strings |Advantages |Disadvantages | |:---|:---|:---| |Treated as zero-length strings
without being migrated to NULL | String concatenation (||) can be used as is. | The target data has fewer hits than with IS NULL.
Conditional expressions must be changed. | | Migrated to NULL | IS NULL can be used as is. | The result of string concatenation (||) is NULL.
String concatenation must be changed. | The following sections explain how to make changes if zero-length strings and NULL values are used together. #### 2.4.1 Search Conditions (IS NULL Predicate) **Functional differences** - **Oracle database** - Even zero-length strings hit the IS NULL condition. - **PostgreSQL** - Zero-length strings do not hit the IS NULL condition. **Migration procedure** Use the following procedure to perform migration: 1. Search for the keyword IS NULL and identify where a NULL search is used. 2. Change the portions found by the IS NULL search to IS NULL OR strName = ''. **Migration example** The example below shows migration when a search for zero-length strings and NULL values is performed.
Oracle database PostgreSQL
SELECT * FROM staff_table 
 WHERE job IS NULL;
SELECT * FROM staff_table 
 WHERE job IS NULL OR job = '';
The example below shows migration when a search for values other than zero-length strings and NULL values is performed.
Oracle database PostgreSQL
SELECT * FROM staff_table 
 WHERE job IS NOT NULL;
SELECT * FROM staff_table 
 WHERE job IS NOT NULL AND job != '';
#### 2.4.2 Search Conditions (Comparison Predicate) **Functional differences** - **Oracle database** - Zero-length strings are treated as NULL, so they do not match search conditions. - **PostgreSQL** - Zero-length strings are not treated as NULL, so they can match search conditions. **Migration procedure** Use the following procedure to perform migration: 1. Search for the name of the column where the zero-length string is stored, and identify where a string comparison is used. 2. Add AND columnName != '' to the search condition. **Migration example** The example below shows migration when a zero-length string comparison is specified as the search condition.
Oracle database PostgreSQL
SELECT * FROM staff_table 
 WHERE job < 'A00';
SELECT * FROM staff_table 
 WHERE job < 'A00' AND job != '';
#### 2.4.3 String Concatenation (||) **Functional differences** - **Oracle database** - Concatenation with NULL returns strings other than NULL. - **PostgreSQL** - Concatenation with NULL returns NULL. **Migration procedure** Use the following procedure to perform migration: 1. Search for the keyword || and identify where string concatenation is used. 2. If the values to be concatenated are likely to become NULL, use the NVL function to return a zero-length string instead of NULL. **Migration example** The example below shows migration when NULL is returned by string concatenation (||) in Oracle databases.
Oracle database PostgreSQL
SELECT 'NAME:' || name 
 FROM staff_table;
 SELECT 'NAME:' || NVL( name, '' ) 
  FROM staff_table;
orafce-VERSION_3_9_0/doc/sql_migration/sql_migration03.md000066400000000000000000000374561362147214200233240ustar00rootroot00000000000000Chapter 3 Migrating Functions --- This chapter explains how to migrate SQL functions. ### 3.1 CONVERT **Description** CONVERT converts a string from one character set to another. **Functional differences** - **Oracle database** - The string is converted from the character set identified in the third argument to the character set identified in the second argument. - **PostgreSQL** - The string is converted from the character set identified in the second argument to the character set identified in the third argument. **Migration procedure** Use the following procedure to perform migration: 1. Search for the keyword CONVERT and identify where it is used. 2. Switch the second and third arguments. 3. Change the character sets in the second and third arguments to names that are valid under the PostgreSQL encoding system. **Migration example** The example below shows migration when strings are changed to the character set of the target database.
Oracle database PostgreSQL
SELECT CONVERT( 'abc', 
 'JA16EUC', 
 'AL32UTF8' ) 
 FROM DUAL;
SELECT CONVERT( CAST( 'abc' AS BYTEA ), 
  'UTF8', 
 'EUC_JP' ) 
 FROM DUAL;
### 3.2 EMPTY_BLOB **Description** EMPTY_BLOB initializes BLOB type areas and creates empty data. **Functional differences** - **Oracle database** - BLOB type areas are initialized and empty data is created. - **PostgreSQL** - EMPTY_BLOB cannot be used. Instead, use a zero-length string for initialization. **Migration procedure** Use the following procedure to perform migration: 1. Search for the keyword EMPTY_BLOB() and identify where it is used. 2. Change EMPTY_BLOB() to the zero-length string ''. **Migration example** The example below shows migration when empty data is inserted into the BLOB column.
Oracle database PostgreSQL
CREATE TABLE t1( col1 INTEGER, 
 col2 BLOB ); 

INSERT INTO t1 VALUES( 11, EMPTY_BLOB() );
CREATE TABLE t1( col1 INTEGER, 
 col2 BYTEA ); 

INSERT INTO t1 VALUES( 11, '' );
The example below shows migration when BLOB column data is updated to empty.
Oracle database PostgreSQL
UPDATE t1 SET col2 = EMPTY_BLOB() WHERE col1 = 11;
UPDATE t1 SET col2 = '' WHERE col1 = 11;
### 3.3 LEAD **Description** LEAD obtains the value of the column specified in the arguments from the record that is the specified number of lines below. **Functional differences** - **Oracle database** - A NULL value in the column specified in the arguments can be excluded from the calculation. - **PostgreSQL** - A NULL value in the column specified in the arguments cannot be excluded from the calculation. **Migration procedure** Use the following procedure to perform migration: 1. Search for the keyword LEAD and identify where it is used. 2. If the IGNORE NULLS clause is specified, check the following values to create a subquery that excludes NULL values: - Arguments of LEAD (before IGNORE NULLS) - Tables targeted by IGNORE NULLS - Columns targeted by IGNORE NULLS - Columns to be sorted 3. Change the table in the FROM clause to a subquery to match the format shown below. 4. Replace LEAD in the select list with MAX. Specify LEAD_IGNLS in the arguments of MAX, and PARTITION BY CNT in the OVER clause. ~~~ FROM ( SELECT columnBeingUsed, CASE WHEN ignoreNullsTargetColumn IS NOT NULL THEN LEAD( leadFunctionArguments ) OVER( PARTITION BY NVL2( ignoreNullsTargetColumn, '0', '1' ) ORDER BY sortTargetColumn ) END AS LEAD_IGNLS, COUNT( ignoreNullsTargetColumn ) OVER( ORDER BY sortTargetColumn ROWS BETWEEN 1 FOLLOWING AND UNBOUNDED FOLLOWING ) AS CNT FROM ignoreNullsTargetTable ) AS T1; ~~~ **Migration example** The example below shows migration when NULL values are not included in the calculation of column values.
Oracle database PostgreSQL
SELECT staff_id, 
       name, 
       job, 
 LEAD( job, 1 ) IGNORE NULLS 
 OVER( ORDER BY staff_id DESC) 
 AS "LEAD_IGNORE_NULLS" 
 FROM staff_table 
 ORDER BY staff_id DESC;

















SELECT staff_id, 
       name, 
       job, 
 MAX( LEAD_IGNLS ) 
 OVER( PARTITION BY CNT ) 
 AS "LEAD_IGNORE_NULLS" 
 FROM ( SELECT staff_id, 
       name, 
       job, 
 CASE 
 WHEN job IS NOT NULL THEN 
 LEAD( job, 1 ) 
 OVER( PARTITION BY NVL2( 
       job, 
       '0', 
       '1' ) 
 ORDER BY staff_id DESC) 
 END AS LEAD_IGNLS, 
 COUNT( job ) 
 OVER( ORDER BY staff_id DESC 
  ROWS BETWEEN 1 FOLLOWING 
  AND UNBOUNDED FOLLOWING ) 
 AS CNT 
 FROM staff_table ) AS T1 
 ORDER BY staff_id DESC;
**Information** ---- If the IGNORE NULLS clause is not specified or if the RESPECT NULLS clause is specified, NULL is included in the calculation, so operation is the same as the LEAD function of PostgreSQL. Therefore, if the IGNORE NULLS clause is not specified, no changes need to be made. If the RESPECT NULLS clause is specified, delete the RESPECT NULLS clause. The example below shows migration when RESPECT NULLS is specified in the Oracle database. **LEAD migration example (when RESPECT NULLS is specified)**
Oracle database PostgreSQL
SELECT staff_id, 
       name, 
       job, 
 LEAD( job, 1 ) 
 RESPECT NULLS 
 OVER( ORDER BY staff_id DESC ) 
 AS "LEAD_RESPECT_NULLS" 
 FROM staff_table 
 ORDER BY staff_id DESC;
SELECT staff_id, 
       name, 
       job, 
 LEAD( job, 1 ) 
 OVER( ORDER BY staff_id DESC ) 
 AS "LEAD_RESPECT_NULLS" 
 FROM staff_table 
 ORDER BY staff_id DESC; 
 
---- ### 3.4 RAWTOHEX **Description** RAWTOHEX converts RAW type data to a hexadecimal string value. **Functional differences** - **Oracle database** - RAW type data is converted to a hexadecimal string value. - **PostgreSQL** - RAWTOHEX cannot be used. Instead, use ENCODE to convert binary data types corresponding to the RAW type. **Migration procedure** Use the following procedure to perform migration: 1. Search for the keyword RAWTOHEX and identify where it is used. 2. Change RAWTOHEX to ENCODE and specify HEX in the second argument. **Migration example** The example below shows migration when RAW data types are converted to hexadecimal string values.
Oracle database PostgreSQL
SELECT RAWTOHEX ( 'ABC' ) FROM DUAL;
SELECT ENCODE ( 'ABC', 'HEX' ) FROM DUAL;
**Information** ---- A RAWTOHEX function that is used in PL/SQL to take a string as an argument must first be converted to a binary data type using DECODE, and then ENCODE must be used to convert the value to a string. The example below shows migration of RAWTOHEX when it is used in PL/SQL to take a string as an argument. **ROWTOHEX migration example (when taking a string as an argument in PL/SQL)**
Oracle database PostgreSQL
SET SERVEROUTPUT ON; 

DECLARE HEX_TEXT VARCHAR2( 100 ); BEGIN HEX_TEXT := RAWTOHEX( '414243' );

DBMS_OUTPUT.PUT_LINE( HEX_TEXT ); END; /
 
 DO $$ 
 DECLARE 
 HEX_TEXT TEXT; 
 BEGIN 
 HEX_TEXT := 
 ENCODE( DECODE( '414243', 'HEX' ), 'HEX' ); 
 PERFORM DBMS_OUTPUT.SERVEROUTPUT( TRUE ); 
 PERFORM DBMS_OUTPUT.PUT_LINE( HEX_TEXT ); 
 END; 
 $$ LANGUAGE plpgsql;
---- ### 3.5 REGEXP_LIKE **Description** REGEXP_LIKE uses regular expressions to compare part of a string with a pattern to see if it matches. **Functional differences** - **Oracle database** - Regular expressions are used to compare part of a string with a pattern to see if it matches. - **PostgreSQL** - REGEXP_LIKE is not available. Use the ~ operator instead. **Migration procedure** Use the following procedure to perform migration: 1. Search for the keyword REGEXP_LIKE and identify where it is used. 2. Delete the REGEXP_LIKE keyword and parentheses. 3. Change the comma (,) to a tilde with a single space on either side ( ~ ). **Migration example** The example below shows migration when records containing names that start with 'tel' are extracted.
Oracle database PostgreSQL
SELECT i_number, i_name, i_quantity 
 FROM inventory_table 
 WHERE REGEXP_LIKE( i_name, '^tel' ) 
 ORDER BY i_number;
SELECT i_number, i_name, i_quantity 
 FROM inventory_table 
 WHERE i_name ~ '^tel' 
 ORDER BY i_number;
### 3.6 REGEXP_REPLACE **Description** REGEXP_REPLACE uses a regular expression pattern to replace a string. **Functional differences** - **Oracle database** - All strings that match the regular expression pattern are replaced. - **PostgreSQL** - The first string that matches the regular expression pattern is replaced. **Migration procedure** The REGEXP_REPLACE function of PostgreSQL can return the same result if the option string is specified in the fourth argument. Use the following procedure to perform migration: 1. Search for the keyword REGEXP_REPLACE and identify where it is used. 2. Specify the argument 'g' in the fourth argument of REGEXP_REPLACE. **Migration example** The example below shows migration when a regular expression pattern is used to convert a string.
Oracle database PostgreSQL
SELECT REGEXP_REPLACE( '2016', 
       '[0-2]', 
       '*' ) AS "REGEXP_REPLACE" 
 FROM DUAL; 
 
SELECT REGEXP_REPLACE( '2016', 
       '[0-2]', 
       '*', 
       'g' ) AS "REGEXP_REPLACE" 
 FROM DUAL;
### 3.7 REGEXP_SUBSTR **Description** REGEXP_SUBSTR extract a substring from a string using regular expression pattern matching **Functional differences** - **Oracle database** - Return the substring that match the regular expression pattern from the string. - **PostgreSQL** - REGEXP_SUBSTR is not available. **Migration procedure** The REGEXP_MATCHES combinated to the ARRAY_TO_STRING function of PostgreSQL can be used to return the same result following the different parameters of the Oracle function. Use the following procedure to perform migration: 1. Search for the keyword REGEXP_SUBSTR and identify where it is used. 2. Replace the keyword REGEXP_SUBSTR by REGEXP_MATCHES 3. Specify the argument 'g' as embedded option in the third argument of REGEXP_MATCHES to search for all occurences. 4. Use this function in the FROM clause of a SELECT ARRAY_TO_STRING() statement and limit the number of rows returned by this statement to 1 using LIMIT. 5. If the third parameter of REGEXP_SUBSTR is greater than 1 use it as the start position of the SUBSTR function called on the first argument of the REGEXP_MATCHES function. 6. If the fourth parameter is greater than 1 append a call to OFFSET with a value set to this parameter minus 1 to return the substring found at this position. 7. If there is a fifth parameter to the REGEXP_SUBSTR() function append it to 'g', the embedded regular expression option of the REGEXP_MATCHES call. **Migration example** The example below shows migration when a regular expression pattern is used to extract a string.
Oracle database PostgreSQL

SELECT
    REGEXP_SUBSTR('one two three four five ',
	'(\S*)\s') AS "REGEXP"
FROM DUAL;
Result: one
 

SELECT (
    SELECT array_to_string(a, '') AS "REGEXP"
    FROM regexp_matches('one two three four five ',
	'(\S*)\s',
	'g') AS f(a)
    LIMIT 1
);
Result: one
 

SELECT
    REGEXP_SUBSTR('one two three four five ',
	'(\S*)\s', 1, 3) AS "REGEXP"
FROM DUAL;
Result: three
 

SELECT (
    SELECT array_to_string(a, '') AS "REGEXP"
    FROM regexp_matches('one two three four five ',
	'(\S*)\s', 'g') AS f(a)
    LIMIT 1 OFFSET (3 - 1)
);
Result: three
 

SELECT
    REGEXP_SUBSTR('one two three four five ',
	'(\S*)\s', 5, 3)  AS "REGEXP"
FROM DUAL;
Result: four
 

SELECT (
    SELECT array_to_string(a, '') AS "REGEXP"
    FROM regexp_matches(substring(
		'one two three four five ',
		5
	), '(\S*)\s', 'g') AS f(a)
    LIMIT 1 OFFSET (3 - 1)
);
Result: four
 

SELECT
    REGEXP_SUBSTR('one two three four five ',
	'(\S*)\s', 1, 1, 'i')
FROM DUAL;
Result: one
 

SELECT (
    SELECT array_to_string(a, '') AS "REGEXP"
    FROM regexp_matches('one two three four five ',
	'(\S*)\s', 'gi') AS f(a)
    LIMIT 1
);
Result: one
 
### 3.8 TO_TIMESTAMP **Description** TO_TIMESTAMP converts a string value to the TIMESTAMP data type. **Functional differences** - **Oracle database** - The language to be used for returning the month and day of the week can be specified. - **PostgreSQL** - The language to be used for returning the month and day of the week cannot be specified. **Migration procedure** Use the following procedure to perform migration: 1. Search for the keyword TO_TIMESTAMP and identify where it is used. 2. If the third argument of TO_TIMESTAMP is specified, delete it. 3. If the a string in the first argument contains a national character string, it is replaced with a datetime keyword supported by PostgreSQL. **Migration example** The example below shows migration when a string value is converted to the TIMESTAMP data type. One string specifies the month in Japanese as a national character, so it is replaced with the date keyword 'JULY'.
Oracle database PostgreSQL
SELECT TO_TIMESTAMP('2016/**/21 14:15:30', 
        'YYYY/MONTH/DD HH24:MI:SS', 
        'NLS_DATE_LANGUAGE = Japanese') 
 FROM DUAL;
SELECT TO_TIMESTAMP('2016/JULY/21 14:15:30', 
        'YYYY/MONTH/DD HH24:MI:SS') 

FROM DUAL;
\*\*: The July in Japanese orafce-VERSION_3_9_0/doc/sql_migration/sql_migration04.md000066400000000000000000001311711362147214200233120ustar00rootroot00000000000000Chapter 4 Migrating SQL Statements --- This chapter explains how to migrate SQL statements. ### 4.1 Partitions This section provides examples of migrating partitions. #### 4.1.1 Partition Tables **Description** Partitions split tables and indexes into smaller units for management. The following example shows conversion of an Oracle database partition to child tables in PostgreSQL. All migration examples provided here are based on this table. **Example of tables created by partitioning inventory_table** | i_number
(product code) | i_name
(category) | i_quantity
(inventory quantity) | i_warehouse
(warehouse code) | | :---: | :--- | :---: | :---: | | SMALLINT
PRIMARY KEY | VARCHAR(20)
NOT NULL | INTEGER | SMALLINT | | 123 | refrigerator | 60 | 1 | | 124 | refrigerator | 75 | 1 | | 226 | refrigerator | 8 | 1 | | 227 | refrigerator | 15 | 1 | | 110 | television | 85 | 2 | | 111 | television | 90 | 2 | | 140 | cd player | 120 | 2 | | 212 | television | 0 | 2 | | 215 | Video | 5 | 2 | | 240 | cd player | 25 | 2 | | 243 | cd player | 14 | 2 | | 351 | Cd | 2500 | 2 | **Functional differences** - **Oracle database** - Partition tables can be created. - **PostgreSQL** - Partition tables cannot be created. **Migration procedure** Use the following procedure to perform migration: 1. Search for the keyword PARTITION and identify where CREATE TABLE is used to create a partition. 2. Delete the PARTITION clause and following lines from the CREATE TABLE statement and create a table. 3. Create a child table that inherits the table defined in step 1, and add table constraints to the split table for defining partition constraints. 4. Define a trigger or rule so that data inserted to the table is assigned to the appropriate child table. **Migration example** The example below shows migration when partitions are created in inventory_table.
Oracle database PostgreSQL
CREATE TABLE inventory_table( 
 i_number SMALLINT PRIMARY KEY, 
 i_name VARCHAR2(20) NOT NULL, 
 i_quantity INTEGER, 
 i_warehouse SMALLINT ) 
 PARTITION BY LIST ( i_warehouse ) 
 ( PARTITION inventory_table_1 VALUES (1), 
 PARTITION inventory_table_2 VALUES (2) ); 
























CREATE TABLE inventory_table( 
 i_number SMALLINT PRIMARY KEY, 
 i_name VARCHAR(20) NOT NULL, 
 i_quantity INTEGER, 
 i_warehouse SMALLINT ); 
 CREATE TABLE inventory_table_1 
 (CHECK ( i_warehouse = 1 )) 
 INHERITS( inventory_table ); 
 CREATE TABLE inventory_table_2 
 (CHECK ( i_warehouse = 2 )) 
 INHERITS( inventory_table ); 
 ------------------------------------------------- 
 CREATE FUNCTION TABLE_INSERT_TRIGGER() 
 RETURNS TRIGGER AS $$ 
 BEGIN 
   IF ( NEW.i_warehouse = 1 ) THEN 
     INSERT INTO inventory_table_1 
 VALUES( NEW.*); 
   ELSIF ( NEW.i_warehouse = 2 ) THEN 
     INSERT INTO inventory_table_2 
 VALUES( NEW.*); 
 ELSE 
   RAISE EXCEPTION 'Data out of range.  Fix the TABLE_INSERT_TRIGGER() function!'; 
   END IF; 
   RETURN NULL; 
 END; 
 $$ LANGUAGE plpgsql; 
 ------------------------------------------------- 
 CREATE TRIGGER TABLE_INSERT_TRIGGER 
 BEFORE INSERT ON inventory_table 
 FOR EACH ROW 
 EXECUTE PROCEDURE TABLE_INSERT_TRIGGER();
#### 4.1.2 PARTITION Clause in a SELECT Statement Before a PARTITION clause in a SELECT statement can be migrated, the Oracle database partition must have been converted to child tables for PostgreSQL. **Description** A PARTITION clause treats only some partitions of the table (partition table) specified in the FROM clause as the targets of a query. #### 4.1.2.1 Queries Where a PARTITION Clause is Specified **Functional differences** - **Oracle database** - A PARTITION clause can be specified. - **PostgreSQL** - A PARTITION clause cannot be specified. **Migration procedure** A PARTITION clause cannot be specified, so change the search target to a child table so that the same result is returned. Use the procedure below to perform migration. The migration sequence depends on whether a FOR clause is specified. 1. Search for the keyword PARTITION and identify where it is specified in a SELECT statement. 2. Change the table name specified in the FROM clause to the name of the child table corresponding to the partition specified in the PARTITION clause. 3. Delete the PARTITION clause. **Migration example** The example below shows migration of a query that uses PARTITION.
Oracle database PostgreSQL
SELECT * 
 FROM inventory_table PARTITION( 
 inventory_table_1);
SELECT * 
 FROM inventory_table_1; 
 
#### 4.1.2. Queries when FOR is Specified in a PARTITION Clause **Functional differences** - **Oracle database** - FOR can be specified in a PARTITION clause. - **PostgreSQL** - A PARTITION clause cannot be specified. **Migration procedure** Use the following procedure to perform migration: 1. Search for the keyword PARTITION and identify where it is specified in a SELECT statement. 2. Move the value specified in the PARTITION clause to a WHERE clause, and replace it with a conditional expression that compares the value with the column name written in the partition definition. 3. Delete the PARTITION clause. **Migration example** The example below shows migration when a PARTITION FOR clause is used to execute a query.
Oracle database PostgreSQL
SELECT * 
 FROM inventory_table PARTITION FOR (2);
SELECT * 
 FROM inventory_table WHERE i_warehouse = 2;
### 4.2 SELECT Statements This section explains SELECT statements. #### 4.2.1 UNIQUE **Description** UNIQUE deletes duplicate rows from the selected list and displays the result. **Functional differences** - **Oracle database** - UNIQUE can be specified in a select list. - **PostgreSQL** - UNIQUE cannot be specified in a select list. Specify DISTINCT instead. **Migration procedure** Use the following procedure to perform migration: 1. Search for the keyword UNIQUE and identify where it is specified in the select list of the SELECT statement. 2. Change UNIQUE in the SELECT statement to DISTINCT. **Migration example** The example below shows migration when UNIQUE is specified in a select list.
Oracle database PostgreSQL
SELECT UNIQUE i_name 
FROM inventory_table;
SELECT DISTINCT i_name 
FROM inventory_table;
#### 4.2.2 Subqueries **Description** A subquery specifies a sub SELECT statement in the main SQL statement. **Functional differences** - **Oracle database** - A subquery specified in a FROM clause can be executed even without an alias being specified for it. - **PostgreSQL** - A subquery specified in a FROM clause cannot be executed unless an alias is specified for it. **Migration procedure** Use the following procedure to perform migration: 1. Search for the keyword SELECT and identify where a subquery is used. 2. If the subquery is specified in a FROM clause and no alias is specified for it, specify an alias. **Migration example** The example below shows migration when a SELECT statement that uses a subquery is executed.
Oracle database PostgreSQL
SELECT * 
 FROM ( SELECT * FROM inventory_table 
 WHERE i_name = 'television' ) 
 WHERE i_quantity > 0; 
SELECT * 
 FROM ( SELECT * FROM inventory_table 
 WHERE i_name = 'television' ) AS foo 
 WHERE i_quantity > 0;
#### 4.2.3 Hierarchical Queries **Description** If a table contains data that can associate its own records, a hierarchical query displays the result of associating those records. ##### 4.2.3.1 Executing Hierarchical Queries **Functional differences** - **Oracle database** - Hierarchical queries can be used. - **PostgreSQL** - Hierarchical queries cannot be used. **Migration procedure** Hierarchical queries cannot be used, so specify a recursive query that uses a WITH clause so that the same result is returned. Use the following procedure to perform migration: 1. Search for the keyword CONNECT and identify where a hierarchical query is used. 2. Check the following: - Target table of the hierarchical query - Column being used - Conditional expressions specified in the CONNECT BY clause 3. Replace the hierarchical query with WITH clause syntax to match the format shown below. 4. Change the table name specified in the FROM clause to the name of the query in the WITH clause, and delete the CONNECT BY clause. ~~~ WITH RECURSIVE queryName( columnUsed ) AS ( SELECT columnUsed FROM targetTableOfHierarchicalQuery UNION ALL SELECT columnUsed(qualified by n) FROM targetTableOfHierarchicalQuery n, queryName w WHERE conditionalExprOfConnectByClause(use w to qualify part qualified by PRIOR) ) ~~~ **Migration example** The example below shows migration when a hierarchical query is executed.
Oracle database PostgreSQL
SELECT staff_id, name, manager_id 
 FROM staff_table 
 CONNECT BY PRIOR staff_id = manager_id; 







WITH RECURSIVE staff_table_w( staff_id, 
 name, 
 manager_id ) AS 
 ( SELECT staff_id, name, manager_id 
       FROM staff_table 
     UNION ALL 
     SELECT n.staff_id, n.name, n.manager_id 
       FROM staff_table n, staff_table_w w 
       WHERE w.staff_id = n.manager_id ) 
 SELECT staff_id, name, manager_id 
 FROM staff_table_w;
##### 4.2.3.2 Hierarchical Query with Start Row **Functional differences** - **Oracle database** - A START WITH clause can be specified in a hierarchical query to set start row conditions. - **PostgreSQL** - A START WITH clause cannot be specified. **Migration procedure** In a recursive query that uses a WITH clause, set a condition that is self-referencing so that the same result is returned. Use the following procedure to perform migration: 1. Replace the hierarchical query with syntax that uses a recursive query (WITH clause). 2. If a START WITH clause is specified, move the specified conditional expression to the WHERE clause of the first subquery specified in the WITH clause. 3. Delete the START WITH clause. **Migration example** The example below shows migration when the start row is specified using a hierarchical query.
Oracle database PostgreSQL
SELECT staff_id, name, manager_id 
 FROM staff_table 
 START WITH staff_id = '1001' 
 CONNECT BY PRIOR staff_id = manager_id;







WITH RECURSIVE staff_table_w( staff_id, 
 name, 
 manager_id ) AS 
 ( SELECT staff_id, name, manager_id 
       FROM staff_table 
       WHERE staff_id = '1001' 
     UNION ALL 
     SELECT n.staff_id, n.name, n.manager_id 
       FROM staff_table n, staff_table_w w 
       WHERE w.staff_id = n.manager_id ) 
 SELECT staff_id, name, manager_id 
 FROM staff_table_w;
##### 4.2.3.3 Hierarchical Query Displaying the Hierarchical Position of Each Row **Functional differences** - **Oracle database** - Specifying a LEVEL pseudocolumn in the select list of a hierarchical query displays the hierarchical position of each row. - **PostgreSQL** - A LEVEL pseudocolumn cannot be specified. **Migration procedure** In a recursive query that uses a WITH clause, create a result column equivalent to the LEVEL pseudocolumn as the query result of the WITH clause so that the same result is returned. Use the following procedure to perform migration: 1. Replace the hierarchical query with syntax that uses a recursive query (WITH clause). 2. Add LEVEL to the column list of the query result of the WITH clause. 3. Specify the following values as the select list of the subquery in the position corresponding to the LEVEL column: - Specify 1 in the first query. - Specify LEVEL + 1 in the next query. (LEVEL is a column of the recursive table.) 4. Using a query, replace the portion where the LEVEL pseudocolumn is used with LEVEL (quoted identifier). The following shows the conversion format containing the LEVEL pseudocolumn. ~~~ WITH RECURSIVE queryName( columnUsed, "LEVEL" ) AS ( SELECT columnUsed, 1 FROM targetTableOfHierarchicalQuery UNION ALL SELECT columnUsed(qualified by n), w."LEVEL" + 1 FROM targetTableOfHierarchicalQuery n, queryName w WHERE conditionalExprOfConnectByClause(use w to qualify part qualified by PRIOR) ) ~~~ **Migration example** The example below shows migration when a hierarchical query is used for displaying the hierarchical position of each row.
Oracle database PostgreSQL
SELECT staff_id, name, manager_id, LEVEL 
 FROM staff_table 
 START WITH staff_id = '1001' 
 CONNECT BY PRIOR staff_id = manager_id; 











WITH RECURSIVE staff_table_w( staff_id, 
                name, 
                manager_id, 
                "LEVEL"  ) AS 
   ( SELECT staff_id, name, manager_id, 1 
       FROM staff_table 
       WHERE staff_id = '1001' 
     UNION ALL 
     SELECT n.staff_id, 
            n.name, 
            n.manager_id, 
            w."LEVEL" + 1 
       FROM staff_table n, staff_table_w w 
       WHERE w.staff_id = n.manager_id ) 
 SELECT staff_id, name, manager_id, "LEVEL"  
 FROM staff_table_w;
##### 4.2.3.4 Hierarchical Query Displaying the Hierarchical Structure **Functional differences** - **Oracle database** - Specifying SYS_CONNECT_BY_PATH in the select list of a hierarchical query displays the hierarchical structure. - **PostgreSQL** - SYS_CONNECT_BY_PATH cannot be specified. **Migration procedure** In a recursive query that uses a WITH clause, create an arithmetic expression that also uses the recursive query of the WITH clause so that the same result is returned. Use the following procedure to perform migration: 1. Replace the hierarchical query with syntax that uses a recursive query (WITH clause). 2. Add PATH to the column list of the query result of the WITH clause. 3. Specify the following values for the select list of the subquery corresponding to the PATH column. The example here explains migration when a slash (/) is specified as the delimiter. - In the first query, specify the path to the values of the columns from the root to the node. - Specify m.PATH || '/' || n.columnName in the next query. (PATH is a recursive table column.) 4. Using a query, replace the part where PATH is used, with PATH. The following shows the conversion format containing PATH. ~~~ WITH RECURSIVE queryName( columnUsed, PATH ) AS ( SELECT columnUsed, '/' || columnName FROM targetTableOfHierarchicalQuery UNION ALL SELECT columnUsed(qualified by n), w.PATH || '/' || n.columnName FROM targetTableOfHierarchicalQuery n, queryName w WHERE conditionalExprOfConnectByClause ) ~~~ For conditionalExprOfConnectByClause, use w to qualify the part qualified by PRIOR. **Migration example** The example below shows migration when the hierarchical structure is displayed.
Oracle database PostgreSQL
SELECT staff_id,name,manager_id, 
 SYS_CONNECT_BY_PATH(name,'/') AS PATH  
 FROM staff_table 
 START WITH staff_id = '1001' 
 CONNECT BY PRIOR staff_id = manager_id; 










 WITH RECURSIVE staff_table_w( staff_id, 
                name, 
                manager_id, 
                 PATH) AS 
 ( SELECT staff_id,name,manager_id, '/' || name 
 	FROM staff_table 
 	WHERE staff_id = '1001' 
 	UNION ALL 
 	SELECT n.staff_id, 
               name, 
               n.manager_id, 
               w.PATH || '/' || n.name 
 	FROM staff_table n,staff_table_w w 
 	WHERE w.staff_id = n.manager_id ) 
 SELECT staff_id,name,manager_id, PATH 
 FROM staff_table_w;
##### 4.2.3.5 Hierarchical Queries That Sort Each Hierarchy Level **Functional differences** - **Oracle database** - Specifying an ORDER SIBLINGS BY clause in a hierarchical query enables sorting of each hierarchical level. - **PostgreSQL** - An ORDER SIBLINGS BY clause cannot be specified. **Migration procedure** Use the following procedure to perform migration: 1. Replace the hierarchical query with syntax that uses a recursive query (WITH clause). 2. In the syntax that uses a recursive query (WITH clause), add poskey to the column list of the query result of the WITH clause. 3. Specify ROW_NUMBER() in the position corresponding to the poskey column. In the OVER clause, specify an ORDER BY clause that specifies the column of the ORDER SIBLINGS BY clause. 4. Add siblings_pos to the column list of the query result of the WITH clause. 5. Specify the following values as the select list of the subquery in the position corresponding to the siblings_pos column: - Specify ARRAY[poskey] in the first query. - Specify a concatenation of siblings_pos and poskey in the next query. 6. Using a query, specify siblings_pos in the ORDER BY clause to perform a sort. The following shows the conversion format containing sorting of each hierarchy level. ~~~ WITH RECURSIVE queryNameForPoskey( columnUsed, poskey ) AS ( SELECT columnUsed, ROW_NUMBER() OVER( ORDER BY columnNameSpecifiedInOrderSiblingsByClause ) FROM targetTableOfHierarchicalQuery ), WITH RECURSIVE queryName( columnUsed, siblings_pos ) AS ( SELECT columnUsed, ARRAY[poskey] FROM queryNameForPoskey UNION ALL SELECT columnUsed(qualified by n), w.siblings_pos || n.poskey FROM queryNameForPoskey n, queryName w WHERE conditionalExprOfConnectByClause(use w to qualify part qualified by PRIOR ) ) ~~~ **Migration example** The example below shows migration when a hierarchical query is used to perform a sort in each hierarchy level.
Oracle database PostgreSQL
SELECT staff_id, name, manager_id 
  FROM staff_table 
  START WITH staff_id = '1001' 
  CONNECT BY PRIOR staff_id = manager_id 
  ORDER SIBLINGS BY name; 























 WITH RECURSIVE staff_table_pos ( staff_id, 
                name, 
                manager_id, 
                poskey ) AS 
 ( SELECT staff_id, 
          name, 
          manager_id, 
 ROW_NUMBER() OVER( ORDER BY name ) 
 FROM staff_table ), 
 staff_table_w ( staff_id, 
                 name, 
                 manager_id, 
 siblings_pos ) AS 
 ( SELECT staff_id, 
          name, 
          manager_id, 
          ARRAY[poskey] 
         FROM staff_table_pos 
         WHERE staff_id = '1001' 
       UNION ALL 
       SELECT n.staff_id, 
              n.name, 
              n.manager_id, 
              w.siblings_pos || n.poskey 
         FROM staff_table_pos n, staff_table_w w 
         WHERE w.staff_id = n.manager_id ) 
 SELECT staff_id, name, manager_id 
 FROM staff_table_w 
 ORDER BY siblings_pos;
#### 4.2.4 MINUS **Description** MINUS finds the difference between two query results, that is, it returns rows that are in the first result set that are not in the second result set. **Functional differences** - **Oracle database** - MINUS is specified to find the difference between two query results. - **PostgreSQL** - MINUS cannot be specified to find the difference between two query results. Specify EXCEPT instead. **Migration procedure** Use the following procedure to perform migration: 1. Search for the keyword MINUS and identify where it is used. 2. Change MINUS to EXCEPT. **Migration example** The example below shows migration when the set difference of query results is to be found.
Oracle database PostgreSQL
SELECT i_number, i_name FROM inventory_table 
  WHERE i_warehouse = 2 
 MINUS 
 SELECT i_number, i_name FROM inventory_table 
  WHERE i_name = 'cd';
SELECT i_number, i_name FROM inventory_table 
  WHERE i_warehouse = 2 
 EXCEPT 
 SELECT i_number, i_name FROM inventory_table 
  WHERE i_name = 'cd';
### 4.3 DELETE Statements This section explains DELETE statements. #### 4.3.1 Omitting the FROM Keyword **Functional differences** - **Oracle database** - The FROM keyword can be omitted from a DELETE statement. - **PostgreSQL** - The FROM keyword cannot be omitted from a DELETE statement. **Migration procedure** Use the following procedure to perform migration: 1. Search for the keyword DELETE and identify where it is used. 2. If the FROM keyword has been omitted from the DELETE statement, add it. **Migration example** The example below shows migration when the FROM keyword is omitted from a DELETE statement.
Oracle database PostgreSQL
DELETE inventory_table 
  WHERE i_name = 'cd player';
DELETE FROM inventory_table 
  WHERE i_name = 'cd player';
### 4.4 MERGE Statements This section explains MERGE statements. #### 4.4.1 Executing MERGE Statements **Functional differences** - **Oracle database** - MERGE statements can be used. - **PostgreSQL** - MERGE statements cannot be used. **Migration procedure** Use the following procedure to perform migration: 1. Use an INSERT statement to specify the INSERT keyword that follows WHEN NOT MATCHED THEN in the MERGE statement. 2. Use a SELECT statement after the lines added in step 1 to specify the SELECT statement that follows the USING clause of the MERGE statement. 3. Use DO UPDATE in an ON CONFLICT clause of the INSERT statement specified in step 1 to specify the UPDATE keyword that follows WHEN MATCHED THEN in the MERGE statement. **Migration example** The example below shows how to migrate the MERGE statement.
Oracle database PostgreSQL
MERGE INTO new_inventory_table N 
 USING ( SELECT i_number, 
 i_name, 
 i_quantity, 
 i_warehouse 
 FROM inventory_table ) I 
 ON ( N.i_number = I.i_number ) 
 WHEN MATCHED THEN 
     UPDATE SET N.i_quantity = I.i_quantity 
 WHEN NOT MATCHED THEN 
     INSERT ( N.i_number, 
 N.i_name, 
 N.i_quantity, 
 N.i_warehouse ) 
     VALUES ( I.i_number, 
 I.i_name, 
 I.i_quantity, 
 I.i_warehouse );
INSERT INTO new_inventory_table AS N ( 
             i_number, 
             i_name, 
             i_quantity, 
             i_warehouse 
            ) 
 SELECT i_number, 
        i_name, 
        i_quantity, 
        i_warehouse 
 FROM inventory_table 
 ON CONFLICT (i_number) DO UPDATE 
 SET i_quantity = excluded.i_quantity; 




**Note** ---- In the migration example shown above, a primary key or unique key definition must have been specified in the column specified in the ON clause of the MERGE statement. If using a table for which a primary key or unique key definition is not specified in the column of the conditional expression, refer to the migration example provided in "Information" below. ---- **Information** ---- The example below shows migration when a primary key or unique key definition is not specified in the column specified in the ON clause of the MERGE statement. **Migration procedure** Use the following procedure to perform migration: 1. Use a SELECT statement in a WITH query to specify the SELECT statement that follows the USING clause of the MERGE statement. 2. Use an UPDATE statement in the WITH query to specify the UPDATE keyword that follows WHEN MATCHED THEN in the MERGE statement. 3. Specify the INSERT keyword that follows the WHEN NOT MATCHED THEN clause of the MERGE statement as an INSERT statement following the WITH query. 4. Specify NOT IN within the INSERT statement added in step 3 as an equivalent condition to the WHEN MATCHED THEN clause of the MERGE statement. **Migration example** The example below shows migration of a MERGE statement in which no primary key or unique key definition is specified.
Oracle database PostgreSQL
MERGE INTO new_inventory_table N 
 USING ( SELECT i_number, 
                i_name, 
                i_quantity, 
                i_warehouse 
 FROM inventory_table ) I 
 ON ( N.i_number = I.i_number ) 
 WHEN MATCHED THEN 
     UPDATE SET N.i_quantity = I.i_quantity 
 WHEN NOT MATCHED THEN 
     INSERT ( N.i_number, 
              N.i_name, 
              N.i_quantity, 
              N.i_warehouse ) 
     VALUES ( I.i_number, 
              I.i_name, 
              I.i_quantity, 
              I.i_warehouse );
WITH I AS ( 
 SELECT i_number, 
        i_name, 
        i_quantity, 
        i_warehouse 
 FROM inventory_table ), 
 U AS ( 
 UPDATE new_inventory_table AS N  
 SET i_quantity = I.i_quantity  
 FROM inventory_table I 
 WHERE N.i_number = I.i_number 
 RETURNING N.i_number ) 
 INSERT INTO new_inventory_table ( 
 SELECT * FROM I WHERE i_number NOT IN ( 
 SELECT i_number FROM U ) ); 


---- ### 4.5 ALTER INDEX Statements **Description** An ALTER INDEX statement changes an index definition. #### 4.5.1 Restructuring an Index **Functional differences** - **Oracle database** - A REBUILD clause can be specified in the ALTER INDEX statement to restructure an index. - **PostgreSQL** - A REBUILD clause cannot be specified in the ALTER INDEX statement. Use a REINDEX statement instead. **Migration procedure** Use the following procedure to perform migration: 1. Search for the keywords ALTER and INDEX, and identify where they are used. 2. If a REBUILD clause is specified, replace the ALTER INDEX statement with a REINDEX statement. **Migration example** The example below shows migration when an index is restructured.
Oracle database PostgreSQL
ALTER INDEX idx REBUILD;
REINDEX INDEX idx;
#### 4.5.2 Restructuring an Index Where a Tablespace is Specified **Functional differences** - **Oracle database** - A tablespace can be specified in a REBUILD clause. - **PostgreSQL** - A REBUILD clause cannot be used. **Migration procedure** The REBUILD statement for an index restructure is replaced with a REINDEX statement, but a tablespace cannot be specified in this statement. Therefore, move the tablespace before performing the index restructure. Use the following procedure to perform migration: 1. Search for the keywords ALTER and INDEX, and identify where they are used. 2. If both a REBUILD clause and a TABLESPACE clause are specified, replace the REBUILD clause of the ALTER INDEX statement with a SET clause. 3. Add a REINDEX statement after the ALTER INDEX statement. **Migration example** The example below shows migration when a tablespace is specified for restructuring an index.
Oracle database PostgreSQL
ALTER INDEX idx REBUILD TABLESPACE tablespace1;
ALTER INDEX idx SET TABLESPACE tablespace1; 
 REINDEX INDEX idx;
#### 4.5.3 Restructuring an Index Where a Free Space Percentage is Specified **Functional differences** - **Oracle database** - PCTFREE can be specified in a REBUILD clause to specify a free space percentage for an index. - **PostgreSQL** - A REBUILD clause cannot be used. **Migration procedure** The REBUILD statement for an index restructure is replaced with a REINDEX statement, but a free space percentage cannot be specified in this statement. Therefore, change the index utilization rate so that an equivalent result is returned. Then restructure the index. Use the following procedure to perform migration: 1. Search for the keywords ALTER and INDEX, and identify where they are used. 2. If both a REBUILD clause and the PCTFREE keyword are specified, replace the REBUILD clause with a SET clause and change PCTFREE to FILLFACTOR. Use 100 - valueSpecifiedInPctfree as the set value. 3. Add a REINDEX statement after the ALTER INDEX statement. **Migration example** The example below shows migration when a fill factor is specified for restructuring an index.
Oracle database PostgreSQL
ALTER INDEX idx REBUILD PCTFREE 10;
ALTER INDEX idx SET (FILLFACTOR=90); 
 REINDEX INDEX idx;
### 4.6 ALTER SESSION Statements **Description** An ALTER SESSION statement specifies and changes parameters per session. #### 4.6.1 Closing dblink **Functional differences** - **Oracle database** - An ALTER SESSION statement is used to close dblink. - **PostgreSQL** - ALTER SESSION statements cannot be used. Use DBLINK_CLOSE instead. **Migration procedure** Use the following procedure to perform migration: 1. Search for the keywords ALTER and SESSION, and identify where they are used. 2. If a CLOSE DATABASE LINK clause is specified, delete the ALTER SESSION statement and replace it with a SELECT statement that calls DBLINK_CLOSE. **Migration example** The example below shows migration when dblink is closed.
Oracle database PostgreSQL
ALTER SESSION CLOSE DATABASE LINK dblink1;
SELECT DBLINK_CLOSE ( 'dblink1' );
#### 4.6.2 Changing the Initialization Parameters **Functional differences** - **Oracle database** - An ALTER SESSION statement is used to change the initialization parameters. - **PostgreSQL** - ALTER SESSION statements cannot be used. Use a SET statement instead to change the server parameters. **Migration procedure** Use the following procedure to perform migration: 1. Search for the keywords ALTER and SESSION, and identify where they are used. 2. Replace the ALTER SESSION statement with a SET statement. The table below lists the corresponding initialization parameters and server parameters. **Corresponding initialization parameters and server parameters** |Initialization parameter|Runtime configuration parameters of PostgreSQL| |:---|:---| | ENABLE_DDL_LOGGING | log_statement | | NLS_CURRENCY | lc_monetary | | NLS_DATE_FORMAT | DateStyle | | NLS_DATE_LANGUAGE | lc_time | | NLS_TIMESTAMP_FORMAT | lc_time | | NLS_TIMESTAMP_TZ_FORMAT | lc_time | | OPTIMIZER_INDEX_COST_ADJ | cpu_index_tuple_cost
seq_page_cost | **Migration example** The example below shows migration when the initialization parameters are changed.
Oracle database PostgreSQL
ALTER SESSION SET ENABLE_DDL_LOGGING = TRUE;
SET log_statement = 'DDL';
**Note** ---- The values that can be specified for server parameters may differ from those that can be specified for the initialization parameters. Refer to the manual provided by the vendor for the values that can be specified. ---- **See** ---- Refer to "Server Configuration" in "Server Administration" in the PostgreSQL Documentation for information on server parameters. ---- #### 4.6.3 Setting Transaction Characteristics **Functional differences** - **Oracle database** - An ALTER SESSION statement is used to set transaction characteristics. - **PostgreSQL** - ALTER SESSION statements cannot be used. Use a SET TRANSACTION statement instead. **Migration procedure** Use the following procedure to perform migration: 1. Search for the keywords ALTER and SESSION, and identify where they are used. 2. If SET ISOLATION_LEVEL is specified, replace the ALTER SESSION statement with a SET TRANSACTION statement. **Migration example** The example below shows migration when transaction characteristics are set.
Oracle database PostgreSQL
ALTER SESSION SET
 ISOLATION_LEVEL = SERIALIZABLE;
SET TRANSACTION 
 ISOLATION LEVEL SERIALIZABLE;
#### 4.6.4 Migrating the Time Zone Setting **Functional differences** - **Oracle database** - An ALTER SESSION statement is used to set the time zone. - **PostgreSQL** - ALTER SESSION statements cannot be used. Use a SET statement instead. **Migration procedure** Use the following procedure to perform migration: 1. Search for the keywords ALTER and SESSION, and identify where they are used. 2. If SET TIME_ZONE is specified, replace the ALTER SESSION statement with a SET statement. **Migration example** The example below shows migration when the time zone is set.
Oracle database PostgreSQL
ALTER SESSION SET TIME_ZONE = '+09:00';
SET TimeZone='Japan';
**Note** ---- Be sure to use the full time zone name when specifying the time zone in the TimeZone parameter of PostgreSQL. ---- ### 4.7 GRANT Statements **Description** A GRANT statement defines access privileges. #### 4.7.1 Migratability of GRANT Statement Features The following table indicates the migratability of the GRANT statement features provided by Oracle databases to PostgreSQL. **System privileges** |GRANT statement features of Oracle databases|Migratability|Remarks| |:---|:---:|:---| | Granting of system privileges | MR | PUBLIC cannot be specified for a grantee.
There are restrictions on the privileges that can be migrated. | | Granting of role (role) | YR | PUBLIC cannot be specified for a grantee. | | Granting of all system privileges (ALL PRIVILEGES) | Y | | | WITH ADMIN OPTION clause | MR | Only privileges that can be migrated with the GRANT statement. | | WITH DELEGATE OPTION clause | N | | **Object privileges** |GRANT statement features of Oracle databases|Migratability|Remarks| |:---|:---:|:---| | Granting of object privileges | YR | Columns can be specified.
There are restrictions on the privileges that can be migrated. | | Granting of all object privileges (ALL [PRIVILEGES]) | Y | Columns can be specified. | | Grantee Schema object | Y | | | Grantee User | N | | | Grantee Directory | N | | | Grantee Edition | N | | | Grantee Mining model | N | | | Grantee Java source | N | | | Grantee SQL translation profile | N | | | WITH HIERARCHY OPTION clause | N | | | WITH GRANT OPTION clause | Y | | **Program unit privileges** |GRANT statement features of Oracle databases|Migratability|Remarks| |:---|:---|:---| | Granting of program unit privileges | N | | Y: Syntax can be migrated as is YR: Syntax can be migrated as is with restrictions MR: Modified syntax can be migrated with restrictions N: Cannot be migrated #### 4.7.2 Granting System Privileges ##### 4.7.2.1 Granting Privileges for Operating Users and Roles **Functional differences** - **Oracle database** - A GRANT statement is used to grant privileges for creating and changing users and roles. - **PostgreSQL** - A GRANT statement cannot be used to grant privileges for creating and changing users and roles. Use an ALTER ROLE statement instead. **Migration procedure** Use the following procedure to perform migration: 1. Search for the keyword GRANT and identify where it is used. 2. If privileges for creating and changing users and roles are granted, replace the GRANT statement with the ALTER ROLE statement. The table below lists the migratable user and role operation privileges. **Migratable user and role operation privileges** - **ROLES** |GRANT statement in Oracle database|Corresponding ALTER ROLE statement in PostgreSQL| |:---|:---:| |GRANT CREATE ROLE TO *roleName*
GRANT ALTER ANY ROLE TO *roleName*
GRANT DROP ANY ROLE TO *roleName*
GRANT ANY ROLE TO *roleName* | ALTER ROLE *roleName* CREATEROLE;| - **USERS** |GRANT statement in Oracle database|Corresponding ALTER ROLE statement in PostgreSQL| |:---|:---:| |GRANT CREATE USER TO *userName*
GRANT ALTER USER TO *userName*
GRANT DROP USER TO *userName*|ALTER ROLE *userName* CREATEUSER| **Migration example** The example below shows migration when role creation privileges are granted.
Oracle database PostgreSQL
GRANT CREATE ROLE TO role1;
ALTER ROLE role1 CREATEROLE;
#### 4.7.2.2 Granting Privileges for Creating Objects **Functional differences** - **Oracle database** - A GRANT statement is used to grant creation privileges per object. - **PostgreSQL** - A GRANT statement is used to grant object creation privileges per schema or database. **Migration procedure** Use the following procedure to perform migration: 1. Search for the keyword GRANT and identify where it is used. 2. If creation privileges are granted per object, replace the GRANT statement with a GRANT statement that grants creation privileges per schema or database. The table below lists the migratable object creation privileges. **Migratable object creation privileges** |Object|GRANT statement in Oracle database|Corresponding ALTER ROLE statement in PostgreSQL| |:---|:---|:---| | MATERIALIZED VIEWS | GRANT CREATE MATERIALIZED VIEW TO *userName* | GRANT CREATE ON SCHEMA *schemaName* TO *userName* | | OPERATORS | GRANT CREATE OPERATOR TO *userName* | GRANT CREATE ON SCHEMA *schemaName* TO *userName* | | PROCEDURES | GRANT CREATE PROCEDURE TO *userName* | GRANT CREATE ON SCHEMA *schemaName* TO *userName* | | SEQUENCES | GRANT CREATE SEQUENCE TO *userName* | GRANT CREATE ON SCHEMA *schemaName* TO *userName* | | SESSIONS | GRANT CREATE SESSION TO *userName* | GRANT CONNECT ON DATABASE *databaseName* TO *userName* | | TABLES | GRANT CREATE TABLE TO *userName* | GRANT CREATE ON SCHEMA *schemaName* TO *userName* | | TRIGGERS | GRANT CREATE TRIGGER TO *userName* | GRANT CREATE ON SCHEMA *schemaName* TO *userName* | | TYPES | GRANT CREATE TYPE TO *userName* | GRANT CREATE ON SCHEMA *schemaName* TO *userName* | | VIEWS | GRANT CREATE VIEW TO *userName* | GRANT CREATE ON SCHEMA *schemaName* TO *userName* | **Migration example** The example below shows migration when table creation privileges are granted.
Oracle database PostgreSQL
GRANT CREATE TABLE TO user1;
GRANT CREATE ON SCHEMA scm1 TO user1;
##### 4.7.2.3 Granting Roles (with Password Setting) **Functional differences** - **Oracle database** - When a GRANT statement is used to assign a user to a role, a password can be set at the same time. - **PostgreSQL** - When a GRANT statement is used to assign a user to a role, a password cannot be set at the same time. **Migration procedure** To set a password, you must specify a separate CREATE USER or ALTER USER statement and set the password in that statement. Use the following procedure to perform migration: 1. Search for the keyword GRANT and identify where it is used. 2. If an IDENTIFIED BY clause is specified, check if the target user exists. 3. If the user exists, use an ALTER USER statement to change the password. If the user does not exist, use a CREATE USER statement to create a new user and set a password. 4. Delete the clause for granting a password from the GRANT statement. **Migration example** The example below shows migration when role1 is granted to user1.
Oracle database PostgreSQL
GRANT role1 TO user1 IDENTIFIED BY PASSWORD;
 CREATE USER user1 PASSWORD 'PASSWORD'; 
 GRANT role1 TO user1;
#### 4.7.3 Granting Object Privileges There is no difference in the syntax of GRANT statements with regard to object privileges that are migratable from an Oracle database. However, some object privileges cannot be used in PostgreSQL, so they must be changed to supported object privileges. The table below lists the object privileges that can be migrated from an Oracle database to PostgreSQL. **Migratable object privileges** - **Materialized view privileges** |Name of object privilege|Change required|Remarks| |:---|:---:|:---| | READ | Yes | Change to SELECT. | | SELECT | No | If a FOR UPDATE clause is used in the SELECT statement, UPDATE privileges are also required. | - **Operator privileges** |Name of object privilege|Change required|Remarks| |:---|:---:|:---| EXECUTE | Yes | In PostgreSQL, EXECUTE privileges must be granted to a function that implements operators.| - **Procedure, function, and package privileges** |Name of object privilege|Change required|Remarks| |:---|:---:|:---| | EXECUTE | Yes | The FUNCTION keyword must be added before the function name. | - **Sequence privileges** |Name of object privilege|Change required|Remarks| |:---|:---:|:---| | SELECT | Yes | Change to USAGE.
The SEQUENCE keyword must be added before the sequence name. | - **Table privileges** |Name of object privilege|Change required|Remarks| |:---|:---:|:---| | DELETE | No | | | INSERT | No | | | READ | Yes | Change to SELECT. | | REFERENCES | No | | | SELECT | No | If a FOR UPDATE clause is used in the SELECT statement, UPDATE privileges are also required. | | UPDATE | No | | - **View privileges** |Name of object privilege|Change required|Remarks| |:---|:---:|:---| | DELETE | No | | | INSERT | No | | | READ | Yes | Change to SELECT. | | REFERENCES | No | | | SELECT | No | If a FOR UPDATE clause is used in the SELECT statement, UPDATE privileges are also required. | | UPDATE | No | | orafce-VERSION_3_9_0/doc/sql_migration/sql_migration05.md000066400000000000000000001401271362147214200233140ustar00rootroot00000000000000Chapter 5 Migrating PL/SQL --- This chapter explains how to migrate Oracle database PL/SQL. Note that in this document, PL/SQL refers to the language to be migrated to PostgreSQL PL/pgSQL. ### 5.1 Notes on Migrating from PL/SQL to PL/pgSQL This section provides notes on migration from PL/SQL to PL/pgSQL. #### 5.1.1 Transaction Control PL/pgSQL does not allow transaction control within a process. Terminate a procedure whenever a transaction is terminated in the Oracle database and execute a transaction control statement from the application. ### 5.2 Basic Elements This section explains how to migrate the basic elements of PL/SQL. #### 5.2.1 Migrating Data Types The table below lists the PostgreSQL data types that correspond to data types unique to PL/SQL. Data type correspondence with PL/SQL - **Character** |Oracle database Data type|Remarks|Migratability|PostgreSQL Data type|Remarks| |:---|:---|:---:|:---|:---| | STRING | The number of bytes or number of characters can be specified. | MR | varchar | Only the number of characters can be specified. | - **Numeric** |Oracle database Data type|Remarks|Migratability|PostgreSQL Data type|Remarks| |:---|:---|:---:|:---|:---| | BINARY_INTEGER | | M | integer | | | NATURAL | | M | integer | | | NATURALN | Type with NOT NULL constraints | MR | integer | Set "not null" constraints for variable declarations. | | PLS_INTEGER | | M | integer | | | POSITIVE | | M | integer | | | POSITIVEN | Type with NOT NULL constraints | MR | integer | Set "not null" constraints for variable declarations. | | SIGNTYPE | | M | smallint | | | SIMPLE_DOUBLE | Type with NOT NULL constraints | MR | double precision | Set "not null" constraints for variable declarations. | | SIMPLE_FLOAT | Type with NOT NULL constraints | MR | real | Set "not null" constraints for variable declarations. | | SIMPLE_INTEGER | Type with NOT NULL constraints | MR | integer | Set "not null" constraints for variable declarations. | - **Date and time** |Oracle database Data type|Remarks|Migratability|PostgreSQL Data type|Remarks| |:---|:---|:---:|:---|:---| | DSINTERVAL_UNCONSTRAINED | | N | | | | TIME_TZ_UNCONSTRAINED | | N | | | | TIME_UNCONSTRAINED | | N | | | | TIMESTAMP_LTZ_UNCONSTRAINED | | N | | | | TIMESTAMP_TZ_UNCONSTRAINED | | N | | | | TIMESTAMP_UNCONSTRAINED | | N | | | | YMINTERVAL_UNCONSTRAINED | | N | | | - **Other** |Oracle database Data type|Remarks|Migratability|PostgreSQL Data type|Remarks| |:---|:---|:---:|:---|:---| | BOOLEAN | | Y | boolean | | | RECORD | | M | Complex type | | | REF CURSOR (cursor variable) | | M | refcursor type | | | Subtype with constraints | | N | | | | Subtype that uses the base type within the same data type family | | N | | | | Unconstrained subtype | | N | | | Y: Data type can be migrated as is M: Modified data type can be migrated N: Cannot be migrated MR: Modified data type can be migrated with restrictions **See** ---- Refer to "Data Types" for information on migrating data types other than those unique to PL/SQL. ---- #### 5.2.2 Error-Related Elements This section explains elements related to PL/SQL errors. ##### 5.2.2.1 Predefined Exceptions **Description** A predefined exception is an error defined beforehand in an Oracle database. **Functional differences** - **Oracle database** - Predefined exceptions can be used. - **PostgreSQL** - Predefined exceptions cannot be used. Use PostgreSQL error codes instead. **Migration procedure** Use the following procedure to perform migration: 1. Identify where predefined exceptions are used. 2. Refer to the table below and replace the values of predefined exceptions with PostgreSQL error codes. |Predefined exception
(Oracle database)|Migratability|Corresponding PostgreSQL error code| |:---|:---:|:---| | ACCESS_INTO_NULL | N | Not generated | | CASE_NOT_FOUND | Y | case_not_found | | COLLECTION_IS_NULL | N | Not generated | | CURSOR_ALREADY_OPEN | Y | duplicate_cursor | | DUP_VAL_ON_INDEX | Y | unique_violation | | INVALID_CURSOR | Y | invalid_cursor_name | | INVALID_NUMBER | Y | invalid_text_representation | | LOGIN_DENIED | Y | invalid_authorization_specification
invalid_password | | NO_DATA_FOUND | Y | no_data_found | | NO_DATA_NEEDED | N | Not generated | | NOT_LOGGED_ON | N | Not generated | | PROGRAM_ERROR | Y | internal_error | | ROWTYPE_MISMATCH | N | Not generated | | SELF_IS_NULL | N | Not generated | | STORAGE_ERROR | Y | out_of_memory | | SUBSCRIPT_BEYOND_COUNT | N | Not generated | | SUBSCRIPT_OUTSIDE_LIMIT | N | Not generated | | SYS_INVALID_ROWID | N | Not generated | | TIMEOUT_ON_RESOURCE | N | Not generated | | TOO_MANY_ROWS | Y | too_many_rows | | VALUE_ERROR | Y | null_value_not_allowed
invalid_text_representation
string_data_right_truncation
invalid_parameter_value | | ZERO_DIVIDE | Y | division_by_zero | Y: Can be migrated N: Cannot be migrated **Migration example** The example below shows how to migrate the VALUE_ERROR exception. Note that OR is used in the migration example to group error codes so that VALUE_ERROR corresponds to multiple PostgreSQL error codes.
Oracle database PostgreSQL
SET SERVEROUTPUT ON; 
 DECLARE 
  variety VARCHAR2(20) := 'television'; 
  company VARCHAR2(20) := 'Fullmoon Industry'; 
  name VARCHAR2(30); 
 BEGIN 

name := ( variety || 'from' || company ); EXCEPTION WHEN VALUE_ERROR THEN


DBMS_OUTPUT.PUT_LINE ( 'ERR: Category length is out of range.' ); END; /
DO $$ 
 DECLARE 
  variety VARCHAR(20) := 'television'; 
  company VARCHAR(20) := 'Fullmoon Industry'; 
 name VARCHAR(30); 
 BEGIN 
  PERFORM DBMS_OUTPUT.SERVEROUTPUT(TRUE); 
  name := ( variety || 'from' || company ); 
 EXCEPTION 
  WHEN null_value_not_allowed 
       OR invalid_text_representation 
       OR string_data_right_truncation 
       OR invalid_parameter_value THEN 
  PERFORM DBMS_OUTPUT.PUT_LINE ( 
   'ERR: Category length is out of range.' ); 
 END; 
 $$ 
 ; 
 
##### 5.2.2.2 SQLCODE **Description** SQLCODE returns the error code of an error. **Functional differences** - **Oracle database** - SQLCODE can be specified to obtain an error code. - **PostgreSQL** - SQLCODE cannot be specified to obtain an error code. **Migration procedure** Use the following procedure to perform migration: 1. Search for the keyword SQLCODE and identify where it is used. 2. Change the portion that calls SQLCODE to SQLSTATE. **Migration example** The example below shows migration when the code of an error is displayed.
Oracle database PostgreSQL
SET SERVEROUTPUT ON; 
 DECLARE 
  v_i_number SMALLINT := 401; 
  v_i_name VARCHAR2(30) := 'Blu-ray and DVD recorder'; 
  v_i_quantity INTEGER := 10; 
  v_i_warehouse SMALLINT := 2; 
 BEGIN 

INSERT INTO inventory_table VALUES ( v_i_number, v_i_name, v_i_quantity, v_i_warehouse ); EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE( 'ERR:' || SQLCODE || ': Failure of INSERT.' ); END; /
DO $$ 
 DECLARE 
  v_i_number SMALLINT := 401; 
  v_i_name VARCHAR(30) := 'Blu-ray and DVD recorder'; 
  v_i_quantity INTEGER := 10; 
  v_i_warehouse SMALLINT := 2; 
 BEGIN 
 PERFORM DBMS_OUTPUT.SERVEROUTPUT(TRUE); 
 INSERT INTO inventory_table 
  VALUES ( v_i_number, 
           v_i_name, 
           v_i_quantity, 
           v_i_warehouse ); 
 EXCEPTION 
  WHEN OTHERS THEN 
   PERFORM DBMS_OUTPUT.PUT_LINE( 
    'ERR:' || SQLSTATE || 
    ': Failure of INSERT.' ); 
 END; 
 $$ 
 ;
**Note** ---- Oracle databases and PostgreSQL have different error codes, so the set SQLCODE values and SQLSTATE values are different. Refer to "Appendix A. PostgreSQL Error Codes" in the PostgreSQL Documentation for information on the error codes to be defined in PostgreSQL. ---- ##### 5.2.2.3 EXCEPTION Declarations **Description** An EXCEPTION declaration defines an error. **Functional differences** - **Oracle database** - EXCEPTION declarations can be used to define errors. - **PostgreSQL** - EXCEPTION declarations cannot be used. **Migration procedure** EXCEPTION declarations cannot be used, so specify the error number in a RAISE statement to achieve equivalent operation. Use the following procedure to perform migration: 1. Search for the keyword EXCEPTION, identify where an EXCEPTION declaration is used, and check the error name. 2. Search for the keyword RAISE and identify where the error created using the EXCEPTION declaration is used. 3. Delete the error name from the RAISE statement and instead specify the error code using ERRCODE in a USING clause. 4. Change the portion of the EXCEPTION clause where the error name is used to capture the error to SQLSTATE 'errCodeSpecifiedInStep3'. 5. Delete the EXCEPTION declaration. **Migration example** The example below shows migration when a user-defined error is generated.
Oracle database PostgreSQL
SET SERVEROUTPUT ON; 
 DECLARE 
  v_i_number SMALLINT := 200; 
  v_i_name VARCHAR2(20) := 'television'; 
  v_i_quantity INTEGER := 10; 
  v_i_warehouse SMALLINT := 3; 
  warehouse_num_err EXCEPTION; 
 BEGIN 

IF ( v_i_warehouse = 1 ) OR ( v_i_warehouse = 2 ) THEN INSERT INTO inventory_table VALUES ( v_i_number, v_i_name, v_i_quantity, v_i_warehouse ); ELSE RAISE warehouse_num_err; END IF; EXCEPTION WHEN warehouse_num_err THEN DBMS_OUTPUT.PUT_LINE( 'ERR: Warehouse number is out of range.' );
END; /
SET SERVEROUTPUT ON; 
 DECLARE 
  v_i_number SMALLINT := 200; 
  v_i_name VARCHAR2(20) := 'television'; 
  v_i_quantity INTEGER := 10; 
  v_i_warehouse SMALLINT := 3; 

BEGIN
IF ( v_i_warehouse = 1 ) OR ( v_i_warehouse = 2 ) THEN INSERT INTO inventory_table VALUES ( v_i_number, v_i_name, v_i_quantity, v_i_warehouse ); ELSE RAISE USING ERRCODE = '20001'; END IF; EXCEPTION WHEN SQLSTATE '20001' THEN DBMS_OUTPUT.PUT_LINE( 'ERR: Warehouse number is out of range.' );
END; /
##### 5.2.2.4 PRAGMA EXCEPTION_INIT and RAISE_APPLICATION_ERROR **Description** An EXCEPTION_INIT pragma associates a user-defined error name with an Oracle database error code. RAISE_APPLICATION_ERROR uses a user-defined error code and error message to issue an error. **Functional differences** - **Oracle database** - EXCEPTION_INIT pragmas and RAISE_APPLICATION_ERROR statements can be used. - **PostgreSQL** - EXCEPTION_INIT pragmas and RAISE_APPLICATION_ERROR statements cannot be used. **Migration procedure** EXCEPTION_INIT pragmas and RAISE_APPLICATION_ERROR statements cannot be used, so specify an error message and error code in a RAISE statement to achieve equivalent operation. Use the following procedure to perform migration: 1. Search for the keywords EXCEPTION and PRAGMA, and check for an EXCEPTION_INIT pragma and the specified error and error code. 2. Search for the keyword RAISE_APPLICATION_ERROR and check where an error is used. 3. Replace the error message and error code called by RAISE_APPLICATION_ERROR with syntax that uses a USING clause in RAISE. 4. Change the portion of the EXCEPTION clause where the user-defined error name is used to capture the error to SQLSTATE 'errCodeSpecifiedInStep3'. To display the error message and error code in the EXCEPTION clause, use SQLERRM and SQLSTATE. 5. Delete the EXCEPTION declaration and EXCEPTION INIT pragma. **Migration example** The example below shows migration when an EXCEPTION INIT pragma and RAISE APPLICATION ERROR statement are used.
Oracle database PostgreSQL
SET SERVEROUTPUT ON; 
 DECLARE 
  v_i_number SMALLINT := 200; 
  v_i_name VARCHAR2(30) := ' liquid crystal?television'; 
  v_i_quantity INTEGER := 10; 
  v_i_warehouse SMALLINT := 3; 
  invalid_length EXCEPTION; 
  PRAGMA EXCEPTION_INIT ( invalid_length, -20001 ); 
 BEGIN 

IF ( LENGTH( v_i_name ) <= 20 ) THEN INSERT INTO inventory_table VALUES ( v_i_number, v_i_name, v_i_quantity, v_i_warehouse ); ELSE RAISE_APPLICATION_ERROR( -20001, 'ERR: i_name is invalid length.' ); END IF; EXCEPTION WHEN invalid_length THEN DBMS_OUTPUT.PUT_LINE( TO_CHAR(SQLERRM(-20001)) );
END; /
DO $$ 
 DECLARE 
  v_i_number SMALLINT := 200; 
  v_i_name VARCHAR(30) := ' liquid crystal television'; 
  v_i_quantity INTEGER := 10; 
  v_i_warehouse SMALLINT := 3; 


BEGIN PERFORM DBMS_OUTPUT.SERVEROUTPUT( TRUE ); IF ( LENGTH( v_i_name ) <= 20 ) THEN INSERT INTO inventory_table VALUES ( v_i_number, v_i_name, v_i_quantity, v_i_warehouse ); ELSE RAISE 'ERR: i_name is invalid length.' USING ERRCODE = '20001'; END IF; EXCEPTION WHEN SQLSTATE '20001' THEN PERFORM DBMS_OUTPUT.PUT_LINE( SQLSTATE || ':' || SQLERRM ); END; $$ ;
**Note** ---- SQLERRM provided by PostgreSQL cannot specify an error code in its argument. ---- ##### 5.2.2.5 WHENEVER **Description** WHENEVER SQLERROR predefines the processing to be run when an error occurs in an SQL statement or PL/SQL. WHENEVER OSERROR predefines the processing to be run when an operating system error occurs. **Functional differences** - **Oracle database** - WHENEVER can be used to predefine the processing to be run when an error occurs. - **PostgreSQL** - WHENEVER cannot be used. **Migration procedure** Use the following procedure to perform migration: 1. Search for the keyword WHENEVER and identify where it is used. 2. Replace WHENEVER SQLERROR EXIT FAILURE syntax or WHENEVER OSERROR EXIT FAILURE syntax with \set ON_ERROR_STOP ON. **Migration example** The example below shows migration when an active script that encounters an error is stopped.
Oracle database PostgreSQL
WHENEVER SQLERROR EXIT FAILURE 

DECLARE v_i_number SMALLINT := 401; v_i_name VARCHAR2(30) := 'liquid crystal television'; v_i_quantity INTEGER := 100; v_i_warehouse SMALLINT := 2; BEGIN INSERT INTO inventory_table VALUES ( v_i_number, v_i_name, v_i_quantity, v_i_warehouse ); END; /
\set ON_ERROR_STOP ON 
 DO $$ 
 DECLARE 
  v_i_number SMALLINT := 401; 
  v_i_name VARCHAR(30) := 'liquid crystal television'; 
  v_i_quantity INTEGER := 100; 
  v_i_warehouse SMALLINT := 2; 
 BEGIN 
  INSERT INTO inventory_table 
   VALUES ( v_i_number, 
            v_i_name, 
            v_i_quantity, 
            v_i_warehouse ); 
 END; 
 $$ 
 ;
**Note** ---- - WHENEVER SQLERROR and WHENEVER OSERROR are SQL*Plus features. Migrate them to the psql feature in PostgreSQL. - Of the values that can be specified in WHENEVER, only EXIT FAILURE and CONTINUE NONE can be migrated. If CONTINUE NONE is specified, replace it with \set ON_ERROR_ROLLBACK ON. ---- #### 5.2.3 Cursor-Related Elements This section explains elements related to PL/SQL cursors. ##### 5.2.3.1 %FOUND **Description** %FOUND obtains information on whether an SQL statement affected one or more rows. **Functional differences** - **Oracle database** - %FOUND can be used. - **PostgreSQL** - %FOUND cannot be used. Use FOUND instead. **Migration procedure** Use the following procedure to perform migration with FOUND: - When there is one implicit or explicit cursor 1. Search for the keyword %FOUND and identify where it is used. 2. Change the portion that calls cursorName%FOUND to FOUND. - When there are multiple explicit cursors 1. Search for the keyword %FOUND and identify where it is used. 2. Using DECLARE, declare the same number of BOOLEAN variables as explicit cursors. 3. Immediately after each FETCH statement, store the value obtained by FOUND in the variable declared in step 2. 4. Replace the portion that calls cursorName%FOUND with the variable used in step 3. **Migration example** The example below shows migration when update of a row by an implicit cursor is checked.
Oracle database PostgreSQL
SET SERVEROUTPUT ON; 
 BEGIN 

UPDATE inventory_table SET i_warehouse = 3 WHERE i_name = 'television'; IF SQL%FOUND THEN DBMS_OUTPUT.PUT_LINE ( 'Updated!' ); ELSE DBMS_OUTPUT.PUT_LINE ( 'Not Updated!' ); END IF; END; /
DO $$ 
 BEGIN 
  PERFORM DBMS_OUTPUT.SERVEROUTPUT(TRUE); 
  UPDATE inventory_table SET i_warehouse = 3 
   WHERE i_name = 'television'; 
  IF FOUND THEN 
   PERFORM DBMS_OUTPUT.PUT_LINE( 'Updated!' ); 
  ELSE 
   PERFORM DBMS_OUTPUT.PUT_LINE( 'Not updated!' ); 
  END IF; 
 END; 
 $$ 
 ;
**Note** ---- Statements in which %FOUND is determined to be NULL cannot be migrated. If SQL has not been executed at all, FOUND is set to FALSE, which is the same return value as when no row has been affected. ---- ##### 5.2.3.2 %NOTFOUND **Description** %NOTFOUND obtains information on whether an SQL statement affected no rows. **Functional differences** - **Oracle database** - %NOTFOUND can be used. - **PostgreSQL** - %NOTFOUND cannot be used. Use NOT FOUND instead. **Migration procedure** Use the following procedure to perform migration: - When there is one implicit or explicit cursor 1. Search for the keyword %NOTFOUND and identify where it is used. 2. Change the portion that calls cursorName%NOTFOUND to NOT FOUND. - When there are multiple explicit cursors 1. Search for the keyword %NOTFOUND and identify where it is used. 2. Using DECLARE, declare the same number of BOOLEAN variables as explicit cursors. 3. Immediately after each FETCH statement, store the value obtained by FOUND in the variable declared in step 2. 4. Replace the portion that calls cursorName%NOTFOUND with negation of the variable used in step 3. **Migration example** The example below shows migration when multiple explicit cursors are used to repeat FETCH until there are no more rows in one of the tables.
Oracle database PostgreSQL
 SET SERVEROUTPUT ON; 
 DECLARE 
  CURSOR cur1 IS 
   SELECT i_number, i_name 
    FROM inventory_table 
    WHERE i_name = 'television'; 
  CURSOR cur2 IS 
   SELECT i_number, i_name 
    FROM inventory_table 
    WHERE i_name = 'cd player'; 
  v1_i_number inventory_table.i_number%TYPE; 
  v2_i_number inventory_table.i_number%TYPE; 
  v1_i_name inventory_table.i_name%TYPE; 
  v2_i_name inventory_table.i_name%TYPE; 


BEGIN
OPEN cur1; OPEN cur2; LOOP FETCH cur1 into v1_i_number, v1_i_name;
FETCH cur2 into v2_i_number, v2_i_name;
EXIT WHEN ( cur1%NOTFOUND ) OR ( cur2%NOTFOUND ); DBMS_OUTPUT.PUT_LINE( 'No.' || v1_i_number || ': ' || v1_i_name ); DBMS_OUTPUT.PUT_LINE( 'No.' || v2_i_number || ': ' || v2_i_name ); END LOOP; CLOSE cur1; CLOSE cur2; END; /
DO $$ 
 DECLARE 
  cur1 CURSOR FOR 
   SELECT i_number, i_name 
    FROM inventory_table 
    WHERE i_name = 'television'; 
  cur2 CURSOR FOR 
   SELECT i_number, i_name 
    FROM inventory_table 
    WHERE i_name = 'cd player'; 
  v1_i_number inventory_table.i_number%TYPE; 
  v2_i_number inventory_table.i_number%TYPE; 
  v1_i_name inventory_table.i_name%TYPE; 
  v2_i_name inventory_table.i_name%TYPE; 
  flg1 BOOLEAN; 
  flg2 BOOLEAN; 
 BEGIN 
  PERFORM DBMS_OUTPUT.SERVEROUTPUT( TRUE ); 
  OPEN cur1; 
  OPEN cur2; 
  LOOP 
   FETCH cur1 into v1_i_number, v1_i_name; 
   flg1 := FOUND; 
   FETCH cur2 into v2_i_number, v2_i_name; 
   flg2 := FOUND; 
   EXIT WHEN ( NOT flg1 ) OR ( NOT flg2 ); 
   PERFORM DBMS_OUTPUT.PUT_LINE( 
    'No.' || v1_i_number || ': ' || v1_i_name ); 
   PERFORM DBMS_OUTPUT.PUT_LINE( 
    'No.' || v2_i_number || ': ' || v2_i_name ); 
  END LOOP; 
  CLOSE cur1; 
  CLOSE cur2; 
 END; 
 $$ 
 ;
**Note** ---- Statements in which %NOTFOUND is determined to be NULL cannot be migrated. If SQL has not been executed at all, FOUND is set to FALSE, which is the same return value as when no row has been affected. ---- ##### 5.2.3.3 %ROWCOUNT **Description** %ROWCOUNT indicates the number of rows processed by an SQL statement. **Functional differences** - **Oracle database** - %ROWCOUNT can be used. - **PostgreSQL** - %ROWCOUNT cannot be used. Use ROW_COUNT instead. **Migration procedure** Use the following procedure to perform migration: 1. Search for the keyword %ROWCOUNT and identify where it is used. 2. Declare the variable that will store the value obtained by ROW_COUNT. 3. Use GET DIAGNOSTICS immediately in front of %ROWCOUNT identified in step 1. It obtains ROW_COUNT and stores its value in the variable declared in step 2. 4. Replace the portion that calls %ROWCOUNT with the variable used in step 3. **Migration example** The example below shows migration when the number of deleted rows is obtained.
Oracle database PostgreSQL
SET SERVEROUTPUT ON; 


BEGIN
DELETE FROM inventory_table WHERE i_name = 'television';
DBMS_OUTPUT.PUT_LINE ( TO_CHAR( SQL%ROWCOUNT ) || 'rows deleted!' ); END; /
DO $$ 
 DECLARE 
  row_num INTEGER; 
 BEGIN 
  PERFORM DBMS_OUTPUT.SERVEROUTPUT( TRUE ); 
  DELETE FROM inventory_table 
   WHERE i_name = 'television'; 
  GET DIAGNOSTICS row_num := ROW_COUNT; 
  PERFORM DBMS_OUTPUT.PUT_LINE( 
   TO_CHAR( row_num ) || 'rows deleted!' ); 
 END; 
 $$ 
 ;
**Note** Statements in which %ROWCOUNT is determined to be NULL cannot be migrated. If SQL has not been executed at all, 0 is set. ##### 5.2.3.4 REF CURSOR **Description** REF CURSOR is a data type that represents the cursor in Oracle databases. **Functional differences** - **Oracle database** - REF CURSOR type variables can be defined. - **PostgreSQL** - REF CURSOR type variables cannot be defined. Use refcursor type variables instead. **Migration procedure** Use the following procedure to perform migration: 1. Search for the keyword REF CURSOR and identify where it is used. 2. Delete the REF CURSOR type definition and the portion where the cursor variable is declared using that type. 3. Change the specification so that the cursor variable is declared using the refcursor type. **Migration example** The example below shows migration when the cursor variable is used to FETCH a row.
Oracle database PostgreSQL
SET SERVEROUTPUT ON; 
 DECLARE 
  TYPE curtype IS REF CURSOR; 
  cur curtype; 
  v_inventory inventory_table%ROWTYPE; 
 BEGIN 

OPEN cur FOR SELECT * FROM inventory_table WHERE i_warehouse = 2; DBMS_OUTPUT.PUT_LINE( 'In warehouse no.2 is :' );
LOOP FETCH cur into v_inventory; EXIT WHEN cur%NOTFOUND; DBMS_OUTPUT.PUT_LINE( 'No.' || v_inventory.i_number || ': ' || v_inventory.i_name || '(' || v_inventory.i_quantity || ')' ); END LOOP; CLOSE cur; END; /
DO $$ 
 DECLARE 
  cur refcursor; 

v_inventory inventory_table%ROWTYPE; BEGIN PERFORM DBMS_OUTPUT.SERVEROUTPUT(TRUE); OPEN cur FOR SELECT * FROM inventory_table WHERE i_warehouse = 2; PERFORM DBMS_OUTPUT.PUT_LINE( 'In warehouse no.2 is :' ); LOOP FETCH cur into v_inventory; EXIT WHEN NOT FOUND; PERFORM DBMS_OUTPUT.PUT_LINE( 'No.' || v_inventory.i_number || ': ' || v_inventory.i_name || '(' || v_inventory.i_quantity || ')' ); END LOOP; CLOSE cur; END; $$ ;
**Note** ----- The RETURN clause (specifies the return type of the cursor itself) cannot be specified in the refcursor type provided by PostgreSQL. ----- ##### 5.2.3.5 FORALL **Description** FORALL uses the changing value of the VALUES clause or WHERE clause to execute a single command multiple times. **Functional differences** - **Oracle database** - FORALL statements can be used. - **PostgreSQL** - FORALL statements cannot be used. **Migration procedure** FORALL statements cannot be used, so replace them with FOR statements so that the same result is returned. Use the following procedure to perform migration: 1. Search for the keyword FORALL and identify where it is used. 2. Store the elements used by commands within FORALL in array type variables. In addition, delete Oracle database array definitions. 3. Replace FORALL statements with FOR - LOOP statements. 4. Replace portions that reference an array in the Oracle database with referencing of the array type variable defined in step 2. The portions changed in the migration example and details of the changes are as follows: - Start of the loop: Change i_numL.FIRST to 1. - End of the loop: Replace i_numL.LAST with ARRAY_LENGTH. - Referencing of array elements: Change i_numL(i) to i_numL[i]. **Migration example** The example below shows migration when FORALL is used to execute INSERT.
Oracle database PostgreSQL
 
 DECLARE 
   TYPE NumList IS TABLE OF SMALLINT; 
   i_numL NumList := NumList( 151, 
                              152, 
                              153, 
                              154, 
                              155 ); 
 BEGIN 
   FORALL i IN i_numL.FIRST .. i_numL.LAST 
     INSERT INTO inventory_table 
     VALUES ( i_numL(i), 'television', 10, 2 ); 

END; /
DO $$ 
 DECLARE 

i_numL SMALLINT ARRAY := '{ 151, 152, 153, 154, 155 }'; BEGIN FOR i IN 1..ARRAY_LENGTH( i_numL, 1 ) LOOP INSERT INTO inventory_table VALUES ( i_numL[i], 'television', 10, 2 ); END LOOP; END; $$ ;
### 5.3 Migrating Functions This section explains how to migrate PL/SQL functions. **Description** A stored function is a user-defined function that returns a value. #### 5.3.1 Defining Functions **Functional differences** - **Oracle database** - A RETURN clause within a function prototype is specified as RETURN.
DECLARE does not need to be specified as the definition portion of a variable used within a function. - **PostgreSQL** - Use RETURNS to specify a RETURN clause within a function prototype.
DECLARE must be specified as the definition portion of a variable to be used within a function. **Migration procedure** Use the following procedure to perform migration: 1. Search for the keywords CREATE and FUNCTION, and identify where user-defined functions are created. 2. If an IN or OUT qualifier is specified in an argument, move it to the beginning of the parameters. 3. Change RETURN within the function prototype to RETURNS. 4. Change the AS clause to AS $$. (If the keyword is IS, change it to AS.) 5. If a variable is defined, add the DECLARE keyword after $$. 6. Delete the final slash (/) and specify $$ and a LANGUAGE clause. **Migration example** The example below shows migration when CREATE FUNCTION is used to define a function.
Oracle database PostgreSQL
CREATE FUNCTION PROFIT_FUNC( 
  selling IN INTEGER, 
  sales_num IN INTEGER, 
  cost IN INTEGER 
 ) RETURN INTEGER AS 

profit INTEGER; BEGIN profit := ( ( selling * sales_num ) - cost ); RETURN profit; END; /
CREATE FUNCTION PROFIT_FUNC( 
  IN selling INTEGER, 
  IN sales_num INTEGER, 
  IN cost INTEGER 
 ) RETURNS INTEGER AS $$ 
 DECLARE 
     profit INTEGER; 
 BEGIN 
     profit := ( ( selling * sales_num ) - cost ); 
     RETURN profit; 
 END; 
 $$ LANGUAGE plpgsql;
### 5.4 Migrating Procedures This section explains how to migrate PL/SQL procedures. **Description** A stored procedure is a single procedure into which multiple processes have been grouped. #### 5.4.1 Defining Procedures **Functional differences** - **Oracle database** - Procedures can be created. - **PostgreSQL** - Procedures cannot be created. **Migration procedure** Procedures cannot be created in PostgreSQL. Therefore, replace them with functions. Use the following procedure to perform migration: 1. Search for the keywords CREATE and PROCEDURE, and identify where a procedure is defined. 2. Replace the CREATE PROCEDURE statement with the CREATE FUNCTION statement. 3. Change the AS clause to RETURNS VOID AS $$. (If the keyword is IS, change it to AS.) 4. If a variable is defined, add the DECLARE keyword after $$. 5. Delete the final slash (/) and specify $$ and a LANGUAGE clause. **Note** ---- If the OUT or INOUT keywords are specified in the arguments, a different migration method must be used. Refer to "Defining Procedures That Return a Value". ---- **Migration example** The example below shows migration when a procedure is defined.
Oracle database PostgreSQL
CREATE PROCEDURE UPD_QUANTITY ( 
  upd_number SMALLINT, 
  upd_quantity INTEGER 
 ) AS 
   BEGIN 
     UPDATE inventory_table 
 SET i_quantity = upd_quantity 
       WHERE i_number = upd_number; 
   END; 
 / 
 ------------------------------------------------- 

DECLARE v_i_number SMALLINT := 110; v_i_quantity INTEGER := 100; BEGIN upd_quantity( v_i_number, v_i_quantity ); END; /
CREATE FUNCTION UPD_QUANTITY ( 
  upd_number SMALLINT, 
  upd_quantity INTEGER 
 ) RETURNS VOID AS $$ 
 BEGIN 
     UPDATE inventory_table 
 SET i_quantity = upd_quantity 
       WHERE i_number = upd_number; 
 END; 
 $$ LANGUAGE plpgsql; 
 ------------------------------------------------- 
 DO $$ 
 DECLARE 
   v_i_number SMALLINT := 110; 
   v_i_quantity INTEGER := 100; 
 BEGIN 
   PERFORM upd_quantity( v_i_number, v_i_quantity ); 
 END; 
 $$ 
 ;
#### 5.4.2 Calling Procedures **Functional differences** - **Oracle database** - A procedure can be called as a statement. - **PostgreSQL** - Procedures cannot be used. Instead, call the procedure as a function that does not return a value. **Migration procedure** Use the following procedure to perform migration: 1. Identify where each procedure is called. 2. Specify PERFORM in front of the procedure call. **Migration example** The example below shows migration when a procedure is called.
Oracle database PostgreSQL
SET SERVEROUTPUT ON; 
 BEGIN 

DBMS_OUTPUT.PUT_LINE( 'Hello World.' ); END; /
DO $$ 
 BEGIN 
   PERFORM DBMS_OUTPUT.SERVEROUTPUT( TRUE ); 
   PERFORM DBMS_OUTPUT.PUT_LINE( 'Hello World.' ); 
 END; 
 $$ 
 ;
#### 5.4.3 Defining Procedures That Return a Value **Functional differences** - **Oracle database** - Procedures that return a value can be created. - **PostgreSQL** - Procedures that return a value cannot be created. **Migration procedure** Use the following procedure to perform migration: 1. Search for the CREATE and PROCEDURE keywords, and identify where a procedure is defined. 2. Confirm that the OUT or INOUT keyword is specified in the arguments. 3. Replace the CREATE PROCEDURE statement with the CREATE FUNCTION statement. 4. If the IN, OUT, or INOUT keyword is specified in the arguments, move it to the beginning of the arguments. 5. Change the AS clause to AS $$. (If the keyword is IS, change it to AS.) 6. If a variable is defined, add the DECLARE keyword after $$. 7. Delete the final slash (/) and specify $$ and a LANGUAGE clause. 8. If calling a function, call it without specifying arguments in the OUT parameter and store the return value in the variable. If there are multiple OUT parameters, use a SELECT INTO statement. **Migration example** The example below shows migration when the OUT parameter of CREATE PROCEDURE is used to define a procedure that returns a value.
Oracle database PostgreSQL
 CREATE PROCEDURE remove_row ( 
  del_name VARCHAR2, 
  del_row OUT INTEGER 
 ) AS 
  BEGIN 
   DELETE FROM inventory_table 
    WHERE i_name = del_name; 
   del_row := SQL%ROWCOUNT; 
  END; 
 / 
 ------------------------------------------------- 
 SET SERVEROUTPUT ON; 
 DECLARE 
  rtn_row INTEGER; 
  v_i_name VARCHAR2(20) := 'television'; 
 BEGIN 

remove_row( v_i_name, rtn_row ); DBMS_OUTPUT.PUT_LINE( TO_CHAR( rtn_row ) || 'rows deleted!' ); END; /
CREATE FUNCTION remove_row ( 
  del_name VARCHAR, 
  OUT del_row INTEGER 
 ) AS $$ 
  BEGIN 
   DELETE FROM inventory_table 
    WHERE i_name = del_name; 
   GET DIAGNOSTICS del_row := ROW_COUNT; 
  END; 
 $$ LANGUAGE plpgsql; 
 ------------------------------------------------- 
 DO $$ 
 DECLARE 
  rtn_row INTEGER; 
  v_i_name VARCHAR(20) := 'television'; 
 BEGIN 
  PERFORM DBMS_OUTPUT.SERVEROUTPUT( TRUE ); 
  rtn_row := remove_row( v_i_name ); 
  PERFORM DBMS_OUTPUT.PUT_LINE( 
   TO_CHAR( rtn_row ) || 'rows deleted!' ); 
 END; 
 $$ 
 ;
**See** ---- Refer to "Defining Nested Procedures" for examples of migrating a call portion that uses a SELECT INTO statement. ---- #### 5.4.4 Defining Nested Procedures **Functional differences** - **Oracle database** - Nested procedures can be defined. - **PostgreSQL** - Nested procedures cannot be defined. **Migration procedure** Procedures must be replaced with functions, but functions cannot be nested in PostgreSQL. Therefore, define and call the functions separately. Use the following procedure to perform migration: 1. Search for the CREATE and PROCEDURE keywords, and identify where a procedure is defined. 2. If a PROCEDURE statement is defined in a DECLARE clause, regard it as a nested procedure. 3. Check for variables that are used by both the procedure and the nested procedure. 4. Replace a nested procedure (from PROCEDURE procedureName to END procedureName;) with a CREATE FUNCTION statement. Specify the variables you found in step 3 in the INOUT argument of CREATE FUNCTION. 5. Replace the portion that calls the nested procedure with a SELECT INTO statement. Specify the common variables you found in step 3 in both the variables used for calling the function and the variables used for accepting the INTO clause. **Migration example** The example below shows migration when nested procedures are used and a variable is shared by a procedure and its call portion.
Oracle database PostgreSQL
SET SERVEROUTPUT ON; 
 DECLARE 
  sales_num INTEGER; 
  stock_num INTEGER; 
  v_i_quantity INTEGER; 
  PROCEDURE quantity_check ( 
   sales INTEGER, 
   stock INTEGER 
  ) IS 
   quantity_err EXCEPTION; 
  BEGIN 

v_i_quantity := ( stock - sales ); IF ( v_i_quantity < 0 ) THEN RAISE quantity_err; END IF; EXCEPTION WHEN quantity_err THEN DBMS_OUTPUT.PUT_LINE( 'ERR: i_quantity is negative value.' ); END quantity_check;



BEGIN
sales_num := 80; stock_num := 100; quantity_check( sales_num, stock_num );
DBMS_OUTPUT.PUT_LINE( 'i_quantity: ' || v_i_quantity );
sales_num := 100; stock_num := 80; quantity_check( sales_num, stock_num );
DBMS_OUTPUT.PUT_LINE( 'i_quantity: ' || v_i_quantity ); END; /



 
 CREATE FUNCTION quantity_check( 
  sales INTEGER, 
  stock INTEGER, 
  INOUT quantity INTEGER 
 ) AS $$ 

BEGIN PERFORM DBMS_OUTPUT.SERVEROUTPUT( TRUE ); quantity := ( stock - sales ); IF ( quantity < 0 ) THEN RAISE USING ERRCODE = '20001'; END IF; EXCEPTION WHEN SQLSTATE '20001' THEN PERFORM DBMS_OUTPUT.PUT_LINE( 'ERR: i_quantity is negative value.' ); END; $$ LANGUAGE plpgsql; ------------------------------------------------- DO $$ DECLARE sales_num INTEGER; stock_num INTEGER; v_i_quantity INTEGER; BEGIN PERFORM DBMS_OUTPUT.SERVEROUTPUT( TRUE ); sales_num := 80; stock_num := 100; SELECT quantity INTO v_i_quantity FROM quantity_check( sales_num, stock_num, v_i_quantity ); PERFORM DBMS_OUTPUT.PUT_LINE( 'i_quantity: ' || v_i_quantity );
sales_num := 100; stock_num := 80; SELECT quantity INTO v_i_quantity FROM quantity_check( sales_num, stock_num, v_i_quantity ); PERFORM DBMS_OUTPUT.PUT_LINE( 'i_quantity: ' || v_i_quantity ); END; $$ ;
#### 5.4.5 Defining Anonymous Code Blocks **Description** An anonymous code block generates and executes a temporary function within a procedural language. **Functional differences** - **Oracle database** - Anonymous code blocks that are enclosed with (DECLARE) BEGIN to END can be executed. - **PostgreSQL** - PL/pgSQL blocks ((DECLARE) BEGIN to END) that are enclosed with DO $$ to $$ can be executed. **Migration procedure** Use the following procedure to perform migration: 1. Search for the keywords DECLARE and BEGIN, and identify where an anonymous code block is defined. 2. Specify DO $$ at the beginning of the anonymous code block. 3. Delete the final slash (/) and specify $$. **Migration example** The example below shows migration when an anonymous code block is defined.
Oracle database PostgreSQL
SET SERVEROUTPUT ON; 
 BEGIN 

DBMS_OUTPUT.PUT_LINE( 'Hello World.' ); END; /
DO $$ 
 BEGIN 
     PERFORM DBMS_OUTPUT.SERVEROUTPUT( TRUE ); 
     PERFORM DBMS_OUTPUT.PUT_LINE( 'Hello World.' ); 
 END; 
 $$ 
 ;
### 5.5 Migrating Packages This section explains how to migrate PL/SQL packages. **Description** A package defines and contains procedures and functions as a single relationship group in the database. **Functional differences** - **Oracle database** - Packages can be created. - **PostgreSQL** - Packages cannot be created. Packages cannot be created in PostgreSQL, so define a schema with the same name as the package and define functions that have a relationship in the schema so that they are treated as a single group. In the following sections, the migration procedure is explained for each feature to be defined in a package. #### 5.5.1 Defining Functions Within a Package **Functional differences** - **Oracle database** - Functions can be created within a package. - **PostgreSQL** - The package itself cannot be created. **Migration procedure** Use the following procedure to perform migration: 1. Search for the keywords CREATE and PACKAGE, and identify where they are defined. 2. Define a schema with the same name as the package. 3. If a FUNCTION statement is specified within a CREATE PACKAGE BODY statement, define, within the schema created in step 2, the functions that were defined within the package. **Migration example** The example below shows migration when a package is defined and functions are created within that package.
Oracle database PostgreSQL
CREATE PACKAGE smpl_pkg AS 
   FUNCTION remove_row( rm_i_name VARCHAR2 ) 
     RETURN INTEGER; 
 END smpl_pkg; 
 / 
 CREATE PACKAGE BODY smpl_pkg AS 
   FUNCTION remove_row( rm_i_name VARCHAR2 ) 
     RETURN INTEGER IS 

rtn_row INTEGER; BEGIN DELETE FROM inventory_table WHERE i_name = rm_i_name;
RETURN(SQL%ROWCOUNT); END; END smpl_pkg; /
CREATE SCHEMA smpl_scm; 




CREATE FUNCTION smpl_scm.remove_row( rm_i_name VARCHAR ) RETURNS INTEGER AS $$ DECLARE rtn_row INTEGER; BEGIN DELETE FROM inventory_table WHERE i_name = rm_i_name; GET DIAGNOSTICS rtn_row := ROW_COUNT; RETURN rtn_row; END; $$ LANGUAGE plpgsql;
**See** ---- Refer to "Defining Functions" for information on migrating FUNCTION statements within a package. ---- #### 5.5.2 Defining Procedures Within a Package **Functional differences** - **Oracle database** - Procedures can be created within a package. - **PostgreSQL** - The package itself cannot be created. **Migration procedure** Use the following procedure to perform migration: 1. Search for the keywords CREATE and PACKAGE, and identify where they are defined. 2. Define a schema with the same name as the package. 3. If a PROCEDURE statement is specified within a CREATE PACKAGE BODY statement, migrate the procedures that were defined within the package to functions and define them within the schema created in step 2. **Migration example** The example below shows migration when a package is defined and procedures are created within that package.
Oracle database PostgreSQL
CREATE PACKAGE smpl_pkg AS 
  PROCEDURE increase_row( 
   add_i_num SMALLINT, 
   add_i_name VARCHAR2, 
   add_i_quantity INTEGER, 
   add_i_warehouse SMALLINT 
  ); 
  END smpl_pkg; 
 / 
 CREATE PACKAGE BODY smpl_pkg AS 
  PROCEDURE increase_row( 
   add_i_num SMALLINT, 
   add_i_name VARCHAR2, 
   add_i_quantity INTEGER, 
   add_i_warehouse SMALLINT 
  ) IS 
   BEGIN 
    INSERT INTO inventory_table 
     VALUES ( add_i_num, 
              add_i_name, 
              add_i_quantity, 
              add_i_warehouse ); 
     END; 
 END smpl_pkg; 
 /
CREATE SCHEMA smpl_scm; 









CREATE FUNCTION smpl_scm.increase_row( add_i_num SMALLINT, add_i_name VARCHAR, add_i_quantity INTEGER, add_i_warehouse SMALLINT ) RETURNS VOID AS $$ BEGIN INSERT INTO inventory_table VALUES ( add_i_num, add_i_name, add_i_quantity, add_i_warehouse ); END; $$ LANGUAGE plpgsql;
**See** ---- Refer to "Defining Procedures" for information on migrating PROCEDURE statements within a package. ---- #### 5.5.3 Sharing Variables Within a Package **Functional differences** - **Oracle database** - Variables can be shared within a package. - **PostgreSQL** - A package cannot be created, so variables cannot be shared. **Migration procedure** Use a temporary table instead of variables within a package. Use the following procedure to perform migration: 1. Search for the keywords CREATE and PACKAGE, and identify where they are defined. 2. Check for variables defined directly in a package. 3. Create a temporary table that defines the variables checked in step 2 in a column. 4. Insert one record to the temporary table created in step 3. (The set value is the initial value specified within the package.) 5. Replace the respective portions that reference a variable and set a variable with SQL statements. - To reference a variable, use a SELECT INTO statement to store a value in the variable and then reference it. (A variable for referencing a variable must be defined separately.) - To update a variable, use an UPDATE statement and update the target column. **Migration example** The example below shows migration when a package is defined and variables within the package are shared.
Oracle database PostgreSQL
SET SERVEROUTPUT ON; 
 CREATE PACKAGE row_pkg AS 
   PROCEDURE set_item( item INTEGER ); 
   i_item INTEGER; 
 END row_pkg; 
 / 
 CREATE PACKAGE BODY row_pkg AS 

PROCEDURE set_item( item INTEGER ) IS BEGIN i_item := item; END; END row_pkg; / ------------------------------------------------- SET SERVEROUTPUT ON;





BEGIN
row_pkg.set_item( 1000 );

DBMS_OUTPUT.PUT_LINE( 'ITEM :' || row_pkg.i_item ); row_pkg.set_item(2000);

DBMS_OUTPUT.PUT_LINE( 'ITEM :' || row_pkg.i_item ); END; /
CREATE SCHEMA row_pkg; 







CREATE FUNCTION row_pkg.set_item( item INTEGER ) RETURNS VOID AS $$ BEGIN UPDATE row_pkg_variables SET i_item = item; END; $$ LANGUAGE plpgsql;
------------------------------------------------- CREATE TEMP TABLE row_pkg_variables ( i_item INTEGER ); INSERT INTO row_pkg_variables VALUES (0);
DO $$ DECLARE g_item INTEGER; BEGIN PERFORM DBMS_OUTPUT.SERVEROUTPUT( TRUE ); PERFORM row_pkg.set_item( 1000 ); SELECT i_item INTO g_item FROM row_pkg_variables; PERFORM DBMS_OUTPUT.PUT_LINE( 'ITEM :' || g_item ); PERFORM row_pkg.set_item(2000); SELECT i_item INTO g_item FROM row_pkg_variables; PERFORM DBMS_OUTPUT.PUT_LINE( 'ITEM :' || g_item ); END; $$ ;
orafce-VERSION_3_9_0/doc/sql_migration/sql_migration06.md000066400000000000000000002161601362147214200233160ustar00rootroot00000000000000Chapter 6 Notes on Using orafce --- This chapter provides notes on using Oracle database compatibility features added by orafce. ### 6.1 Data Types This section explains how to migrate data types added by orafce. #### 6.1.1 Notes on VARCHAR2 This section provides notes on VARCHAR2. ##### 6.1.1.1 Specifying the Maximum Number of Bytes and Maximum Number of Characters **Functional differences** - **Oracle database** - Specifying the keyword BYTE or CHAR after a size enables the size to be indicated in terms of the maximum number of bytes or the maximum number of characters. - **PostgreSQL** - The keyword BYTE or CHAR cannot be set after the size. **Migration procedure** Use the following procedure to perform migration: 1. Search for the keyword VARCHAR2 and check if the keyword BYTE or CHAR is specified after the size. 2. If the BYTE keyword is specified, delete it. 3. If the CHAR keyword is specified, delete it and convert the data type to VARCHAR. **Migration example** The example below shows migration when the maximum number of bytes or the maximum number of characters for the VARCHAR2 type is specified.
Oracle database PostgreSQL
CREATE TABLE t1( 
  col1 VARCHAR2(5 BYTE), 
  col2 VARCHAR2(5 CHAR) 
 );
CREATE TABLE t1( 
  col1 VARCHAR2(5), 
  col2 VARCHAR(5) 
 );
**Note** ---- The VARCHAR2 type does not support collating sequences. Therefore, the following error occurs when a collating sequence like that of an ORDER BY clause is required. At this time, the following HINT will prompt to use a COLLATE clause, however, because collating sequences are not supported, it is not possible to use this clause. ~~~ ERROR: could not determine which collation to use for string comparison HINT: Use the COLLATE clause to set the collation explicitly. ~~~ If the error shown above is displayed, explicitly cast the column to VARCHAR or TEXT type. ---- ### 6.2 Functions This section explains how to migrate functions added by orafce. #### 6.2.1 INSTRB **Description** INSTRB searches for a substring in a string and returns the start position (in bytes) of the first occurrence of the substring. ##### 6.2.1.1 Obtaining the Start Position of a Substring (in Bytes) **Functional differences** - **Oracle database** - INSTRB searches for a substring in a string and returns the start position (in bytes) of the substring. - **PostgreSQL** - There is no INSTRB function. Use STRPOSB instead. STRPOSB is unique to orafce. **Migration procedure** Use the following procedure to migrate to STRPOSB: 1. Search for the keyword INSTRB and identify where it is used. 2. Confirm that arguments up to the second argument are specified. 3. Change INSTRB to STRPOSB. **Migration example** The example below shows migration when searching for a particular substring in a string, and returning the start position of the substring in bytes.
Oracle database PostgreSQL
SELECT c_code, INSTRB( c_address, ',' ) 
  FROM company_table;
SELECT c_code, STRPOSB( c_address, ',' ) 
  FROM company_table;
**Note** ---- If the third argument is specified in INSTRB, refer to the conversion example shown below. If the fourth argument is specified, migration is not possible. ---- **Information** ---- The general rules for STRPOSB are as follows: ---- **Description** INSTRB returns the start position (in bytes) of a substring within a string. **Specification format** ![STRPOSB](gif/STRPOSB.gif) **General rules** - STRPOSB searches for string *str2* in *str1* and returns the start position it finds in bytes. - If *str2* is not found, 0 is returned. - The data type of the return value is INTEGER. ##### 6.2.1.2 Obtaining the Start Position of a Substring from a Specified Search Start Position (in Bytes) **Functional differences** - **Oracle database** - The search start position is specified in the third argument of INSTRB. - **PostgreSQL** - A search start position cannot be specified with STRPOSB. **Migration procedure** A search start position cannot be specified, so truncate the search target string to the start position so that the same result is returned. Use the following procedure to perform migration: 1. Search for the keyword INSTRB and identify where it is used. 2. Confirm that arguments up to the third argument are specified and that a positive number is specified. 3. Enclose the string specified in the first argument with SUBSTRB, and specify the value specified in the third argument of INSTRB as the second argument of SUBSTRB. 4. Change INSTRB to STRPOSB and delete the value specified in the third argument. 5. Enclose the function in a simple CASE expression to evaluate the result of the function changed in step 4.
Define the selector so that 0 is returned when the result is 0.
If the result is not 0, specify the same function as in step 4, and add the value obtained by subtracting 1 from the value specified in the second argument of SUBSTRB. **Migration example** The example below shows migration when a search start position is specified and then the start position of a string is found in bytes.
Oracle database PostgreSQL
SELECT c_code, INSTRB( c_address, '-', 10 ) 
 FROM company_table; 




SELECT c_code, 
 CASE STRPOSB( SUBSTRB( c_address, 10 ),'-') 
 WHEN 0 THEN 0 
 ELSE STRPOSB( SUBSTRB( c_address, 10 ), '-' ) + 9 
 END 
 FROM company_table;
#### 6.2.2 INSTRC, INSTR2, and INSTR4 **Description** INSTRC, INSTR2, and INSTR4 return the start position of a substring in a string using the relevant encoding. **Functional differences** - **Oracle database** - INSTRC, INSTR2, and INSTR4 use the relevant encoding to search for a substring in a string from a specified position and then return the start position of the substring. - **PostgreSQL** - There are no INSTRC, INSTR2, and INSTR4 functions. Only Unicode encoding is used in PostgreSQL. **Migration procedure** Use the following procedure to migrate to INSTR: 1. Search for the keywords INSTRC, INSTR2, and INSTR4, and identify where they are used. 2. Change those keywords to INSTR. **Migration example** The example below shows migration from INSTRC, INSTR2, and INSTR4.
Oracle database PostgreSQL
 SELECT c_name, INSTRC( c_name, 'Corp', 2, 1 ) 
  FROM company_table; 

SELECT c_name, INSTR2( c_name, 'Corp', 2, 1 ) FROM company_table;
SELECT c_name, INSTR4( c_name, 'Corp', 2, 1 ) FROM company_table;
SELECT c_name, INSTR( c_name, 'Corp', 2, 1 ) 
  FROM company_table; 






#### 6.2.3 LENGTHC, LENGTH2, and LENGTH4 **Description** LENGTHC, LENGTH2, and LENGTH4 use the relevant encoding to return the length of the specified string. **Functional differences** - **Oracle database** - LENGTHC, LENGTH2, and LENGTH4 use the relevant encoding to return the length of the specified string. - **PostgreSQL** - There are no LENGTHC, LENGTH2, and LENGTH4 functions. Only Unicode encoding is used in PostgreSQL. **Migration procedure** Use the following procedure to migrate to LENGTH: 1. Search for the keywords LENGTHC, LENGTH2, and LENGTH4, and identify where they are used. 2. Change those keywords to LENGTH. **Migration example** The example below shows migration from LENGTHC, LENGTH2, and LENGTH4.
Oracle database PostgreSQL
 SELECT name, LENGTHC( name ) 
  FROM staff_table 
  WHERE job = 'sales member'; 

SELECT name, LENGTH2( name ) FROM staff_table WHERE job = 'sales member';
SELECT name, LENGTH4( name ) FROM staff_table WHERE job = 'sales member';
 SELECT name, LENGTH( name ) 
  FROM staff_table 
  WHERE job = 'sales member'; 








#### 6.2.4 LISTAGG **Description** LISTAGG returns a concatenated, delimited list of string values. ##### 6.2.4.1 Specifying the Join Sequence for a List **Functional differences** - **Oracle database** - The join sequence for a list is specified using WITHIN GROUP(ORDER BY). - **PostgreSQL** - WITHIN GROUP(ORDER BY) cannot be used. Instead, a join sequence can be specified using ORDER BY immediately after the value. **Migration procedure** Use the following procedure to perform migration: 1. Search for the keyword LISTAGG and confirm where it is used. 2. Move the ORDER BY clause of WITHIN GROUP(ORDER BY) immediately after the value of LISTAGG and then delete WITHIN GROUP(). **Migration example** The example below shows migration of the join sequence of specified values.
Oracle database PostgreSQL
 SELECT manager_id, 
        LISTAGG( name, ', ' ) 
         WITHIN GROUP( ORDER BY staff_id ) 
  FROM staff_table 
  GROUP BY manager_id;
 SELECT manager_id, 
        LISTAGG( name, ', ' ORDER BY staff_id ) 

FROM staff_table GROUP BY manager_id;
##### 6.2.4.2 Specifying the Join Sequence for a List per Group (Window Functions) **Functional differences** - **Oracle database** - The join sequence for a list per group is specified using WITHIN GROUP(ORDER BY) OVER(PARTITION BY). - **PostgreSQL** - The join sequence for a list per group cannot be specified. **Migration procedure** The join sequence for a list per group cannot be specified, so sort the data into the sequence in which it is to be joined and then join it. Use the following procedure to perform migration: 1. Search for the keywords LISTAGG and OVER, and identify where the OVER clause of LISTAGG is used. 2. Convert the table in the FROM clause to a subquery, and move the ORDER BY clause of WITHIN GROUP(ORDER BY) to the subquery. 3. Delete WITHIN GROUP(ORDER BY). **Migration example** The example below shows migration when a join sequence for a list per group is specified.
Oracle database PostgreSQL
 SELECT name, 
        manager_id, 
        LISTAGG( name, ', ' ) 
         WITHIN GROUP( ORDER BY staff_id ) 
         OVER( PARTITION BY manager_id )  
  FROM staff_table; 

 SELECT name, 
        manager_id, 
        LISTAGG( name, ', ' ) 

OVER( PARTITION BY manager_id ) FROM ( SELECT * FROM staff_table ORDER BY staff_id ) st_tbl;
#### 6.2.5 NLSSORT **Description** NLSSORT returns a binary value that denotes the lexical order of the locale (COLLATE). ##### 6.2.5.1 Sorting by the Specified Locale **Functional differences** - **Oracle database** - The locale is specified by NLS_SORT=locale.
The specifiable locales are provided by the Oracle database. - **PostgreSQL** - The locale is specified by locale.
The specifiable locales depend on the operating system. **Migration procedure** Use the following procedure to perform migration: 1. Search for the keyword NLSSORT and identify where it is used. 2. Delete NLS_SORT= and change the locale to the locale used by the operating system corresponding to the specified collating sequence. **Migration example** The example below shows migration when the specified locale is used for sorting. Note that the example locale in PostgreSQL would be the value specified for Linux.
Oracle database PostgreSQL
 SELECT c_code, c_name 
  FROM company_table 
  ORDER BY NLSSORT( c_name, 
                    'NLS_SORT = xDanish' ); 

SELECT c_code, c_name FROM company_table ORDER BY NLSSORT( c_name, 'NLS_SORT = JAPANESE_M' );
 SELECT c_code, c_name 
  FROM company_table 
  ORDER BY NLSSORT( c_name, 'danish' ); 


SELECT c_code, c_name FROM company_table ORDER BY NLSSORT( c_name, 'ja_JP.UTF8' );
##### 6.2.5.2 Sorting by Character Set **Functional differences** - **Oracle database** - NLS_SORT=BINARY is specified in the locale specification for sorting by character set. - **PostgreSQL** - C is specified in the locale specification for sorting by character set. **Migration procedure** Use the following procedure to perform migration: 1. Search for the keyword NLSSORT and identify where it is used. 2. If NLS_SORT=BINARY is specified for the locale, change it to C. **Migration example** The example below shows migration when the character set is used for sorting.
Oracle database PostgreSQL
 SELECT c_code, c_name 
  FROM company_table 
  ORDER BY NLSSORT( c_name, 'NLS_SORT = BINARY' );
 SELECT c_code, c_name 
  FROM company_table 
  ORDER BY NLSSORT( c_name, 'C' );
##### 6.2.5.3 Case-Insensitive Sorting **Functional differences** - **Oracle database** - Specifying _CI at the end of the locale sets case-insensitive sorting. - **PostgreSQL** - _CI cannot be specified at the end of the locale. **Migration procedure** There are no features that perform case-insensitive sorting, so make all characters either uppercase or lowercase before starting sorting so that the same result is returned. Use the following procedure to perform migration: 1. Search for the keyword NLSSORT and identify where it is used. 2. If _CI is specified at the end of the specified locale, put the sort column inside the parentheses of LOWER (or UPPER). **Migration example** The example below shows migration when case-insensitive sorting is used.
Oracle database PostgreSQL
 SELECT c_code, c_name 
  FROM company_table 
 ORDER BY NLSSORT( c_name, 
                   'NLS_SORT = JAPANESE_M_CI' );
 SELECT c_code, c_name 
  FROM company_table 
  ORDER BY NLSSORT( LOWER( c_name ), 
                    'ja_JP.UTF8' ); 
 
#### 6.2.6 SUBSTRC, SUBSTR2, and SUBSTR4 **Description** SUBSTRC, SUBSTR2, and SUBSTR4 extract part of a string in the character unit of the relevant encoding. **Functional differences** - **Oracle database** - SUBSTRC, SUBSTR2, and SUBSTR4 extract part of a string in the character unit of the relevant encoding. - **PostgreSQL** - There are no SUBSTRC, SUBSTR2, and SUBSTR4 functions. Only Unicode encoding is used in PostgreSQL. **Migration procedure** Use the following procedure to migrate to SUBSTR: 1. Search for the keywords SUBSTRC, SUBSTR2, and SUBSTR4, and identify where they are used. 2. Change those keywords to SUBSTR. **Migration example** The example below shows migration when part of a string is extracted in the character unit of the relevant encoding.
Oracle database PostgreSQL
 SELECT SUBSTRC( c_telephone, 5, 8 ) 
  FROM company_table; 

SELECT SUBSTR2( c_telephone, 5, 8 ) FROM company_table;
SELECT SUBSTR4( c_telephone, 5, 8 ) FROM company_table;
 SELECT SUBSTR( c_telephone, 5, 8 ) 
  FROM company_table; 






#### 6.2.7 SUBSTRB **Description** SUBSTRB extracts part of a string in bytes. ##### 6.2.7.1 Specifying Zero as the Start Position **Functional differences** - **Oracle database** - If 0 is specified as the start position, the part of the string is extracted from the first byte. - **PostgreSQL** - If 0 is specified as the start position, extraction starts at the position found by subtracting 1 from the start position and shifting by that number of positions to the left. **Migration procedure** Use the following procedure to perform migration: 1. Search for the keyword SUBSTRB and identify where it is used. 2. If 0 is specified as the start position, change it to 1. **Migration example** The example below shows migration when 0 is specified as the start position for SUBSTRB.
Oracle database PostgreSQL
 SELECT SUBSTRB( c_telephone, 0, 7 ) || '-xxxx' 
  FROM company_table;
 SELECT SUBSTRB( c_telephone, 1, 7 ) || '-xxxx' 
  FROM company_table;
##### 6.2.7.2 Specifying a Negative Value as the Start Position **Functional differences** - **Oracle database** - If a negative value is specified as the start position, extraction starts at the position found by counting by that number of bytes after the end of the string. - **PostgreSQL** - If a negative value is specified as the start position, extraction starts at the position found by subtracting 1 from the start position and shifting by that number of positions to the left. **Migration procedure** Use the following procedure to perform migration: 1. Search for the keyword SUBSTRB and identify where it is used. 2. If a negative value is specified as the start position, add (OCTET_LENGTH(firstArgumentOfSubstrb)+1) before the negative value of the start position parameter. **Migration example** The example below shows migration when a negative value is specified as the start position for SUBSTRB.
Oracle database PostgreSQL
 SELECT 'xxx-' || 
        SUBSTRB( c_telephone, -8, 3 ) || 
        '-xxxx' 
 FROM company_table; 



SELECT 'xxx-' || 
        SUBSTRB( c_telephone, 
                 ( OCTET_LENGTH( c_telephone )  
                    +1 ) -8, 
                   3 ) || 
        '-xxxx' 
  FROM company_table;
##### 6.2.7.3 Specifying a Value Less Than One as the String Length **Functional differences** - **Oracle database** - If a value less than 1 is specified as the string length, NULL is returned. - **PostgreSQL** - If the string length is 0, a null character is returned. A negative value cannot be specified as a string length. **Migration procedure** Use the following procedure to perform migration. Note that the final step depends on whether NULL or a null character is expected as the return value. - When expecting NULL as the return value 1. Search for the keyword SUBSTRB and identify where it is used. 2. Confirm that a value less than 1 is specified in the string length parameter. 3. Change the string length to NULL. - When expecting a null character as the return value 1. Search for the keyword SUBSTRB and identify where it is used. 2. Confirm that a value less than 1 is specified in the string length parameter. 3. If a value less than 0 is specified as the string length, change it to 0. **Migration example** The example below shows migration when a value less than 1 is specified as the string length in SUBSTRB. In this example, NULL is expected as the return value.
Oracle database PostgreSQL
 SELECT SUBSTRB( c_telephone, 1, -1 ) 
  FROM company_table;
 SELECT SUBSTRB( c_telephone, 1, NULL ) 
  FROM company_table;
#### 6.2.8 TO_CHAR and TO_DATE **Description** TO_CHAR and TO_DATE convert the specified value in accordance with the format. ##### 6.2.8.1 When Only Part of the TO_DATE Datetime Format is Specified **Functional differences** - **Oracle database** - If only part of the TO_DATE datetime format is specified, the omitted portion is set automatically, with the year set to the current year, the month set to the current month, the day set to 1, and the hour, minute, and second set to 0. - **PostgreSQL** - If only part of the TO_DATE datetime format is specified, the omitted portion is set automatically, with the year, month, and day set to 1, and the hour, minute, and second set to 0. **Migration procedure** Use the following procedure to perform migration: 1. Search for the keyword TO_DATE and confirm that the year or month is not specified in the datetime format. 2. Use DATE_TRANC to find the year. If the year is omitted, specify SYSDATE to obtain the current year. 3. Multiply the result of DATE_PART by one month indicated in the INTERVAL type to find the month. If the month is omitted, specify SYSDATE to obtain the current month. 4. Add the results found in steps 2 and 3. **Migration example** The example below shows migration when only part of the TO_DATE datetime format is specified.
Oracle database PostgreSQL
 SELECT TO_DATE( '04', 'MM' ) 
  FROM DUAL;



SELECT TO_DATE( '2000', 'YYYY' ) FROM DUAL;

 SELECT DATE_TRUNC( 'YEAR', SYSDATE() ) 
 + ( DATE_PART( 'MONTH', TO_DATE( '04', 'MM' ) ) - 1 ) 
 * INTERVAL '1 MONTH' 
 FROM DUAL; 

SELECT DATE_TRUNC( 'YEAR', TO_DATE( '2000', 'YYYY' ) ) + ( DATE_PART( 'MONTH', SYSDATE() ) - 1 ) * INTERVAL '1 MONTH' FROM DUAL;
##### 6.2.8.2 Omitting the Data Type Format **Functional differences** - **Oracle database** - If the data type format (datetime format) is omitted from TO_DATE or TO_CHAR, the values are converted in accordance with NLS_DATE_FORMAT.
Statements such as ALTER SESSION can be used to change NLS_DATE_FORMAT. - **PostgreSQL** - If the data type format (datetime format) is omitted from TO_DATE or TO_CHAR, the values are converted in accordance with oracle.nls_date_format.
Statements such as SET can be used to change oracle.nls_date_format. **Migration procedure** Use the following procedure to perform migration: 1. Search for the keywords TO_DATE and TO_CHAR, and check where the data type format (datetime format) is omitted. 2. Check the settings of the NLS_DATE_FORMAT parameter. 3. In oracle.nls_date_format, specify the datetime format specified in the NLS_DATE_FORMAT parameter. **Migration example** The example below shows migration when the date format is specified in the ALTER SESSION statement.
Oracle database PostgreSQL
 ALTER SESSION 
  SET NLS_DATE_FORMAT = "yyyy/mm/dd hh24:mi:ss"; 
 SELECT o_code, TO_CHAR( SYSDATE ) 
  FROM ordering_table; 
  
 SET orafce.nls_date_format =  
     'yyyy/mm/dd hh24:mi:ss'; 
 SELECT o_code, 
        TO_CHAR( SYSDATE() ) 
  FROM ordering_table; 
 
**See** ---- The scope of supported datetime formats differs between Oracle databases and PostgreSQL. Refer to "Formats" for information on the differences in the supported datetime formats. ---- ##### 6.2.8.3 Setting a Data Type Format Locale (Setting the Third Argument) **Functional differences** - **Oracle database** - The third argument (data type format locale setting) can be specified. - **PostgreSQL** - The third argument (data type format locale setting) cannot be specified. **Migration procedure** The locale cannot be specified in the data type format, so change the server parameters so that the same result is returned. Use the following procedure to perform migration: 1. Search for the keywords TO_CHAR and TO_DATE, and identify where they are used. 2. If the third argument is specified, use a SET statement to specify the corresponding server parameter to match the string format locale to be converted. The table below shows the correspondence between the parameters for setting a data type format locale and the server parameters. 3. Delete the third argument specified in TO_CHAR and TO_DATE. **Correspondence between the parameters for setting a data type format locale and the server parameters** |Data type format|Parameter for setting data type format locale
(Oracle database)|Server parameter
(PostgreSQL)| |:---|:---|:---| |Number format|NLS_NUMERIC_CHARACTERS|LC_NUMERIC (\*1)| |Number format|NLS_CURRENCY|LC_MONETARY (\*1)| |Number format|NLS_ISO_CURRENCY|- (Cannot be migrated because there is no corresponding parameter)| |Datetime format|NLS_DATE_LANGUAGE|LC_TIME (\*2)(\*3)(\*4)| \*1: In Oracle databases, the corresponding string is specified directly, but in PostgreSQL, the locale is specified. The string that is set is the value predetermined for each locale. \*2: When a string that is dependent on the specified locale is to be found, the prefix TM must be added at the beginning of the date format. If the TM prefix is not specified, an English-language string will be returned. \*3: When a string that is dependent on a Japanese-language or other character set is to be found, the string including the encoding must be specified. (Example: SET LC_TIME='ja_JP.UTF-8') \*4: Migration is possible only if TO_CHAR is used to find a string from a date. If TO_DATE is used, a locale-dependent string cannot be used as input. **Migration example** The example below shows migration when the data type format locale is set (in the third argument).
Oracle database PostgreSQL
 SELECT o_code, 
        TO_CHAR( o_price * o_quantity / 1.2, 
                 'l999g999g999d00', 
                 'NLS_NUMERIC_CHARACTERS = '',.'' 
                 NLS_CURRENCY = ''EUR'' ' ) "MONEY" 
   FROM ordering_table;
 SET LC_MONETARY='de_DE'; 
 SET LC_NUMERIC='de_DE'; 
 SELECT o_code, 
        TO_CHAR( o_price * o_quantity / 1.2, 
                 'l999g999g999d00' ) "MONEY" 
  FROM ordering_table;
**Information** ---- If the data type format matches the client locale, simply delete the third argument of TO_CHAR. ---- **See** ---- The values that can be specified in the server parameters depend on the locale of the operating system on the client. Refer to the PostgreSQL Documentation for details. ---- #### 6.2.9 Functions Requiring Parentheses Some functions added by orafce do not have arguments. Parentheses must be added to these functions when they are called. The functions to which parentheses must be added are listed below. Functions requiring parentheses: - SYSDATE - SESSIONTIMEZONE - DBTIMEZONE **Migration example** The example below shows migration when a function that has no arguments is called.
Oracle database PostgreSQL
 SELECT SYSDATE FROM DUAL;
 SELECT SYSDATE() FROM DUAL;
### 6.3 Standard Packages This section explains how to migrate the standard packages added by orafce. #### 6.3.1 DBMS_ALERT **Description** The DBMS_ALERT package sends alerts from a PL/pgSQL execution session to multiple other PL/pgSQL execution sessions. ##### 6.3.1.1 Set Value of DBMS_ALERT.REGISTER **Functional differences** - **Oracle database** - The second argument of DBMS_ALERT.REGISTER can be specified. The second argument specifies whether to perform a cleanup of the pipe to be used.
The default is TRUE, which causes a cleanup to be performed. - **PostgreSQL** - The second argument cannot be specified. **Migration procedure** Use the following procedure to perform migration: 1. Search for the keyword DBMS_ALERT.REGISTER and identify where it is used. 2. If the second argument is specified, delete it. **Migration example** The example below shows migration when the second argument is specified in DBMS_ALERT.REGISTER.
Oracle database PostgreSQL
 DBMS_ALERT.REGISTER( 'SAMPLEALERT', TRUE );
 PERFORM DBMS_ALERT.REGISTER( 'SAMPLEALERT' );
##### 6.3.1.2 Case Sensitivity of Alert Names **Functional differences** - **Oracle database** - Alert names are case-insensitive. - **PostgreSQL** - Alert names are case-sensitive. **Migration procedure** Use the following procedure to perform migration: 1. Search for the keywords DBMS_ALERT.REGISTER, DBMS_ALERT.SIGNAL, DBMS_ALERT.WAITONE, and DBMS_ALERT.REMOVE, and identify where they are used. 2. If there are alert names in different cases (uppercase and lowercase characters), change them to the same case. **Migration example** The example below shows migration when there is an alert name in uppercase characters and an alert name in lowercase characters. In this example, the alert names are aligned in uppercase.
Oracle database PostgreSQL
 DBMS_ALERT.REGISTER( 'SAMPLEALERT', TRUE ); 
 ~ 
 DBMS_ALERT.SIGNAL( 'samplealert', 
                    'TEST MESSAGE 1' );
 PERFORM DBMS_ALERT.REGISTER( 'SAMPLEALERT' ); 
 ~ 
 PERFORM DBMS_ALERT.SIGNAL( 'SAMPLEALERT', 
                            'TEST MESSAGE 1' );
##### 6.3.1.3 Other Notes on Using DBMS_ALERT This section explains the functional differences to be noted when DBMS_ALERT is used. Note that PL/pgSQL features cannot migrate these functional differences. Consider, for example, changing the application logic. ###### 6.3.1.3.1 Executing DBMS_ALERT.SIGNAL from Multiple PL/pgSQL Sessions **Functional differences** - **Oracle database** - DBMS_ALERT.SIGNAL is serialized according to the execution sequence.
Therefore, when DBMS_ALERT.SIGNAL is sent from multiple PL/SQL execution sessions to the same alert,
each DBMS_ALERT.SIGNAL remains in wait state until the preceding DBMS_ALERT.SIGNAL is committed. - **PostgreSQL** - DBMS_ALERT.SIGNAL is not serialized according to the execution sequence.
Therefore, even if the preceding DBMS_ALERT.SIGNAL is not yet committed,
the following DBMS_ALERT.SIGNAL does not enter wait state and the alert that is committed first is reported. ###### 6.3.1.3.2 Message Received when Alert is Reported Multiple Times **Functional differences** - **Oracle database** - If multiple DBMS_ALERT.SIGNAL procedures are executed between the time that DBMS_ALERT.REGISTER is executed and DBMS_ALERT.WAITANY/WAITONE is executed, the message from the DBMS_ALERT.SIGNAL executed last is received. All earlier alert messages are discarded. - **PostgreSQL** - If multiple DBMS_ALERT.SIGNAL procedures are executed between the time that DBMS_ALERT.REGISTER is executed and DBMS_ALERT.WAITANY/WAITONE is executed, the message from the DBMS_ALERT.SIGNAL executed first is received. Subsequent alert messages are not discarded but retained. **Note** ---- If alerts with the same name are used in multiple sessions, ensure that all alert messages are received or delete alerts from the PL/pgSQL sessions by using DBMS_ALERT.REMOVE/REMOVEALL at the point where alerts no longer need to be received. If alerts remain when the session is closed, other sessions may no longer be able to receive alerts properly. ---- ##### 6.3.1.4 Example of Migrating DBMS_ALERT The example below shows migration to PL/pgSQL when DBMS_ALERT is used.
Oracle database PostgreSQL
(Receiving side) 
 BEGIN 
  DBMS_ALERT.REGISTER( 'SAMPLEALERT', TRUE ); 
 END; 
 / 


------------------------------------------------- (Sending side)
BEGIN DBMS_ALERT.SIGNAL( 'samplealert', 'TEST MESSAGE 1' ); COMMIT; DBMS_ALERT.SIGNAL( 'samplealert', 'TEST MESSAGE 2' ); COMMIT; END; / ------------------------------------------------- (Receiving side) SET SERVEROUTPUT ON DECLARE alname VARCHAR2(100) := 'SAMPLEALERT'; almess VARCHAR2(1000); alst NUMBER; BEGIN DBMS_ALERT.WAITONE( alname, almess, alst, 60 ); DBMS_OUTPUT.PUT_LINE( alname ); DBMS_OUTPUT.PUT_LINE( almess ); DBMS_OUTPUT.PUT_LINE( 'alst =' || alst ); DBMS_ALERT.REMOVE( alname ); END; /

 (Receiving side) 
 DO $$ 
 BEGIN 
  PERFORM DBMS_ALERT.REGISTER( 'SAMPLEALERT' ); 
 END; 
 $$ 
 ; 
 ------------------------------------------------- 
 (Sending side) 
 DO $$ 
 BEGIN 
  PERFORM DBMS_ALERT.SIGNAL( 'SAMPLEALERT', 
                             'TEST MESSAGE 1' ); 
  PERFORM DBMS_ALERT.SIGNAL( 'SAMPLEALERT', 
                             'TEST MESSAGE 2' ); 
 END; 
 $$ 
 ; 

------------------------------------------------- (Receiving side) DO $$ DECLARE alname VARCHAR2(100) := 'SAMPLEALERT'; almess VARCHAR2(1000); alst int; BEGIN PERFORM DBMS_OUTPUT.SERVEROUTPUT( TRUE ); SELECT message, status INTO almess, alst FROM DBMS_ALERT.WAITONE( alname, 60 ); PERFORM DBMS_OUTPUT.PUT_LINE( alname ); PERFORM DBMS_OUTPUT.PUT_LINE( almess ); PERFORM DBMS_OUTPUT.PUT_LINE( 'alst =' || alst ); PERFORM DBMS_ALERT.REMOVE( alname ); END; $$ ;
#### 6.3.2 DBMS_ASSERT **Description** The DBMS_ASSERT package checks and normalizes SQL syntax elements. ##### 6.3.2.1 DBMS_ASSERT.ENQUOTE_LITERAL **Functional differences** - **Oracle database** - If a string in an argument is already enclosed in single quotation marks, it is not again enclosed in single quotation marks. - **PostgreSQL** - Even if a string in an argument is already enclosed in single quotation marks, it is again enclosed in single quotation marks. **Migration procedure** Use the following procedure to perform migration: 1. Search for the keyword DBMS_ASSERT.ENQUOTE_LITERAL and identify where it is used. 2. In the conditions of an IF statement, use LEFT and RIGHT to check the leading and trailing characters. 3. If each result does not match a single quotation mark (E'\x27'), use ENQUOTE_LITERAL to replace it. **Migration example** The example below shows migration when a string is enclosed in single quotation marks.
Oracle database PostgreSQL
 DBMS_OUTPUT.PUT_LINE( 
  DBMS_ASSERT.ENQUOTE_LITERAL( en_lit ) ); 




 IF ( LEFT( en_lit, 1 ) = E'\x27' AND 
      RIGHT( en_lit, 1 ) = E'\x27' ) THEN 
   PERFORM DBMS_OUTPUT.PUT_LINE( en_lit ); 
 ELSE 
  PERFORM DBMS_OUTPUT.PUT_LINE( 
   DBMS_ASSERT.ENQUOTE_LITERAL( en_lit ) ); 
 END IF;
**Note** ---- PostgreSQL does not verify single quotation marks. ---- ##### 6.3.2.2 DBMS_ASSERT.ENQUOTE_NAME **Functional differences** - **Oracle database** - If the string in the first argument is already enclosed in double quotation marks, it is not again enclosed in double quotation marks.
In addition, regardless of whether there is a second argument, a string enclosed in double quotation marks is not converted from lowercase to uppercase. - **PostgreSQL** - Even if the string in the first argument is already enclosed in double quotation marks, it is again enclosed in double quotation marks.
However, a first argument string that is all in lowercase is not enclosed in double quotation marks.
In addition, if the second argument is set to TRUE or the default, it is converted from uppercase to lowercase even if it is enclosed in double quotation marks. **Migration procedure** Use the following procedure to perform migration: 1. Search for the keyword DBMS_ASSERT.ENQUOTE_NAME and identify where it is used. 2. In the conditions of an IF statement, use LEFT and RIGHT to check the leading and trailing characters. 3. If each result does not match a double quotation mark (E'\x27'), use ENQUOTE_NAME to replace it. **Migration example** The example below shows migration when a string is enclosed in double quotation marks.
Oracle database PostgreSQL
 DBMS_OUTPUT.PUT_LINE( 
  DBMS_ASSERT.ENQUOTE_NAME( en_nam ) ); 




 IF ( LEFT( en_nam, 1 ) = E'\x22' AND 
      RIGHT( en_nam, 1 ) = E'\x22' ) THEN 
   PERFORM DBMS_OUTPUT.PUT_LINE( en_nam ); 
 ELSE 
  PERFORM DBMS_OUTPUT.PUT_LINE( 
   DBMS_ASSERT.ENQUOTE_NAME( en_nam ) ); 
 END IF;
##### 6.3.2.3 DBMS_ASSERT.SIMPLE_SQL_NAME **Functional differences** - **Oracle database** - If the leading or trailing position of a string in an argument contains a space, the space is deleted before the string is evaluated. - **PostgreSQL** - If the leading or trailing position of a string in an argument contains a space, the string is evaluated as is, causing an error. **Migration procedure** Use the following procedure to perform migration: 1. Search for the keyword DBMS_ASSERT.SIMPLE_SQL_NAME and identify where it is used. 2. If the leading or trailing position of a string in an argument contains a space, use TRIM to delete the space immediately preceding or following the argument string. **Migration example** The example below shows migration when the leading or trailing position of a string in an argument contains a space.
Oracle database PostgreSQL
DBMS_OUTPUT.PUT_LINE( 
  DBMS_ASSERT.SIMPLE_SQL_NAME( si_nam ) ); 
  
 PERFORM DBMS_OUTPUT.PUT_LINE( 
  DBMS_ASSERT.SIMPLE_SQL_NAME( 
   TRIM( both from si_nam ) ) );
**See** ---- The strings checked by DBMS_ASSERT.SIMPLE_SQL_NAME correspond to identifiers among the SQL elements. Refer to "The SQL Language" > "Lexical Structure" > "Identifiers and Key Words" in the PostgreSQL Documentation for information on the values that can be used as identifiers in PostgreSQL. ---- ##### 6.3.2.4 DBMS_ASSERT.SQL_OBJECT_NAME **Functional differences** - **Oracle database** - DBMS_ASSERT.SQL_OBJECT_NAME exists. - **PostgreSQL** - DBMS_ASSERT.SQL_OBJECT_NAME does not exist. Use DBMS_ASSERT.OBJECT_NAME instead. **Migration procedure** Use the following procedure to perform migration: 1. Search for the keyword DBMS_ASSERT.SQL_OBJECT_NAME and identify where it is used. 2. Change DBMS_ASSERT.SQL_OBJECT_NAME to DBMS_ASSERT.OBJECT_NAME. **Migration example** The example below shows migration when an input value is verified as a qualified SQL identifier of an existing SQL object.
Oracle database PostgreSQL
 SELECT 
   DBMS_ASSERT.SQL_OBJECT_NAME( 'inventory_table' ) 
  INTO table_name 
  FROM DUAL;
 SELECT 
   DBMS_ASSERT.OBJECT_NAME( 'inventory_table' ) 
  INTO table_name 
  FROM DUAL;
##### 6.3.2.5 Example of Migrating DBMS_ASSERT The example below shows migration to PL/pgSQL when DBMS_ASSERT is used.
Oracle database PostgreSQL
 SET SERVEROUTPUT ON 
 DECLARE 
  en_lit VARCHAR2(50) := '''ENQUOTE_LITERAL'''; 
  en_nam VARCHAR2(50) := '"enquote_name"'; 
  si_nam VARCHAR2(50) := ' SIMPLE_SQL_NAME   '; 
  table_name VARCHAR2(20); 
 BEGIN 

DBMS_OUTPUT.PUT_LINE( DBMS_ASSERT.ENQUOTE_LITERAL( en_lit ));





DBMS_OUTPUT.PUT_LINE( DBMS_ASSERT.ENQUOTE_NAME( en_nam ));





DBMS_OUTPUT.PUT_LINE( DBMS_ASSERT.SIMPLE_SQL_NAME( si_nam ));

SELECT DBMS_ASSERT.SQL_OBJECT_NAME( 'inventory_table' ) INTO table_name FROM DUAL; DBMS_OUTPUT.PUT_LINE( 'Object is : ' || table_name ); END; /
 DO $$ 
 DECLARE 
  en_lit VARCHAR2(50) := '''ENQUOTE_LITERAL''';  
  en_nam VARCHAR2(50) := '"enquote_name"';  
  si_nam VARCHAR2(50) := ' SIMPLE_SQL_NAME   ';  
  table_name VARCHAR2(20);  
 BEGIN 
  PERFORM DBMS_OUTPUT.SERVEROUTPUT(TRUE);  
  IF ( LEFT( en_lit, 1 ) = E'\x27' AND 
       RIGHT( en_lit, 1 ) = E'\x27' ) THEN 
   PERFORM DBMS_OUTPUT.PUT_LINE( en_lit );  
  ELSE 
   PERFORM DBMS_OUTPUT.PUT_LINE( 
    DBMS_ASSERT.ENQUOTE_LITERAL( en_lit )); 
  END IF; 

IF ( LEFT( en_nam, 1 ) = E'\x22' AND RIGHT( en_nam, 1 ) = E'\x22' ) THEN PERFORM DBMS_OUTPUT.PUT_LINE( en_nam ); ELSE PERFORM DBMS_OUTPUT.PUT_LINE( DBMS_ASSERT.ENQUOTE_NAME( en_nam ) ); END IF;
PERFORM DBMS_OUTPUT.PUT_LINE( DBMS_ASSERT.SIMPLE_SQL_NAME( TRIM( both from si_nam ) ) );
SELECT DBMS_ASSERT.OBJECT_NAME( 'inventory_table' ) INTO table_name FROM DUAL; PERFORM DBMS_OUTPUT.PUT_LINE( 'Object is : ' || table_name ); END; $$ ;
#### 6.3.3 DBMS_OUTPUT **Description** The DBMS_OUTPUT package sends messages from PL/pgSQL to clients such as psql. ##### 6.3.3.1 Differences in the Timing of Output Immediately After DBMS_OUTPUT.SERVEROUTPUT Changes from OFF to ON **Functional differences** - **Oracle database** - Messages stored in the buffer while SERVEROUTPUT is OFF are displayed after the execution of the first SQL statement or anonymous PL/SQL after SERVEROUTPUT changes to ON. - **PostgreSQL** - Messages stored in the buffer while SERVEROUTPUT is FALSE are not displayed even after the execution of the first SQL statement or anonymous block after SERVEROUTPUT changes to TRUE. DBMS_OUT.NEW_LINE must be executed. **Migration procedure** Use the following procedure to perform migration: 1. Search for the keyword SERVEROUTPUT and identify where it changes from OFF to ON. 2. Change the code so that DBMS_OUT.NEW_LINE is executed immediately after the SQL statement or anonymous block that is executed after the SERVEROUTPUT statement is changed to ON. **Migration example** The example below shows migration when the status of SERVEROUTPUT changes.
Oracle database PostgreSQL
 SET SERVEROUTPUT OFF; 





...
SET SERVEROUTPUT ON; SELECT * FROM dual;




 DO $$ 
 BEGIN 
 PERFORM DBMS_OUTPUT.SERVEROUTPUT( FALSE ); 
 END; 
 $$ 
 ; 
 ... 

SELECT * FROM dual; DO $$ BEGIN PERFORM DBMS_OUTPUT.SERVEROUTPUT( TRUE ); PERFORM DBMS_OUTPUT.NEW_LINE(); END; $$ ;
##### 6.3.3.2 Other Notes on Using DBMS_OUTPUT This section explains the functional differences to be noted when DBMS_OUTPUT is used. Note that PL/pgSQL features cannot migrate these functional differences. Consider, for example, changing the application logic. ###### 6.3.3.2.1 Differences in the Output Timing of DBMS_OUTPUT.PUT_LINE and DBMS_OUTPUT.NEW_LINE **Functional differences** - **Oracle database** - When SERVEROUTPUT is ON, the outputs of DBMS_OUTPUT.PUT_LINE and DBMS_OUTPUT.NEW_LINE are displayed together after the procedure finishes.
These outputs are stored in the buffer of the server while the procedure is running. - **PostgreSQL** - When SERVEROUTPUT is TRUE, the outputs from executing DBMS_OUTPUT.PUT_LINE and DBMS_OUTPUT.NEW_LINE are sent to the client and displayed immediately.
They are not stored in the buffer of the server. ##### 6.3.3.3 Example of Migrating DBMS_OUTPUT The example below shows migration to PL/pgSQL when DBMS_OUTPUT is used.
Oracle database PostgreSQL
 SET SERVEROUTPUT OFF; 
 BEGIN 

DBMS_OUTPUT.ENABLE( NULL ); DBMS_OUTPUT.PUT_LINE( '1:Hello World' ); END; /
SET SERVEROUTPUT ON SELECT * FROM dual;





 DO $$ 
 BEGIN 
  PERFORM DBMS_OUTPUT.SERVEROUTPUT( FALSE ); 
  PERFORM DBMS_OUTPUT.ENABLE( NULL ); 
  PERFORM DBMS_OUTPUT.PUT_LINE( '1:Hello World' ); 
 END; 
 $$ 
 ; 
 SELECT * FROM dual; 
 DO $$ 
  BEGIN 
   PERFORM DBMS_OUTPUT.SERVEROUTPUT( TRUE ); 
   PERFORM DBMS_OUTPUT.NEW_LINE(); 
 END; 
 $$ 
 ; 
#### 6.3.4 DBMS_PIPE **Description** The DBMS_PIPE package performs one-to-one communication between PL/pgSQL sessions. ##### 6.3.4.1 Differences from the DBMS_PIPE.CREATE_PIPE Definition **Functional differences** - **Oracle database** - The second argument specifies the maximum size of the pipe in bytes. The default is 8192 bytes.
The third argument specifies the pipe type. The default is TRUE (private pipe). - **PostgreSQL** - The second argument specifies the maximum number of messages that the pipe can hold. The default is 0. The specifiable range of numeric values is 1 to 32767.
The third argument specifies the pipe type. The default is FALSE (public pipe). **Migration procedure** Use the following procedure to perform migration: 1. Search for the keyword DBMS_PIPE.CREATE_PIPE and identify where it is used. 2. Change the code so that the maximum number of messages is specified in the second argument. 3. If the third argument is omitted and a private pipe is to be created, specify TRUE in the third argument. **Note** ---- Preferably, create a public pipe (the default) as the pipe type. If you create a private pipe, internal information (the creator of the private pipe) will remain even after the pipe is removed. Thus repeatedly creating and removing pipes may ultimately cause memory to run out. ---- **Migration example** The example below shows migration of DBMS_PIPE.CREATE_PIPE.
Oracle database PostgreSQL
 DBMS_PIPE.CREATE_PIPE( 
           'pipename', 
           2000,  
           TRUE );
 DBMS_PIPE.CREATE_PIPE( 
           'pipename', 
           50, 
           TRUE );
##### 6.3.4.2 Return Values of DBMS_PIPE.CREATE_PIPE and DBMS_PIPE.REMOVE_PIPE **Functional differences** - **Oracle database** - DBMS_PIPE.CREATE_PIPE and DBMS_PIPE.REMOVE_PIPE both return values. - **PostgreSQL** - DBMS_PIPE.CREATE_PIPE and DBMS_PIPE.REMOVE_PIPE both do not return values. **Migration procedure** Use the following procedure to perform migration: 1. Search for the keywords DBMS_PIPE.CREATE_PIPE and DBMS_PIPE.REMOVE_PIPE, and identify where they are used. 2. Change the code so that the call processing identified in step 1 is called by the PERFORM keyword. 3. If return values are used, replace the target processing with 0. **Migration example** The example below shows migration of DBMS_PIPE.CREATE_PIPE.
Oracle database PostgreSQL
 st := DBMS_PIPE.CREATE_PIPE( pipename, 2000 ); 
 DBMS_OUTPUT.PUT_LINE( 'Return Value =' || st ); 

 PERFORM DBMS_PIPE.CREATE_PIPE( pipename, 50 ); 
 st := 0; 
 PERFORM DBMS_OUTPUT.PUT_LINE( 
                  'Return Value =' || st );
##### 6.3.4.3 Creating the Same Pipe Name with DBMS_PIPE.CREATE_PIPE **Functional differences** - **Oracle database** - If a pipe with the same name already exists and can be used, DBMS_PIPE.CREATE_PIPE returns normally. - **PostgreSQL** - If a pipe with the same name already exists, DBMS_PIPE.CREATE_PIPE returns with an error. **Migration procedure** Use the following procedure to perform migration: 1. Search for the keyword CREATE_PIPE and identify where it is used. 2. If there may be a pipe with the same name, use the PERFORM statement shown below to check if the same pipe exists. 3. If NOT FOUND returns TRUE, there is no pipe with the same name, so execute CREATE_PIPE. ~~~ PERFORM 1 FROM DBMS_PIPE.DB_PIPES WHERE NAME = nameOfPipeToBeCreated ~~~ **Migration example** The example below shows migration of CREATE_PIPE when there may be a pipe with the same name.
Oracle database PostgreSQL
  
 DECLARE 
  pipename VARCHAR2(1000) := 'TESTPIPE01'; 
 BEGIN 
  DBMS_OUTPUT.PUT_LINE( 
   'Return = '|| DBMS_PIPE.CREATE_PIPE( 
                           pipename, 
                           2000, 
                           TRUE ) ); 



END; /
 DO $$ 
 DECLARE 
 pipename VARCHAR2(1000) := 'TESTPIPE01'; 
 BEGIN 
  PERFORM 1 
   FROM DBMS_PIPE.DB_PIPES 
   WHERE NAME = pipename;  
  IF ( NOT FOUND ) THEN 
   PERFORM DBMS_PIPE.CREATE_PIPE( pipename, 
                                  50, 
                                  TRUE ); 
 END IF; 
 END; 
 $$ 
 ;
##### 6.3.4.4 Return Values of DBMS_PIPE.NEXT_ITEM_TYPE **Functional differences** - **Oracle database** - DBMS_PIPE.NEXT_ITEM_TYPE has the following return values:
0: There is no next item.
6: NUMBER type
9: VARCHAR2 type
11: ROWID type
12: DATE type
23: RAW type - **PostgreSQL** - DBMS_PIPE.NEXT_ITEM_TYPE has the following return values:
0: There is no next item.
9: NUMERIC type
11: TEXT type
12: DATE type
13: TIMESTAMP type
23: BYTEA type
24: RECORD type **Migration procedure** Use the following procedure to perform migration: 1. Search for the keyword NEXT_ITEM_TYPE and identify the variable storing the return value of NEXT_ITEM_TYPE. 2. If the return value of NEXT_ITEM_TYPE is determined, change it to the value in PostgreSQL according to the table below. **Correspondence of return values of DBMS_PIPE.NEXT_ITEM_TYPE** |Oracle database|PostgreSQL| |:---|:---| | NUMBER type | NUMERIC type | | VARCHAR2 type | TEXT type | | ROWID type | | | | DATE type | | DATE type | TIMESTAMP type | | RAW type | BYTEA type | | | RECORD type | **Migration example** The example below shows migration when processing is branched according to the return value of DBMS_PIPE.NEXT_ITEM_TYPE.
Oracle database PostgreSQL
 item := DBMS_PIPE.NEXT_ITEM_TYPE; 
 IF ( item = 6 ) THEN  -- NUMBER type 
 ~ 
 ELSIF ( item = 9 ) THEN -- VARCHAR2 type 
 ~ 
 ELSIF ( item = 12 ) THEN  -- DATE type 
 ~
 item := DBMS_PIPE.NEXT_ITEM_TYPE(); 
 IF ( item = 9 ) THEN  -- NUMERIC type 
 ~ 
 ELSIF ( item =11 ) THEN -- TEXT type 
 ~ 
 ELSIF ( item = 13 ) THEN -- TIMESTAMP type 
 ~
##### 6.3.4.5 Data Types That Can be Used in DBMS_PIPE.PACK_MESSAGE and UNPACK_MESSAGE **Functional differences** - **Oracle database** - The data types that can be used are VARCHAR2, NCHAR, NUMBER, DATE, RAW, and ROWID.
When RAW or ROWID is used, the data type must be specified after UNPACK_MESSAGE. - **PostgreSQL** - The data types that can be used are TEXT, NUMERIC, INTEGER (Note), BIGINT (Note), DATE, TIMESTAMP, BYTEA, and RECORD.
All data types require the data type and empty parentheses to be specified after UNPACK_MESSAGE. **Note** ---- - The INTEGER and BIGINT data types can be used with PACK_MESSAGE only. - The INTEGER and BIGINT types are converted internally to the NUMERIC type. Therefore, use UNPACK_MESSAGE_NUMBER to receive a message. ---- **Migration procedure** Use the following procedure to perform migration: 1. Search for the keyword UNPACK_MESSAGE and identify where UNPACK_MESSAGE is used. 2. Change the variable specified in the argument to an assignment expression specified on the left-hand side, separately specify each data type after UNPACK_MESSAGE, and delete the variable from the parentheses. **Migration example** The example below shows migration when a message is sent and received.
Oracle database PostgreSQL
DBMS_PIPE.UNPACK_MESSAGE( testnum );
 testnum := 
     DBMS_PIPE.UNPACK_MESSAGE_NUMBER();
##### 6.3.4.6 Case Sensitivity of DBMS_PIPE.RECEIVE_MESSAGE and SEND_MESSAGE **Functional differences** - **Oracle database** - Pipe names are case-insensitive. - **PostgreSQL** - Pipe names are case-sensitive. **Migration procedure** Use the following procedure to perform migration: 1. Search for the keywords RECEIVE_MESSAGE and SEND_MESSAGE, and check the pipe names. 2. If there are pipe names in different cases (uppercase and lowercase characters), change them to the same case. **Migration example** The example below shows migration when uppercase and lowercase characters are used for the pipe names.
Oracle database PostgreSQL
 (Sending side) 
 st := DBMS_PIPE.SEND_MESSAGE( 'TESTPIPE01', 
                               10, 
                               8192 ); 
 (Receiving side) 
 st := DBMS_PIPE.RECEIVE_MESSAGE( 'testpipe01' );
 (Sending side) 
 st := DBMS_PIPE.SEND_MESSAGE( 'TESTPIPE01', 
                               10, 
                               100 );  
 (Receiving side) 
 st := DBMS_PIPE.RECEIVE_MESSAGE( 'TESTPIPE01' );
**Note** ---- The return values of DBMS_PIPE.RECEIVE_MESSAGE and DBMS_PIPE.SEND_MESSAGE differ as shown below. - **Oracle database** - There are five return values, as follows:
0: Completed successfully.
1: A timeout occurred.
2: A record in the pipe is too big for the buffer.
3: An interrupt occurred.
ORA-23322: The user does not have privileges for reading the pipe. - **PostgreSQL** - There are two return values, as follows:
0: Completed successfully.
1: A timeout occurred. ---- ##### 6.3.4.7 Differences in the DBMS_PIPE.SEND_MESSAGE Feature **Functional differences** - **Oracle database** - The third argument specifies the maximum size of the pipe in bytes. The default is 8192 bytes. - **PostgreSQL** - The third argument specifies the maximum number of messages that the pipe can hold.
The specifiable range of numeric values is 1 to 32767.
Note that if the maximum number of messages is omitted for an implicit pipe, the number is unlimited. **Migration procedure** Use the following procedure to perform migration: 1. Search for the keyword SEND_MESSAGE and identify where the maximum number of bytes is specified. 2. Replace the maximum number of bytes with the maximum number of messages. **Migration example** The example below shows migration when the maximum pipe size is specified.
Oracle database PostgreSQL
 DBMS_PIPE.SEND_MESSAGE( 'testPIPE', 10, 200 );
 DBMS_PIPE.SEND_MESSAGE( 'testPIPE', 10, 10 );
### 6.3.4.8 Example of Migrating DBMS_PIPE The example below shows migration when one-to-one communication is performed between PL/pgSQL sessions.
Oracle database PostgreSQL
 (Sending side) 
 SET SERVEROUTPUT ON; 
 DECLARE 
  testnum NUMBER := 111; 
  testvchar2 VARCHAR2(100) := 'Test Message'; 
  testdate DATE := SYSDATE; 
  testraw RAW(100) := '0101010101'; 
  st INT; 
  pipename VARCHAR2(1000) := 'TESTPIPE01'; 
 BEGIN 

st := DBMS_PIPE.CREATE_PIPE( pipename, 2000 );




DBMS_OUTPUT.PUT_LINE( 'Return Value =' || st );

DBMS_PIPE.PACK_MESSAGE( testnum ); DBMS_PIPE.PACK_MESSAGE( testvchar2 ); DBMS_PIPE.PACK_MESSAGE( testdate ); DBMS_PIPE.PACK_MESSAGE_RAW( testraw ); st := DBMS_PIPE.SEND_MESSAGE( 'TESTPIPE01', 10, 200 ); DBMS_OUTPUT.PUT_LINE( 'Return Value =' || st );
END; /
------------------------------------------------- (Receiving side) SET SERVEROUTPUT ON; DECLARE testnum NUMBER; testvchar2 VARCHAR2(100); testdate DATE; testraw RAW(100); item NUMBER; st INT; BEGIN
st := DBMS_PIPE.RECEIVE_MESSAGE( 'testpipe01' ); DBMS_OUTPUT.PUT_LINE( 'Return Value =' || st );
LOOP item := DBMS_PIPE.NEXT_ITEM_TYPE; DBMS_OUTPUT.PUT_LINE( 'Next Item : ' || item );
IF ( item = 6 ) THEN DBMS_PIPE.UNPACK_MESSAGE( testnum );
DBMS_OUTPUT.PUT_LINE( 'Get Message : ' || testnum ); ELSIF ( item = 9 ) THEN DBMS_PIPE.UNPACK_MESSAGE( testvchar2 );
DBMS_OUTPUT.PUT_LINE( 'Get Message : ' || testvchar2 ); ELSIF ( item = 12 ) THEN DBMS_PIPE.UNPACK_MESSAGE( testdate );
DBMS_OUTPUT.PUT_LINE( 'Get Message : ' || testdate ); ELSIF ( item = 23 ) THEN DBMS_PIPE.UNPACK_MESSAGE_RAW( testraw );


DBMS_OUTPUT.PUT_LINE( 'Get Message : ' || testraw ); ELSE EXIT; END IF; END LOOP; st := DBMS_PIPE.REMOVE_PIPE( 'testpipe01' );
DBMS_OUTPUT.PUT_LINE( 'Return Value =' || st );
END; /
 (Sending side) 
 DO $$ 
 DECLARE 
  testnum NUMERIC := 111; 
  testtext VARCHAR2(100) := 'Test Message'; 
  testtime TIMESTAMP := current_timestamp; 
  testbytea BYTEA := '0101010101'; 
  st INT; 
  pipename VARCHAR2(1000) := 'TESTPIPE01'; 
 BEGIN 
  PERFORM DBMS_OUTPUT.SERVEROUTPUT( TRUE ); 
  PERFORM 1 
   FROM DBMS_PIPE.DB_PIPES 
    WHERE NAME = pipename;  
  IF ( NOT FOUND ) THEN 
   PERFORM DBMS_PIPE.CREATE_PIPE( pipename,50 ); 
   st := 0; 
   PERFORM DBMS_OUTPUT.PUT_LINE( 
                    'Return Value =' || st ); 
  END IF; 
  PERFORM DBMS_PIPE.PACK_MESSAGE( testnum ); 
  PERFORM DBMS_PIPE.PACK_MESSAGE( testtext ); 
  PERFORM DBMS_PIPE.PACK_MESSAGE( testtime ); 
  PERFORM DBMS_PIPE.PACK_MESSAGE( testbytea ); 
  st := DBMS_PIPE.SEND_MESSAGE( 'TESTPIPE01', 
                                10, 
                                10 );  
  PERFORM DBMS_OUTPUT.PUT_LINE( 
  'Return Value =' || st ); 
 END; 
 $$ 
 ; 
 ------------------------------------------------- 
 (Receiving side) 
 DO $$ 
 DECLARE 
  testnum NUMERIC; 
  testtext VARCHAR2(100); 
  testtime TIMESTAMP; 
  testbytea BYTEA; 
  item INT; 
  st INT; 
 BEGIN 
  PERFORM DBMS_OUTPUT.SERVEROUTPUT( TRUE ); 
  st := DBMS_PIPE.RECEIVE_MESSAGE( 'TESTPIPE01' ); 
  PERFORM DBMS_OUTPUT.PUT_LINE( 
                      'Return Value ='|| st ); 
  LOOP 
   item := DBMS_PIPE.NEXT_ITEM_TYPE(); 
   PERFORM DBMS_OUTPUT.PUT_LINE( 
                       'Next Item : ' || item ); 
   IF ( item = 9 ) THEN 
    testnum := 
     DBMS_PIPE.UNPACK_MESSAGE_NUMBER(); 
    PERFORM DBMS_OUTPUT.PUT_LINE( 
                        'Get Message : ' || testnum ); 
   ELSIF ( item =11 ) THEN 
    testtext := 
     DBMS_PIPE.UNPACK_MESSAGE_TEXT(); 
    PERFORM DBMS_OUTPUT.PUT_LINE( 
                        'Get Message : ' || testtext ); 
   ELSIF ( item = 13 ) THEN 
    testtime := 
     DBMS_PIPE.UNPACK_MESSAGE_TIMESTAMP(); 
    PERFORM DBMS_OUTPUT.PUT_LINE( 
                        'Get Message : ' || testtime ); 
   ELSIF ( item = 23 ) THEN 
    testbytea := 
     DBMS_PIPE.UNPACK_MESSAGE_BYTEA(); 
    testtext := CAST( testbytea 
     AS varchar2(100) ); 
        PERFORM DBMS_OUTPUT.PUT_LINE( 
                            'Get Message : ' || testtext ); 
   ELSE 
    EXIT; 
   END IF; 
  END LOOP; 
  PERFORM DBMS_PIPE.REMOVE_PIPE( 'TESTPIPE01' ); 
  st := 0; 
  PERFORM DBMS_OUTPUT.PUT_LINE( 
                      'Return Value ='|| st ); 
 END; 
 $$ 
 ; 
 
#### 6.3.5 UTL_FILE **Description** The UTL_FILE package enables PL/pgSQL to read and write text files. ##### 6.3.5.1 Appending a Newline at File Closure **Functional differences** - **Oracle database** - If data in which no newline is specified remains in the buffer, a newline is appended after the data is output and then the file is closed. - **PostgreSQL** - If data in which no newline is specified remains in the buffer, the data is output and then the file is closed. A newline is not appended. **Migration procedure** Use the following procedure to perform migration: 1. Search for the keywords UTL_FILE.FCLOSE and UTF_FILE.FCLOSE_ALL, and identify where they are used. 2. If UTL_FILE.PUT is executed and no newline is specified during write processing before the file is closed, change the code so that UTL_FILE.NEW_LINE is executed before the file is closed. **Migration example** The example below shows migration when a file that does not end with a newline is closed.
Oracle database PostgreSQL
 UTL_FILE.PUT(v_handle, buff); 
 UTL_FILE.FCLOSE(v_handle); 
 
 PERFORM UTL_FILE.PUT(v_handle, buff); 
 PERFORM UTL_FILE.NEW_LINE(v_handle, 1); 
 s_handle := UTL_FILE.FCLOSE(v_handle);
##### 6.3.5.2 Processing UTL_FILE Exceptions **Functional differences** - **Oracle database** - There are exception definitions for the UTL_FILE package. They can be used for determining exceptions in the EXCEPTION clause. - **PostgreSQL** - There are no exception definitions for the UTL_FILE package. **Migration procedure** There are no exception definitions for the UTL_FILE package, so if they are used for determining exceptions in the EXCEPTION clause, replace them with PostgreSQL error codes. Use the following procedure to perform migration: 1. Search for the keyword UTL_FILE and check if an EXCEPTION clause is specified in the target PL/SQL. 2. If a UTL_FILE exception is used, replace it with a PostgreSQL error code in accordance with the table below. **Correspondence of UTL_FILE exceptions** |UTL_FILE exception definition
(Oracle database)|Migratability|Corresponding PostgreSQL error code| |:---|:---|:---| |INVALID_PATH|Y|RAISE_EXCEPTION| |INVALID_MODE|Y|RAISE_EXCEPTION| |INVALID_FILEHANDLE|Y|RAISE_EXCEPTION| |INVALID_OPERATION|Y|RAISE_EXCEPTION| |READ_ERROR|N|Not generated| |WRITE_ERROR|Y|RAISE_EXCEPTION| |INTERNAL_ERROR|Y|INTERNAL_ERROR| |CHARSETMISMATCH|N|Not generated| |FILE_OPEN|N|Not generated| |INVALID_MAXLINESIZE|Y|RAISE_EXCEPTION| |INVALID_FILENAME|Y|INVALID PARAMETER
NULL VALUE NOT ALLOWED (file name is NULL)| |ACCESS_DENIED|Y|RAISE_EXCEPTION| |INVALID_OFFSET|N|Not generated| |DELETE_FAILED|N|Not generated| |RENAME_FAILED|Y|RAISE_EXCEPTION| Y: Can be migrated N: Cannot be migrated **Migration example** The example below shows migration when an error message is displayed during UTL_FILE exception processing.
Oracle database PostgreSQL
 EXCEPTION 
  WHEN UTL_FILE.INVALID_FILEHANDLE THEN 
   v_errmsg := SQLERRM; 
   DBMS_OUTPUT.PUT_LINE(v_errmsg); 
 END;
 EXCEPTION 
  WHEN RAISE_EXCEPTION THEN 
   v_errmsg := SQLERRM;	 
   PERFORM DBMS_OUTPUT.PUT_LINE(v_errmsg); 
 END;
##### 6.3.5.3 Other Notes on Using UTL_FILE This section explains the functional differences to be noted when UTL_FILE is used. Note that PL/pgSQL features cannot migrate these functional differences. Consider, for example, changing the application logic. ###### 6.3.5.3.1 Differences in the Open Mode of UTL_FILE.FOPEN **Functional differences** - **Oracle database** - The rb (read byte), wb (write byte), or ab (append byte) open mode can be specified. - **PostgreSQL** - The rb (read byte), wb (write byte), and ab (append byte) open modes cannot be specified for OPEN_MODE. ###### 6.3.5.3.2 Differences in UTL_FILE.IS_OPEN **Functional differences** - **Oracle database** - Executing UTL_FILE.IS_OPEN after UTL_FILE.FCLOSE_ALL returns TRUE. - **PostgreSQL** - Executing UTL_FILE.IS_OPEN after UTL_FILE.FCLOSE_ALL returns FALSE. ###### 6.3.5.3.3 Timing of Write by UTL_FILE.FFLUSH **Functional differences** - **Oracle database** - Buffered data up to the newline character is written. - **PostgreSQL** - All buffered data is written. ##### 6.3.5.4 Example of Migrating UTL_FILE The example below shows migration to PL/pgSQL when UTL_FILE is used.
Oracle database PostgreSQL
 SET SERVEROUTPUT ON 
 DECLARE 
  v_handle   UTL_FILE.FILE_TYPE; 
  v_dirname  VARCHAR2(250); 
  v_filename VARCHAR2(250); 
  v_output   VARCHAR2(250); 
  v_getmsg   VARCHAR2(250); 
  v_errmsg   VARCHAR2(1000); 
  v_opcheck  BOOLEAN; 
 BEGIN 
  v_dirname := '/home/oracle'; 
  v_filename := 'sample.txt'; 
  v_output := 'HELLO WORLD!'; 
  v_handle := UTL_FILE.FOPEN(v_dirname, 
                             v_filename, 
                             'w', 
                             256); 


UTL_FILE.PUT_LINE(v_handle, v_output); UTL_FILE.FFLUSH(v_handle); UTL_FILE.PUT(v_handle, v_output);
UTL_FILE.FCLOSE(v_handle); v_handle := UTL_FILE.FOPEN(v_dirname, v_filename, 'r', 256); UTL_FILE.GET_LINE(v_handle, v_getmsg); DBMS_OUTPUT.PUT_LINE( 'GET_MESSAGE : ' || v_getmsg); UTL_FILE.FCLOSE_ALL; v_opcheck := UTL_FILE.IS_OPEN(v_handle); DBMS_OUTPUT.PUT_LINE(CASE WHEN v_opcheck IS NULL THEN 'UNKNOWN' WHEN v_opcheck THEN 'TRUE' WHEN NOT v_opcheck THEN 'FALSE' END);
BEGIN UTL_FILE.PUT_LINE(v_handle, v_output); EXCEPTION WHEN UTL_FILE.INVALID_FILEHANDLE THEN v_errmsg := SQLERRM; DBMS_OUTPUT.PUT_LINE(v_errmsg); END;
EXCEPTION WHEN OTHERS THEN UTL_FILE.FCLOSE_ALL; v_errmsg := SQLERRM; DBMS_OUTPUT.PUT_LINE(v_errmsg); END; /
 DO $$ 
 DECLARE 
  v_handle   UTL_FILE.FILE_TYPE; 
  v_dirname  VARCHAR2(250); 
  v_filename VARCHAR2(250); 
  v_output   VARCHAR2(250); 
  v_getmsg   VARCHAR2(250); 
  v_errmsg   VARCHAR2(1000); 
  v_opcheck  BOOLEAN; 
 BEGIN 
  PERFORM DBMS_OUTPUT.SERVEROUTPUT(TRUE); 
  PERFORM DBMS_OUTPUT.ENABLE(NULL); 
  v_dirname := '/home/pgsql'; 
  v_filename := 'sample.txt'; 
  v_output := 'HELLO WORLD!'; 
  v_handle := UTL_FILE.FOPEN(v_dirname, 
                             v_filename, 
                             'w', 
                             256); 
  PERFORM UTL_FILE.PUT_LINE(v_handle, v_output); 
  PERFORM UTL_FILE.PUT(v_handle, v_output); 
  PERFORM UTL_FILE.FFLUSH(v_handle); 
  PERFORM UTL_FILE.NEW_LINE(v_handle, 1); 
  v_handle := UTL_FILE.FCLOSE(v_handle); 
  v_handle := UTL_FILE.FOPEN(v_dirname, 
                             v_filename, 
                             'r', 
                             256); 
  v_getmsg := UTL_FILE.GET_LINE(v_handle); 
  PERFORM DBMS_OUTPUT.PUT_LINE( 
   'GET_MESSAGE : ' || v_getmsg); 
  PERFORM UTL_FILE.FCLOSE_ALL(); 
  v_opcheck := UTL_FILE.IS_OPEN(v_handle); 
  PERFORM DBMS_OUTPUT.PUT_LINE(CASE 
   WHEN v_opcheck IS NULL THEN 'UNKNOWN' 
   WHEN v_opcheck THEN 'TRUE' 
   WHEN NOT v_opcheck THEN 'FALSE' 
   END); 

BEGIN PERFORM UTL_FILE.PUT_LINE(v_handle, v_output); EXCEPTION WHEN RAISE_EXCEPTION THEN v_errmsg := SQLERRM; PERFORM DBMS_OUTPUT.PUT_LINE(v_errmsg); END;
EXCEPTION WHEN OTHERS THEN PERFORM UTL_FILE.FCLOSE_ALL(); v_errmsg := SQLERRM; PERFORM DBMS_OUTPUT.PUT_LINE(v_errmsg); END; $$ ;
orafce-VERSION_3_9_0/doc/sql_migration/sql_migration07.md000066400000000000000000000164121362147214200233150ustar00rootroot00000000000000Appendix A Correspondence with Oracle Databases ---- This appendix explains the correspondence between PostgreSQL and Oracle databases. ### A.1 Hint Clauses **Description** An execution plan specified for a query can be controlled per SQL statement by hints without any change in the settings for the entire server. #### A.1.1 Hint Clause Correspondence The table below lists the pg_hint_plan hints that correspond to Oracle database hints. **Correspondence between Oracle database hints and pg_hint_plan** |Hint (Oracle database)|Hint (PostgreSQL)| |:---|:---| |FIRST_ROWS hint |Rows | |FULL hint |Seqscan | |INDEX hint |IndexScan | |LEADING hint |Leading | |NO_INDEX hint |NoIndexScan | |NO_USE_HASH hint |NoHashJoin | |NO_USE_MERGE hint |NoMergeJoin | |NO_USE_NL hint |NoNestLoop | |ORDERED hint |Leading | |USE_HASH hint |HashJoin | |USE_MERGE hint |MergeJoin | |USE_NL hint |NestLoop | **Note** --- The optimizer operates differently for each database. Therefore, hint statements that are migrated as is may not have the same effect after migration. Be sure to verify operation at migration. --- **Migration example** The example below shows migration of a hint clause (INDEX hint).
Oracle database PostgreSQL
SELECT /*+INDEX(inventory_table idx1)*/ *
 FROM inventory_table WHERE i_number = 110;
SELECT /*+IndexScan(inventory_table idx1)*/ *
 FROM inventory_table WHERE i_number = 110; 
Note: The string idx1 is the index name defined for the i_number row of inventory_table. **Note** ---- The pg_hint_plan hint, which is an extended feature of PostgreSQL, cannot be used to specify a column name or set a query block before the table name specification. ---- ### A.2 Dynamic Performance Views **Description** Dynamic performance views are views that can reference information mainly relating to database performance. #### A.2.1 Alternatives for Dynamic Performance Views PostgreSQL does not contain any dynamic performance views. Consider using the PostgreSQL system catalogs or statistics views instead. The table below lists the alternative system catalogs and statistics views that correspond to the dynamic performance views. Alternatives for dynamic performance views |Dynamic performance view
(Oracle database) |System catalog or statistics view
(PostgreSQL)| |:---|:---| |V$ACCESS | pg_locks | |V$ACTIVE_SERVICES | pg_stat_activity | |V$ARCHIVED_LOG | pg_stat_archiver | |V$CLIENT_STATS | pg_stat_activity | |V$CONTEXT | pg_settings | |V$DATABASE | pg_database | |V$EMX_USAGE_STATS | pg_stat_user_functions | |V$ENABLEDPRIVS | pg_authid | |V$ENQUEUE_LOCK | pg_locks | |V$FILESTAT | pg_statio_all_tables | |V$FIXED_TABLE | pg_views | |V$FIXED_VIEW_DEFINITION | pg_views | |V$GES_BLOCKING_ENQUEUE | pg_locks | |V$GLOBAL_BLOCKED_LOCKS | pg_locks | |V$GLOBAL_TRANSACTION | pg_locks | |V$LOCK | pg_locks | |V$LOCKED_OBJECT | pg_locks | |V$MVREFRESH | pg_matviews | |V$MYSTAT | pg_stat_all_tables or other view | |V$NLS_PARAMETERS | pg_settings | |V$NLS_VALID_VALUES | pg_proc
pg_ts_config
pg_collation
pg_type | |V$OBJECT_PRIVILEGE | pg_default_acl | |V$OBJECT_USAGE | pg_stat_all_indexes | |V$OPEN_CURSOR | pg_cursors | |V$OPTION | pg_settings | |V$PARAMETER | pg_settings | |V$PARAMETER2 | pg_settings | |V$PROCESS | pg_stat_activity | |V$PWFILE_USERS | pg_users | |V$REPLPROP | pg_replication_origin
pg_replication_origin_status | |V$SESSION | pg_stat_activity | |V$SESSTAT | pg_stat_all_tables or other view | |V$SQLFN_METADATA | pg_proc,pg_aggrgate | |V$SYSTEM_PARAMETER | pg_settings | |V$SYSTEM_PARAMETER2 | pg_settings | |V$TABLESPACE | pg_tablespace | |V$TEMPSTAT | pg_stat_database | |V$TIMEZONE_NAMES | pg_timezone_names | |V$TRANSACTION | pg_locks | |V$TRANSACTION_ENQUEUE | pg_locks | **Note** ---- Not all dynamic performance view information can be obtained from the system catalogs and statistics views. Each user should determine whether the obtained information can be used. ---- ### A.3 Formats **Description** Specifying formats in data type formatting functions makes it possible to convert numeric and date and time data types to formatted strings and to convert formatted strings to specific data types. #### A.3.1 Number Format Correspondence The table below indicates which Oracle database number formats are available in PostgreSQL. **Number format correspondence** |Number format|TO_CHAR | TO_NUMBER | Remarks| |:---|:---:|:---:|:---| | , (comma) | Y | Y | | | . (period) | Y | Y | | | $ | YR | YR | If a dollar sign ($) is specified in any position other than the first character of a number format, move it to the front of the number format. | | 0 | Y | Y | | | 9 | Y | Y | | | B | Y | Y | | | C | N | N | | | D | Y | Y | | | EEEE | Y | Y | | | G | Y | Y | | | L | Y | Y | | | MI | Y | Y | | | PR | Y | Y | | | RN | Y | - | | | Rn | Y | - | | | S | Y | Y | | | TM | N | - | | | U | N | N | | | V | Y | - | | | X | N | N | | | X | N | N | | Y: Available YR: Available with restrictions N: Cannot be migrated -: Does not need to be migrated (because it is not available in Oracle databases) #### A.3.2 Datetime Format Correspondence The table below indicates which Oracle database datetime formats are available in PostgreSQL. Datetime format correspondence |Datetime format|TO_CHAR|TO_DATE|TO_TIMESTAMP|Remarks| |:---|:---|:---|:---|:---| | -
/
,
.
;
:
"text" | Y | Y | Y | | | AD | Y | Y | Y | | | A.D. | Y | Y | Y | | | AM | Y | Y | Y | | | A.M. | Y | Y | Y | | | BC | Y | Y | Y | | | B.C. | Y | Y | Y | | | CC | Y | - | - | | | SCC | Y | - | - | | | D | Y | Y | Y | | | DAY | Y | Y | Y | | | DD | Y | Y | Y | | | DDD | Y | YR | YR | The year must also be specified. (This format is used together with other formats such as YYYY.) | | DL | N | N | N | | | DS | N | N | N | | | DY | Y | Y | Y | | | E | N | N | N | | | EE | N | N | N | | | FF1 to FF9 | MR | - | MR | Change to MS.
However, the number of digits is fixed at three. | | FM | YR | YR | YR | Applies only to the format specified immediately after FM. | | FX | Y | Y | Y | | | HH | Y | Y | Y | | | HH12 | Y | Y | Y | | | HH24 | Y | Y | Y | | | IW | Y | - | - | | | IYYY | Y | - | - | | | IYY | Y | - | - | | | IY | Y | - | - | | | I | Y | - | - | | | J | Y | Y | Y | | | MI | Y | Y | Y | | | MM | Y | Y | Y | | | MON | Y | Y | Y | | | MONTH | Y | Y | Y | | | PM | Y | Y | Y | | | P.M. | Y | Y | Y | | | Q | Y | - | - | | | RM | Y | Y | Y | | | RR | Y | Y | Y | | | RRRR | Y | Y | Y | | | SS | Y | Y | Y | | | SSSSS | M | M | M | Change to SSSS. | | TS | N | N | N | | | TZD | M | - | - | Change to TZ. | | TZH | N | - | - | | | TZM | N | - | - | | | TZR | M | - | - | Change to TZ. | | WW | Y | Y | Y | | | W | Y | Y | Y | | | X | Y | - | Y | | | Y,YYY | Y | Y | Y | | | YEAR | N | - | - | | | SYEAR | N | - | - | | | YYYY | Y | Y | Y | | | SYYYY | N | N | N | | | YYY | Y | Y | Y | | | YY | Y | Y | Y | | | Y | Y | Y | Y | | Y: Available M: Can be migrated N: Cannot be migrated YR: Available with restrictions MR: Can be migrated with restrictions -: Does not need to be migrated (because it is not available in Oracle databases) orafce-VERSION_3_9_0/expected/000077500000000000000000000000001362147214200161345ustar00rootroot00000000000000orafce-VERSION_3_9_0/expected/aggregates.out000066400000000000000000000064161362147214200210050ustar00rootroot00000000000000-- Tests for the aggregate listagg SELECT listagg(i::text) from generate_series(1,3) g(i); listagg --------- 123 (1 row) SELECT listagg(i::text, ',') from generate_series(1,3) g(i); listagg --------- 1,2,3 (1 row) SELECT coalesce(listagg(i::text), '') from (SELECT ''::text) g(i); coalesce ---------- (1 row) SELECT coalesce(listagg(i::text), '') from generate_series(1,0) g(i); coalesce ---------- (1 row) SELECT wm_concat(i::text) from generate_series(1,3) g(i); wm_concat ----------- 1,2,3 (1 row) -- Tests for the aggregate median( real | double ) CREATE FUNCTION checkMedianRealOdd() RETURNS real AS $$ DECLARE med real; BEGIN CREATE TABLE median_test (salary real); INSERT INTO median_test VALUES (4500); INSERT INTO median_test VALUES (NULL); INSERT INTO median_test VALUES (2100); INSERT INTO median_test VALUES (3600); INSERT INTO median_test VALUES (4000); SELECT into med median(salary) from median_test; DROP TABLE median_test; return med; END; $$ LANGUAGE plpgsql; CREATE FUNCTION checkMedianRealEven() RETURNS real AS $$ DECLARE med real; BEGIN CREATE TABLE median_test (salary real); INSERT INTO median_test VALUES (4500); INSERT INTO median_test VALUES (1500); INSERT INTO median_test VALUES (2100); INSERT INTO median_test VALUES (3600); INSERT INTO median_test VALUES (1000); INSERT INTO median_test VALUES (4000); select into med median(salary) from median_test; DROP TABLE median_test; return med; END; $$ LANGUAGE plpgsql; CREATE FUNCTION checkMedianDoubleOdd() RETURNS double precision AS $$ DECLARE med double precision; BEGIN CREATE TABLE median_test (salary double precision); INSERT INTO median_test VALUES (4500); INSERT INTO median_test VALUES (1500); INSERT INTO median_test VALUES (2100); INSERT INTO median_test VALUES (3600); INSERT INTO median_test VALUES (4000); select into med median(salary) from median_test; DROP TABLE median_test; return med; END; $$ LANGUAGE plpgsql; CREATE FUNCTION checkMedianDoubleEven() RETURNS double precision AS $$ DECLARE med double precision; BEGIN CREATE TABLE median_test (salary double precision); INSERT INTO median_test VALUES (4500); INSERT INTO median_test VALUES (1500); INSERT INTO median_test VALUES (2100); INSERT INTO median_test VALUES (3600); INSERT INTO median_test VALUES (4000); INSERT INTO median_test VALUES (1000); select into med median(salary) from median_test; DROP TABLE median_test; return med; END; $$ LANGUAGE plpgsql; SELECT checkMedianRealOdd(); checkmedianrealodd -------------------- 3800 (1 row) SELECT checkMedianRealEven(); checkmedianrealeven --------------------- 2850 (1 row) SELECT checkMedianDoubleOdd(); checkmediandoubleodd ---------------------- 3600 (1 row) SELECT checkMedianDoubleEven(); checkmediandoubleeven ----------------------- 2850 (1 row) DROP FUNCTION checkMedianRealOdd(); DROP FUNCTION checkMedianRealEven(); DROP FUNCTION checkMedianDoubleOdd(); DROP FUNCTION checkMedianDoubleEven(); orafce-VERSION_3_9_0/expected/dbms_alert_session_A.out000066400000000000000000000063441362147214200230130ustar00rootroot00000000000000\set ECHO all SELECT pg_sleep(3); pg_sleep ---------- (1 row) /* * DBMS_ALERT is used for one-way communication of one session to other. * * This session mainly sends signals for testing the alert functionality in * session B and C. * * The following alerts are used to ensure that signals are sent at correct * times to session B for testing. These signals are sent from session B * indicating completion of an event. * After the signal is received, the next required signal for testing is sent * from this session. */ SELECT dbms_alert.register('b1'); register ---------- (1 row) SELECT dbms_alert.register('b2'); register ---------- (1 row) SELECT dbms_alert.register('b3'); register ---------- (1 row) SELECT dbms_alert.register('b4'); register ---------- (1 row) SELECT dbms_alert.register('b5'); register ---------- (1 row) SELECT dbms_alert.signal('a1','Msg1 for a1'); signal -------- (1 row) SELECT dbms_alert.signal('a2','Msg1 for a2'); signal -------- (1 row) /* * Test: defered_signal * The signal is received only when the signalling transaction commits. * To test this, an explict BEGIN-COMMIT block is used. */ SELECT dbms_alert.signal('tds','Begin defered_signal test'); signal -------- (1 row) BEGIN; SELECT dbms_alert.signal('tds','Testing defered_signal'); signal -------- (1 row) /* The signal is received while transaction is running */ SELECT dbms_alert.waitone('b1',20); waitone --------------------------------- ("Transaction still running",0) (1 row) COMMIT; /* The signal is received after transaction completed. * After this the tds signal is received in session B indicating that the * signal is received only after commit. */ SELECT dbms_alert.waitone('b1',20); waitone ----------------------------- ("Transaction committed",0) (1 row) SELECT dbms_alert.waitone('b2',20); waitone ---------------------------------------- ("to check unregistered alert wait",0) (1 row) /* This signals a3 which is not registered in Session B */ SELECT dbms_alert.signal('a3','Msg1 for a3'); signal -------- (1 row) /* alert a4 is signalled soon after a3 */ SELECT dbms_alert.signal('a4','Test- Register after signal'); signal -------- (1 row) /* This signal indicates at remove() is called */ SELECT dbms_alert.waitone('b3',20); waitone ------------------------- ("remove(a1) called",0) (1 row) /* Send signal which is removed in session B */ SELECT dbms_alert.signal('a1','Msg2 for a1'); signal -------- (1 row) SELECT dbms_alert.waitone('b4',20); waitone -------------------------------- ("to check unremoved alert",0) (1 row) /* Send signal which is registered in B and not removed */ SELECT dbms_alert.signal('a4','Msg1 for a4'); signal -------- (1 row) /* This signal inidcates that removeall() is called */ SELECT dbms_alert.waitone('b5',20); waitone ------------------------ ("removeall called",0) (1 row) /* Send a signal to test if session B receives it after removeall() */ SELECT dbms_alert.signal('a2','Msg2 for a2'); signal -------- (1 row) /* cleanup */ SELECT dbms_alert.removeall(); removeall ----------- (1 row) orafce-VERSION_3_9_0/expected/dbms_alert_session_B.out000066400000000000000000000051351362147214200230110ustar00rootroot00000000000000\set ECHO all /* Register alerts */ SELECT dbms_alert.register('a1'); register ---------- (1 row) SELECT dbms_alert.register('a2'); register ---------- (1 row) SELECT dbms_alert.register('tds'); register ---------- (1 row) /* Test: multisession waitone */ SELECT dbms_alert.waitone('a1',20); waitone ------------------- ("Msg1 for a1",0) (1 row) /* Test: multisession waitany */ SELECT dbms_alert.waitany(10); waitany ---------------------- (a2,"Msg1 for a2",0) (1 row) /* Test defered_signal */ /* This indicated that the transaction has begun */ SELECT dbms_alert.waitone('tds',10); waitone --------------------------------- ("Begin defered_signal test",0) (1 row) /* The signal will not be received because the transaction is running */ SELECT dbms_alert.waitone('tds',2); waitone --------- (,1) (1 row) SELECT dbms_alert.signal('b1','Transaction still running'); signal -------- (1 row) SELECT dbms_alert.signal('b1','Transaction committed'); signal -------- (1 row) /* Since the transaction has commited, the signal will be received */ SELECT dbms_alert.waitone('tds',10); waitone ------------------------------ ("Testing defered_signal",0) (1 row) /* Signal session A to send msg1 for a3 */ SELECT dbms_alert.signal('b2','to check unregistered alert wait'); signal -------- (1 row) /* Test: wait for unregistered alert which is signaled*/ SELECT dbms_alert.waitone('a3',2); waitone --------- (,1) (1 row) /* Test: Register after alert is signaled and wait */ SELECT dbms_alert.register('a4'); register ---------- (1 row) SELECT dbms_alert.waitone('a4',2); waitone --------- (,1) (1 row) /* Test: remove one */ SELECT dbms_alert.remove('a1'); remove -------- (1 row) /* Signal session A to send msg2 for a1 */ SELECT dbms_alert.signal('b3','remove(a1) called'); signal -------- (1 row) /* Test: wait for removed alert */ SELECT dbms_alert.waitone('a1',2); waitone --------- (,1) (1 row) /* Signal session A to send msg1 for a4 */ SELECT dbms_alert.signal('b4','to check unremoved alert'); signal -------- (1 row) /* Test: Check if unremoved alert is received */ SELECT dbms_alert.waitone('a4',10); waitone ------------------- ("Msg1 for a4",0) (1 row) /* Test removeall */ SELECT dbms_alert.removeall(); removeall ----------- (1 row) /* Signal session A to send msg2 for a2 */ SELECT dbms_alert.signal('b5','removeall called'); signal -------- (1 row) /* Test: Use waitany to see if any alert is received */ SELECT dbms_alert.waitany(2); waitany --------- (,,1) (1 row) orafce-VERSION_3_9_0/expected/dbms_alert_session_C.out000066400000000000000000000010201362147214200227770ustar00rootroot00000000000000\set ECHO all /* Register alerts */ SELECT dbms_alert.register('a1'); register ---------- (1 row) SELECT dbms_alert.register('a2'); register ---------- (1 row) /* Test: multisession waitone */ SELECT dbms_alert.waitone('a1',20); waitone ------------------- ("Msg1 for a1",0) (1 row) /* Test: multisession waitany */ SELECT dbms_alert.waitany(10); waitany ---------------------- (a2,"Msg1 for a2",0) (1 row) /* cleanup */ SELECT dbms_alert.removeall(); removeall ----------- (1 row) orafce-VERSION_3_9_0/expected/dbms_output.out000066400000000000000000001063121362147214200212350ustar00rootroot00000000000000\set ECHO none DROP FUNCTION dbms_output_test(); ERROR: function dbms_output_test() does not exist DROP TABLE dbms_output_test; ERROR: table "dbms_output_test" does not exist -- DBMS_OUTPUT.DISABLE [0] CREATE TABLE dbms_output_test (buff VARCHAR(20), status INTEGER); CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ DECLARE buff VARCHAR(20); stts INTEGER; BEGIN PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 1'); SELECT INTO buff,stts line,status FROM DBMS_OUTPUT.GET_LINE(); INSERT INTO dbms_output_test VALUES (buff, stts); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); dbms_output_test ------------------ (1 row) SELECT * FROM dbms_output_test; buff | status --------+-------- | 1 (1 row) DROP TABLE dbms_output_test; DROP FUNCTION dbms_output_test(); -- DBMS_OUTPUT.PUT_LINE [1] CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ DECLARE buff1 VARCHAR(20) := 'orafce'; BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('t'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE'); PERFORM DBMS_OUTPUT.PUT_LINE (buff1); PERFORM DBMS_OUTPUT.PUT ('ABC'); PERFORM DBMS_OUTPUT.PUT_LINE (''); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); ORAFCE orafce ABC dbms_output_test ------------------ (1 row) DROP FUNCTION dbms_output_test(); -- DBMS_OUTPUT.PUT_LINE [2] CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('t'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORA F CE'); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); ORA F CE dbms_output_test ------------------ (1 row) DROP FUNCTION dbms_output_test(); -- DBMS_OUTPUT.PUT [1] CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ DECLARE buff1 VARCHAR(20) := 'ora'; buff2 VARCHAR(20) := 'f'; buff3 VARCHAR(20) := 'ce'; BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('t'); PERFORM DBMS_OUTPUT.PUT ('ORA'); PERFORM DBMS_OUTPUT.PUT ('F'); PERFORM DBMS_OUTPUT.PUT ('CE'); PERFORM DBMS_OUTPUT.PUT_LINE (''); PERFORM DBMS_OUTPUT.PUT ('ABC'); PERFORM DBMS_OUTPUT.PUT_LINE (''); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); ORAFCE ABC dbms_output_test ------------------ (1 row) DROP FUNCTION dbms_output_test(); -- DBMS_OUTPUT.PUT [2] CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('t'); PERFORM DBMS_OUTPUT.PUT ('ORA F CE'); PERFORM DBMS_OUTPUT.PUT_LINE (''); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); ORA F CE dbms_output_test ------------------ (1 row) DROP FUNCTION dbms_output_test(); -- DBMS_OUTPUT.GET_LINE [1] CREATE TABLE dbms_output_test (buff VARCHAR(20), status INTEGER); CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ DECLARE buff VARCHAR(20); stts INTEGER; BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 1'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 2'); SELECT INTO buff,stts line,status FROM DBMS_OUTPUT.GET_LINE(); INSERT INTO dbms_output_test VALUES (buff, stts); SELECT INTO buff,stts line,status FROM DBMS_OUTPUT.GET_LINE(); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); dbms_output_test ------------------ (1 row) SELECT * FROM dbms_output_test; buff | status ---------------+-------- ORAFCE TEST 1 | 0 ORAFCE TEST 2 | 0 (2 rows) DROP TABLE dbms_output_test; DROP FUNCTION dbms_output_test(); -- DBMS_OUTPUT.GET_LINE [2] CREATE TABLE dbms_output_test (buff VARCHAR(20), status INTEGER); CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ DECLARE buff VARCHAR(20); stts INTEGER; BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 1'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 2'); SELECT INTO buff,stts line,status FROM DBMS_OUTPUT.GET_LINE(); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 3'); SELECT INTO buff,stts line,status FROM DBMS_OUTPUT.GET_LINE(); INSERT INTO dbms_output_test VALUES (buff, stts); SELECT INTO buff,stts line,status FROM DBMS_OUTPUT.GET_LINE(); INSERT INTO dbms_output_test VALUES (buff, stts); SELECT INTO buff,stts line,status FROM DBMS_OUTPUT.GET_LINE(); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); dbms_output_test ------------------ (1 row) SELECT * FROM dbms_output_test; buff | status ---------------+-------- ORAFCE TEST 1 | 0 ORAFCE TEST 3 | 0 | 1 | 1 (4 rows) DROP TABLE dbms_output_test; DROP FUNCTION dbms_output_test(); -- DBMS_OUTPUT.GET_LINE [3] CREATE TABLE dbms_output_test (buff VARCHAR(20), status INTEGER); CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ DECLARE buff VARCHAR(20); stts INTEGER; BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 1'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 2'); SELECT INTO buff,stts line,status FROM DBMS_OUTPUT.GET_LINE(); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.PUT ('ORA'); SELECT INTO buff,stts line,status FROM DBMS_OUTPUT.GET_LINE(); INSERT INTO dbms_output_test VALUES (buff, stts); SELECT INTO buff,stts line,status FROM DBMS_OUTPUT.GET_LINE(); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); dbms_output_test ------------------ (1 row) SELECT * FROM dbms_output_test; buff | status ---------------+-------- ORAFCE TEST 1 | 0 ORA | 0 | 1 (3 rows) DROP TABLE dbms_output_test; DROP FUNCTION dbms_output_test(); -- DBMS_OUTPUT.GET_LINE [4] CREATE TABLE dbms_output_test (buff VARCHAR(20), status INTEGER); CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ DECLARE buff VARCHAR(20); stts INTEGER; BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 1'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 2'); SELECT INTO buff,stts line,status FROM DBMS_OUTPUT.GET_LINE(); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.NEW_LINE(); SELECT INTO buff,stts line,status FROM DBMS_OUTPUT.GET_LINE(); INSERT INTO dbms_output_test VALUES (buff, stts); SELECT INTO buff,stts line,status FROM DBMS_OUTPUT.GET_LINE(); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); dbms_output_test ------------------ (1 row) SELECT * FROM dbms_output_test; buff | status ---------------+-------- ORAFCE TEST 1 | 0 | 0 | 1 (3 rows) DROP TABLE dbms_output_test; DROP FUNCTION dbms_output_test(); -- DBMS_OUTPUT.GET_LINE [5] CREATE TABLE dbms_output_test (buff VARCHAR(20), status INTEGER); CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ DECLARE buff VARCHAR(20); stts INTEGER; BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 1 '); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 2'); SELECT INTO buff,stts line,status FROM DBMS_OUTPUT.GET_LINE(); INSERT INTO dbms_output_test VALUES (buff, stts); SELECT INTO buff,stts line,status FROM DBMS_OUTPUT.GET_LINE(); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); dbms_output_test ------------------ (1 row) SELECT REPLACE(buff, ' ', '') FROM dbms_output_test; replace ------------------- ORAFCE TEST 1 ORAFCE TEST 2 (2 rows) DROP TABLE dbms_output_test; DROP FUNCTION dbms_output_test(); -- DBMS_OUTPUT.GET_LINE [6] CREATE TABLE dbms_output_test (buff VARCHAR(20), status INTEGER); CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ DECLARE buff VARCHAR(20); stts INTEGER; BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORA F CE'); SELECT INTO buff,stts line,status FROM DBMS_OUTPUT.GET_LINE(); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); dbms_output_test ------------------ (1 row) SELECT regexp_replace(buff, E'\n', '', 'g') FROM dbms_output_test limit 1; regexp_replace ---------------- ORAFCE (1 row) DROP TABLE dbms_output_test; DROP FUNCTION dbms_output_test(); -- DBMS_OUTPUT.GET_LINES [1] CREATE TABLE dbms_output_test (buff VARCHAR(20), status INTEGER); CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ DECLARE buff VARCHAR(20); buff1 VARCHAR(20); buff2 VARCHAR(20); buff3 VARCHAR(20); stts INTEGER := 10; BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 1'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 2'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 3'); SELECT INTO buff1,buff2,buff3,stts lines[1],lines[2],lines[3],numlines FROM DBMS_OUTPUT.GET_LINES(stts); INSERT INTO dbms_output_test VALUES (buff1, stts); INSERT INTO dbms_output_test VALUES (buff2, stts); INSERT INTO dbms_output_test VALUES (buff3, stts); SELECT INTO buff,stts lines[1],numlines FROM DBMS_OUTPUT.GET_LINES(stts); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); dbms_output_test ------------------ (1 row) SELECT * FROM dbms_output_test; buff | status ---------------+-------- ORAFCE TEST 1 | 3 ORAFCE TEST 2 | 3 ORAFCE TEST 3 | 3 | 0 (4 rows) DROP TABLE dbms_output_test; DROP FUNCTION dbms_output_test(); -- DBMS_OUTPUT.GET_LINES [2] CREATE TABLE dbms_output_test (buff VARCHAR(20), status INTEGER); CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ DECLARE buff VARCHAR(20); buff1 VARCHAR(20); buff2 VARCHAR(20); stts INTEGER := 2; BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 1'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 2'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 3'); SELECT INTO buff1,buff2,stts lines[1],lines[2],numlines FROM DBMS_OUTPUT.GET_LINES(stts); INSERT INTO dbms_output_test VALUES (buff1, stts); INSERT INTO dbms_output_test VALUES (buff2, stts); SELECT INTO buff,stts lines[1],numlines FROM DBMS_OUTPUT.GET_LINES(stts); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); dbms_output_test ------------------ (1 row) SELECT * FROM dbms_output_test; buff | status ---------------+-------- ORAFCE TEST 1 | 2 ORAFCE TEST 2 | 2 ORAFCE TEST 3 | 1 (3 rows) DROP TABLE dbms_output_test; DROP FUNCTION dbms_output_test(); -- DBMS_OUTPUT.GET_LINES [3] CREATE TABLE dbms_output_test (buff VARCHAR(20), status INTEGER); CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ DECLARE buff VARCHAR(20); stts INTEGER := 1; BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 1'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 2'); SELECT INTO buff,stts lines[1],numlines FROM DBMS_OUTPUT.GET_LINES(stts); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 3'); SELECT INTO buff,stts lines[1],numlines FROM DBMS_OUTPUT.GET_LINES(stts); INSERT INTO dbms_output_test VALUES (buff, stts); SELECT INTO buff,stts lines[1],numlines FROM DBMS_OUTPUT.GET_LINES(stts); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); dbms_output_test ------------------ (1 row) SELECT * FROM dbms_output_test; buff | status ---------------+-------- ORAFCE TEST 1 | 1 ORAFCE TEST 3 | 1 | 0 (3 rows) DROP TABLE dbms_output_test; DROP FUNCTION dbms_output_test(); -- DBMS_OUTPUT.GET_LINES [4] CREATE TABLE dbms_output_test (buff VARCHAR(20), status INTEGER); CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ DECLARE buff VARCHAR(20); stts INTEGER := 1; BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 1'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 2'); SELECT INTO buff,stts lines[1],numlines FROM DBMS_OUTPUT.GET_LINES(stts); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.PUT ('ORA'); SELECT INTO buff,stts lines[1],numlines FROM DBMS_OUTPUT.GET_LINES(stts); INSERT INTO dbms_output_test VALUES (buff, stts); SELECT INTO buff,stts lines[1],numlines FROM DBMS_OUTPUT.GET_LINES(stts); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); dbms_output_test ------------------ (1 row) SELECT * FROM dbms_output_test; buff | status ---------------+-------- ORAFCE TEST 1 | 1 ORA | 1 | 0 (3 rows) DROP TABLE dbms_output_test; DROP FUNCTION dbms_output_test(); -- DBMS_OUTPUT.GET_LINES [5] CREATE TABLE dbms_output_test (buff VARCHAR(20), status INTEGER); CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ DECLARE buff VARCHAR(20); stts INTEGER := 1; BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 1'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 2'); SELECT INTO buff,stts lines[1],numlines FROM DBMS_OUTPUT.GET_LINES(stts); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.NEW_LINE(); SELECT INTO buff,stts lines[1],numlines FROM DBMS_OUTPUT.GET_LINES(stts); INSERT INTO dbms_output_test VALUES (buff, stts); SELECT INTO buff,stts lines[1],numlines FROM DBMS_OUTPUT.GET_LINES(stts); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); dbms_output_test ------------------ (1 row) SELECT * FROM dbms_output_test; buff | status ---------------+-------- ORAFCE TEST 1 | 1 | 1 | 0 (3 rows) DROP TABLE dbms_output_test; DROP FUNCTION dbms_output_test(); -- DBMS_OUTPUT.GET_LINES [6] CREATE TABLE dbms_output_test (buff VARCHAR(20), status INTEGER); CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ DECLARE buff VARCHAR(20); stts INTEGER := 1; BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORA F CE'); SELECT INTO buff,stts lines[1],numlines FROM DBMS_OUTPUT.GET_LINES(stts); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); dbms_output_test ------------------ (1 row) SELECT regexp_replace(buff, E'\n', '', 'g') FROM dbms_output_test limit 1; regexp_replace ---------------- ORAFCE (1 row) DROP TABLE dbms_output_test; DROP FUNCTION dbms_output_test(); -- DBMS_OUTPUT.NEW_LINE [1] CREATE TABLE dbms_output_test (buff VARCHAR(20), status INTEGER); CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ DECLARE buff1 VARCHAR(20); buff2 VARCHAR(20); stts INTEGER := 10; BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.PUT ('ORA'); PERFORM DBMS_OUTPUT.NEW_LINE(); PERFORM DBMS_OUTPUT.PUT ('FCE'); PERFORM DBMS_OUTPUT.NEW_LINE(); SELECT INTO buff1,buff2,stts lines[1],lines[2],numlines FROM DBMS_OUTPUT.GET_LINES(stts); INSERT INTO dbms_output_test VALUES (buff1, stts); INSERT INTO dbms_output_test VALUES (buff2, stts); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); dbms_output_test ------------------ (1 row) SELECT * FROM dbms_output_test; buff | status ------+-------- ORA | 2 FCE | 2 (2 rows) DROP TABLE dbms_output_test; DROP FUNCTION dbms_output_test(); -- DBMS_OUTPUT.NEW_LINE [2] CREATE TABLE dbms_output_test (buff VARCHAR(3000), status INTEGER); CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ DECLARE buff1 VARCHAR(3000); stts INTEGER := 10; BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.ENABLE(2000); FOR j IN 1..1999 LOOP PERFORM DBMS_OUTPUT.PUT ('A'); END LOOP; PERFORM DBMS_OUTPUT.NEW_LINE(); SELECT INTO buff1,stts lines[1],numlines FROM DBMS_OUTPUT.GET_LINES(stts); INSERT INTO dbms_output_test VALUES (buff1, stts); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); dbms_output_test ------------------ (1 row) SELECT buff FROM dbms_output_test; buff --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA (1 row) DROP TABLE dbms_output_test; DROP FUNCTION dbms_output_test(); -- DBMS_OUTPUT.DISABLE [1] CREATE TABLE dbms_output_test (buff VARCHAR(20), status INTEGER); CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ DECLARE buff VARCHAR(20); stts INTEGER; BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 1'); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); SELECT INTO buff,stts line,status FROM DBMS_OUTPUT.GET_LINE(); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 2'); PERFORM DBMS_OUTPUT.ENABLE(); SELECT INTO buff,stts line,status FROM DBMS_OUTPUT.GET_LINE(); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 3'); PERFORM DBMS_OUTPUT.DISABLE(); SELECT INTO buff,stts line,status FROM DBMS_OUTPUT.GET_LINE(); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.PUT ('ORAFCE TEST 4'); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.NEW_LINE(); SELECT INTO buff,stts line,status FROM DBMS_OUTPUT.GET_LINE(); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.PUT ('ORAFCE TEST 5'); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.NEW_LINE(); PERFORM DBMS_OUTPUT.ENABLE(); SELECT INTO buff,stts line,status FROM DBMS_OUTPUT.GET_LINE(); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); dbms_output_test ------------------ (1 row) SELECT * FROM dbms_output_test; buff | status --------+-------- | 1 | 1 | 1 | 0 | 1 (5 rows) DROP TABLE dbms_output_test; DROP FUNCTION dbms_output_test(); -- DBMS_OUTPUT.DISABLE [2] CREATE TABLE dbms_output_test (buff VARCHAR(20), status INTEGER); CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ DECLARE buff VARCHAR(20); stts INTEGER := 10; BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 1'); SELECT INTO buff,stts lines[1],numlines FROM DBMS_OUTPUT.GET_LINES(stts); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.ENABLE(); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); dbms_output_test ------------------ (1 row) SELECT * FROM dbms_output_test; buff | status --------+-------- | 0 (1 row) DROP TABLE dbms_output_test; DROP FUNCTION dbms_output_test(); -- DBMS_OUTPUT.ENABLE [1] CREATE TABLE dbms_output_test (buff VARCHAR(20), status INTEGER); CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ DECLARE buff VARCHAR(20); status INTEGER; num INTEGER := 2000; BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('t'); PERFORM DBMS_OUTPUT.ENABLE(2000); PERFORM DBMS_OUTPUT.PUT ('ORAFCE TEST 1'); PERFORM DBMS_OUTPUT.NEW_LINE(); PERFORM DBMS_OUTPUT.ENABLE(); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); ORAFCE TEST 1 dbms_output_test ------------------ (1 row) SELECT * FROM dbms_output_test; buff | status ------+-------- (0 rows) DROP TABLE dbms_output_test; DROP FUNCTION dbms_output_test(); -- DBMS_OUTPUT.ENABLE [2] CREATE TABLE dbms_output_test (buff VARCHAR(20), status INTEGER); CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ DECLARE buff VARCHAR(20); stts INTEGER; BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 1'); SELECT INTO buff,stts line,status FROM DBMS_OUTPUT.GET_LINE(); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.PUT ('ORAFCE TEST 2'); PERFORM DBMS_OUTPUT.NEW_LINE(); SELECT INTO buff,stts line,status FROM DBMS_OUTPUT.GET_LINE(); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.ENABLE(); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); dbms_output_test ------------------ (1 row) SELECT * FROM dbms_output_test; buff | status ---------------+-------- ORAFCE TEST 1 | 0 ORAFCE TEST 2 | 0 (2 rows) DROP TABLE dbms_output_test; DROP FUNCTION dbms_output_test(); -- DBMS_OUTPUT.ENABLE [3] CREATE TABLE dbms_output_test (buff VARCHAR(20), status INTEGER); CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ DECLARE buff VARCHAR(20); stts INTEGER := 10; BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 1'); SELECT INTO buff,stts lines[1],numlines FROM DBMS_OUTPUT.GET_LINES(stts); INSERT INTO dbms_output_test VALUES (buff, stts); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); dbms_output_test ------------------ (1 row) SELECT * FROM dbms_output_test; buff | status ---------------+-------- ORAFCE TEST 1 | 1 (1 row) DROP TABLE dbms_output_test; DROP FUNCTION dbms_output_test(); -- DBMS_OUTPUT.ENABLE [4] CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('t'); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); FOR j IN 1..2000 LOOP PERFORM DBMS_OUTPUT.PUT ('A'); END LOOP; PERFORM DBMS_OUTPUT.NEW_LINE(); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA dbms_output_test ------------------ (1 row) DROP FUNCTION dbms_output_test(); -- DBMS_OUTPUT.ENABLE [5] CREATE TABLE dbms_output_test (buff VARCHAR(20), status INTEGER); CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ DECLARE buff VARCHAR(20); stts INTEGER; BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(NULL); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 1'); SELECT INTO buff,stts line,status FROM DBMS_OUTPUT.GET_LINE(); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); dbms_output_test ------------------ (1 row) SELECT * FROM dbms_output_test; buff | status ---------------+-------- ORAFCE TEST 1 | 0 (1 row) DROP TABLE dbms_output_test; DROP FUNCTION dbms_output_test(); -- DBMS_OUTPUT.ENABLE [6] CREATE TABLE dbms_output_test (buff VARCHAR(20), status INTEGER); CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ DECLARE buff VARCHAR(20); stts INTEGER; BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 1'); PERFORM DBMS_OUTPUT.ENABLE(); SELECT INTO buff,stts line,status FROM DBMS_OUTPUT.GET_LINE(); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); dbms_output_test ------------------ (1 row) SELECT * FROM dbms_output_test; buff | status ---------------+-------- ORAFCE TEST 1 | 0 (1 row) DROP TABLE dbms_output_test; DROP FUNCTION dbms_output_test(); -- SERVEROUTPUT [1] CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 1'); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); dbms_output_test ------------------ (1 row) DROP FUNCTION dbms_output_test(); CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ BEGIn PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('t'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 2'); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); ORAFCE TEST 2 dbms_output_test ------------------ (1 row) DROP FUNCTION dbms_output_test(); -- SERVEROUTPUT [2] CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.PUT ('ORAFCE TEST 1'); PERFORM DBMS_OUTPUT.NEW_LINE(); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); dbms_output_test ------------------ (1 row) DROP FUNCTION dbms_output_test(); CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('t'); PERFORM DBMS_OUTPUT.PUT ('ORAFCE TEST 2'); PERFORM DBMS_OUTPUT.NEW_LINE(); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); ORAFCE TEST 2 dbms_output_test ------------------ (1 row) DROP FUNCTION dbms_output_test(); -- SERVEROUTPUT [3] CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.DISABLE(); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); dbms_output_test ------------------ (1 row) DROP FUNCTION dbms_output_test(); CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('t'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 1'); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); ORAFCE TEST 1 dbms_output_test ------------------ (1 row) DROP FUNCTION dbms_output_test(); orafce-VERSION_3_9_0/expected/dbms_pipe_session_A.out000066400000000000000000000034421362147214200226350ustar00rootroot00000000000000\set ECHO none pack_message -------------- (1 row) send_message -------------- 0 (1 row) SELECT createImplicitPipe(); createimplicitpipe -------------------- (1 row) -- Bulk send messages SELECT bulkSend(); bulksend ---------- (1 row) -- An explicit private pipe SELECT notify('recv_private1_notifier'); notify -------- (1 row) SELECT createExplicitPipe('private_pipe_1',3); createexplicitpipe -------------------- (1 row) -- An explicit private pipe SELECT notify('recv_private2_notifier'); notify -------- (1 row) SELECT createExplicitPipe('private_pipe_2',3); createexplicitpipe -------------------- (1 row) -- An explicit public pipe (uses two-argument create_pipe) SELECT notify('recv_public1_notifier'); notify -------- (1 row) SELECT createExplicitPipe('public_pipe_3',2); createexplicitpipe -------------------- (1 row) -- An explicit public pipe (uses one-argument create_pipe) SELECT notify('recv_public2_notifier'); notify -------- (1 row) SELECT createExplicitPipe('public_pipe_4',1); createexplicitpipe -------------------- (1 row) -- tests send_message(text) SELECT checkSend1(); checksend1 ------------ (1 row) -- tests send_message(text,integer) SELECT checkSend2(); checksend2 ------------ (1 row) SELECT notifyDropTemp(); notifydroptemp ---------------- (1 row) -- tests unique_session_name() SELECT checkUniqueSessionNameA(); checkuniquesessionnamea ------------------------- (1 row) DROP FUNCTION createImplicitPipe(); DROP FUNCTION createExplicitPipe(text,integer); DROP FUNCTION createPipe(text,integer); DROP FUNCTION checkSend1(); DROP FUNCTION checkSend2(); DROP FUNCTION checkUniqueSessionNameA(); DROP FUNCTION bulkSend(); DROP FUNCTION notifyDropTemp(); DROP FUNCTION notify(text); DROP FUNCTION send(text); orafce-VERSION_3_9_0/expected/dbms_pipe_session_B.out000066400000000000000000000140001362147214200226260ustar00rootroot00000000000000\set ECHO none receive_message ----------------- 0 (1 row) -- Receives messages sent via an implicit pipe SELECT receiveFrom('named_pipe'); NOTICE: RECEIVE 11: Message From Session A NOTICE: RECEIVE 12: 01-01-2013 NOTICE: RECEIVE 13: Tue Jan 01 09:00:00 2013 PST NOTICE: RECEIVE 13: Tue Jan 01 09:00:00 2013 PST NOTICE: RECEIVE 9: 12345.6789 NOTICE: RECEIVE 9: 12345 NOTICE: RECEIVE 9: 99999999999 NOTICE: RECEIVE 23: \201 NOTICE: RECEIVE 24: (2,rob) receivefrom ------------- (1 row) -- Bulk receive messages SELECT bulkReceive(); NOTICE: RECEIVE 11: Message From Session A NOTICE: RECEIVE 12: 01-01-2013 NOTICE: RECEIVE 13: Tue Jan 01 09:00:00 2013 PST NOTICE: RECEIVE 13: Tue Jan 01 09:00:00 2013 PST NOTICE: RECEIVE 9: 12345.6789 NOTICE: RECEIVE 9: 12345 NOTICE: RECEIVE 9: 99999999999 NOTICE: RECEIVE 23: \201 NOTICE: RECEIVE 24: (2,rob) bulkreceive ------------- (1 row) -- Receives messages sent via an explicit private pipe under the same user -- 'pipe_test_owner' SELECT dbms_pipe.receive_message('recv_private1_notifier'); receive_message ----------------- 0 (1 row) SELECT receiveFrom('private_pipe_1'); NOTICE: RECEIVE 11: Message From Session A NOTICE: RECEIVE 12: 01-01-2013 NOTICE: RECEIVE 13: Tue Jan 01 09:00:00 2013 PST NOTICE: RECEIVE 13: Tue Jan 01 09:00:00 2013 PST NOTICE: RECEIVE 9: 12345.6789 NOTICE: RECEIVE 9: 12345 NOTICE: RECEIVE 9: 99999999999 NOTICE: RECEIVE 23: \201 NOTICE: RECEIVE 24: (2,rob) receivefrom ------------- (1 row) -- Switch user to 'pipe_test_other' DROP USER IF EXISTS pipe_test_other; NOTICE: role "pipe_test_other" does not exist, skipping CREATE USER pipe_test_other; SET SESSION AUTHORIZATION pipe_test_other; -- Try to receive messages sent via an explicit private pipe under the user -- 'pipe_test_other' who is not the owner of pipe. -- insufficient privileges in case of 'private_pipe_2'. SELECT dbms_pipe.receive_message('recv_private2_notifier'); receive_message ----------------- 0 (1 row) SELECT receiveFrom('private_pipe_2'); ERROR: insufficient privilege -- These are explicit private pipes created using create_pipe(text,integer) -- and create_pipe(text) SELECT dbms_pipe.receive_message('recv_public1_notifier'); receive_message ----------------- 0 (1 row) SELECT receiveFrom('public_pipe_3'); NOTICE: RECEIVE 11: Message From Session A NOTICE: RECEIVE 12: 01-01-2013 NOTICE: RECEIVE 13: Tue Jan 01 09:00:00 2013 PST NOTICE: RECEIVE 13: Tue Jan 01 09:00:00 2013 PST NOTICE: RECEIVE 9: 12345.6789 NOTICE: RECEIVE 9: 12345 NOTICE: RECEIVE 9: 99999999999 NOTICE: RECEIVE 23: \201 NOTICE: RECEIVE 24: (2,rob) receivefrom ------------- (1 row) SELECT dbms_pipe.receive_message('recv_public2_notifier'); receive_message ----------------- 0 (1 row) SELECT receiveFrom('public_pipe_4'); NOTICE: RECEIVE 11: Message From Session A NOTICE: RECEIVE 12: 01-01-2013 NOTICE: RECEIVE 13: Tue Jan 01 09:00:00 2013 PST NOTICE: RECEIVE 13: Tue Jan 01 09:00:00 2013 PST NOTICE: RECEIVE 9: 12345.6789 NOTICE: RECEIVE 9: 12345 NOTICE: RECEIVE 9: 99999999999 NOTICE: RECEIVE 23: \201 NOTICE: RECEIVE 24: (2,rob) receivefrom ------------- (1 row) -- Switch back to user 'pipe_test_owner' SET SESSION AUTHORIZATION pipe_test_owner; DROP USER pipe_test_other; -- Tests receive_message(text) SELECT checkReceive1('pipe_name_1'); NOTICE: RECEIVE checking one-argument send_message() checkreceive1 --------------- (1 row) SELECT checkReceive1('pipe_name_2'); NOTICE: RECEIVE checking two-argument send_message() checkreceive1 --------------- (1 row) -- Tests dbms_pipe.db_pipes view SELECT name, items, "limit", private, owner FROM dbms_pipe.db_pipes WHERE name LIKE 'private%' ORDER BY name; name | items | limit | private | owner ----------------+-------+-------+---------+----------------- private_pipe_1 | 0 | 10 | t | pipe_test_owner private_pipe_2 | 9 | 10 | t | pipe_test_owner (2 rows) -- Tests dbms_pipe.__list_pipes(); attribute size is not included -- since it can be different across runs. SELECT name, items, "limit", private, owner FROM dbms_pipe.__list_pipes() AS (name varchar, items int4, siz int4, "limit" int4, private bool, owner varchar) WHERE name <> 'pipe_name_4' ORDER BY 1; name | items | limit | private | owner ----------------+-------+-------+---------+----------------- pipe_name_3 | 1 | | f | private_pipe_1 | 0 | 10 | t | pipe_test_owner private_pipe_2 | 9 | 10 | t | pipe_test_owner public_pipe_3 | 0 | 10 | f | public_pipe_4 | 0 | 10 | f | (5 rows) -- Tests remove_pipe(text) SELECT dbms_pipe.remove_pipe('private_pipe_1'); remove_pipe ------------- (1 row) SELECT dbms_pipe.remove_pipe('private_pipe_2'); remove_pipe ------------- (1 row) SELECT dbms_pipe.remove_pipe('public_pipe_3'); remove_pipe ------------- (1 row) SELECT dbms_pipe.remove_pipe('public_pipe_4'); remove_pipe ------------- (1 row) SELECT dbms_pipe.purge('pipe_name_1'); purge ------- (1 row) SELECT dbms_pipe.purge('pipe_name_2'); purge ------- (1 row) -- Receives drop table notification from session A via 'pipe_name_3' SELECT dropTempTable(); droptemptable --------------- (1 row) SELECT dbms_pipe.purge('pipe_name_3'); purge ------- (1 row) -- tests unique_session_name() (uses 'pipe_name_4') SELECT checkUniqueSessionNameB(); checkuniquesessionnameb ------------------------- f (1 row) SELECT dbms_pipe.purge('pipe_name_4'); purge ------- (1 row) DROP FUNCTION receiveFrom(text); DROP FUNCTION checkReceive1(text); DROP FUNCTION checkUniqueSessionNameB(); DROP FUNCTION bulkReceive(); DROP FUNCTION dropTempTable(); -- Perform a recieve on removed pipe resulting on timeout SELECT dbms_pipe.receive_message('public_pipe_4',2); receive_message ----------------- 1 (1 row) SELECT dbms_pipe.purge('public_pipe_4'); purge ------- (1 row) SET SESSION AUTHORIZATION DEFAULT; DROP USER pipe_test_owner; orafce-VERSION_3_9_0/expected/dbms_random.out000066400000000000000000000021371362147214200211550ustar00rootroot00000000000000-- Tests for package DBMS_RANDOM SELECT dbms_random.initialize(8); initialize ------------ (1 row) SELECT dbms_random.normal()::numeric(10, 8); normal ------------- -0.37787769 (1 row) SELECT dbms_random.normal()::numeric(10, 8); normal ------------ 0.80499804 (1 row) SELECT dbms_random.seed(8); seed ------ (1 row) SELECT dbms_random.random(); random ------------ -632387854 (1 row) SELECT dbms_random.seed('test'); seed ------ (1 row) SELECT dbms_random.string('U',5); string -------- XEJGE (1 row) SELECT dbms_random.string('P',2); string -------- T9 (1 row) SELECT dbms_random.string('x',4); string -------- FVGL (1 row) SELECT dbms_random.string('a',2); string -------- AZ (1 row) SELECT dbms_random.string('l',3); string -------- hmo (1 row) SELECT dbms_random.seed(5); seed ------ (1 row) SELECT dbms_random.value()::numeric(10, 8); value ------------ 0.27474560 (1 row) SELECT dbms_random.value(10,15)::numeric(10, 8); value ------------- 10.23233882 (1 row) SELECT dbms_random.terminate(); terminate ----------- (1 row) orafce-VERSION_3_9_0/expected/dbms_utility.out000066400000000000000000000006341362147214200214000ustar00rootroot00000000000000\set ECHO none checkhexcallstack ----- PL/pgSQL Call Stack ----- object line object handle number name 0 function anonymous object 0 function checkhexcallstack (1 row) checkintcallstack 0 function anonymous object 0 function checkintcallstack (1 row) checkintunpaddedcallstack 0,,anonymous object 0,,checkintunpaddedcallstack (1 row) orafce-VERSION_3_9_0/expected/files.out000066400000000000000000000130221362147214200177650ustar00rootroot00000000000000SET client_min_messages = NOTICE; \set VERBOSITY terse \set ECHO all CREATE OR REPLACE FUNCTION gen_file(dir text) RETURNS void AS $$ DECLARE f utl_file.file_type; BEGIN f := utl_file.fopen(dir, 'regress_orafce.txt', 'w'); PERFORM utl_file.put_line(f, 'ABC'); PERFORM utl_file.put_line(f, '123'::numeric); PERFORM utl_file.put_line(f, '-----'); PERFORM utl_file.new_line(f); PERFORM utl_file.put_line(f, '-----'); PERFORM utl_file.new_line(f, 0); PERFORM utl_file.put_line(f, '-----'); PERFORM utl_file.new_line(f, 2); PERFORM utl_file.put_line(f, '-----'); PERFORM utl_file.put(f, 'A'); PERFORM utl_file.put(f, 'B'); PERFORM utl_file.new_line(f); PERFORM utl_file.putf(f, '[1=%s, 2=%s, 3=%s, 4=%s, 5=%s]', '1', '2', '3', '4', '5'); PERFORM utl_file.new_line(f); PERFORM utl_file.put_line(f, '1234567890'); f := utl_file.fclose(f); END; $$ LANGUAGE plpgsql; /* Test functions utl_file.fflush(utl_file.file_type) and * utl_file.get_nextline(utl_file.file_type) * This function tests the positive test case of fflush by reading from the * file after flushing the contents to the file. */ CREATE OR REPLACE FUNCTION checkFlushFile(dir text) RETURNS void AS $$ DECLARE f utl_file.file_type; f1 utl_file.file_type; ret_val text; i integer; BEGIN f := utl_file.fopen(dir, 'regressflush_orafce.txt', 'a'); PERFORM utl_file.put_line(f, 'ABC'); PERFORM utl_file.new_line(f); PERFORM utl_file.put_line(f, '123'::numeric); PERFORM utl_file.new_line(f); PERFORM utl_file.putf(f, '[1=%s, 2=%s, 3=%s, 4=%s, 5=%s]', '1', '2', '3', '4', '5'); PERFORM utl_file.fflush(f); f1 := utl_file.fopen(dir, 'regressflush_orafce.txt', 'r'); ret_val=utl_file.get_nextline(f1); i:=1; WHILE ret_val IS NOT NULL LOOP RAISE NOTICE '[%] >>%<<', i,ret_val; ret_val := utl_file.get_nextline(f1); i:=i+1; END LOOP; RAISE NOTICE '>>%<<', ret_val; f1 := utl_file.fclose(f1); f := utl_file.fclose(f); END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION read_file(dir text) RETURNS void AS $$ DECLARE f utl_file.file_type; BEGIN f := utl_file.fopen(dir, 'regress_orafce.txt', 'r'); FOR i IN 1..11 LOOP RAISE NOTICE '[%] >>%<<', i, utl_file.get_line(f); END LOOP; RAISE NOTICE '>>%<<', utl_file.get_line(f, 4); RAISE NOTICE '>>%<<', utl_file.get_line(f, 4); RAISE NOTICE '>>%<<', utl_file.get_line(f); RAISE NOTICE '>>%<<', utl_file.get_line(f); EXCEPTION -- WHEN no_data_found THEN, 8.1 plpgsql doesn't know no_data_found WHEN others THEN RAISE NOTICE 'finish % ', sqlerrm; RAISE NOTICE 'is_open = %', utl_file.is_open(f); PERFORM utl_file.fclose_all(); RAISE NOTICE 'is_open = %', utl_file.is_open(f); END; $$ LANGUAGE plpgsql; SELECT EXISTS(SELECT * FROM pg_catalog.pg_class where relname='utl_file_dir') AS exists; exists -------- t (1 row) SELECT EXISTS(SELECT * FROM pg_catalog.pg_type where typname='file_type') AS exists; exists -------- t (1 row) -- Trying to access a file in path not registered SELECT utl_file.fopen(utl_file.tmpdir(),'sample.txt','r'); ERROR: UTL_FILE_INVALID_PATH -- Trying to access file in a non-existent directory INSERT INTO utl_file.utl_file_dir(dir) VALUES('test_tmp_dir'); SELECT utl_file.fopen('test_tmp_dir','file.txt.','w'); ERROR: UTL_FILE_INVALID_PATH DELETE FROM utl_file.utl_file_dir WHERE dir LIKE 'test_tmp_dir'; -- Add tmpdir() to utl_file_dir table INSERT INTO utl_file.utl_file_dir(dir) VALUES(utl_file.tmpdir()); SELECT count(*) from utl_file.utl_file_dir where dir <> ''; count ------- 1 (1 row) -- Trying to access non-existent file SELECT utl_file.fopen(utl_file.tmpdir(),'non_existent_file.txt','r'); ERROR: UTL_FILE_INVALID_PATH --Other test cases SELECT gen_file(utl_file.tmpdir()); gen_file ---------- (1 row) SELECT fexists FROM utl_file.fgetattr(utl_file.tmpdir(), 'regress_orafce.txt'); fexists --------- t (1 row) SELECT utl_file.fcopy(utl_file.tmpdir(), 'regress_orafce.txt', utl_file.tmpdir(), 'regress_orafce2.txt'); fcopy ------- (1 row) SELECT fexists FROM utl_file.fgetattr(utl_file.tmpdir(), 'regress_orafce2.txt'); fexists --------- t (1 row) SELECT utl_file.frename(utl_file.tmpdir(), 'regress_orafce2.txt', utl_file.tmpdir(), 'regress_orafce.txt', true); frename --------- (1 row) SELECT fexists FROM utl_file.fgetattr(utl_file.tmpdir(), 'regress_orafce.txt'); fexists --------- t (1 row) SELECT fexists FROM utl_file.fgetattr(utl_file.tmpdir(), 'regress_orafce2.txt'); fexists --------- f (1 row) SELECT read_file(utl_file.tmpdir()); NOTICE: [1] >>ABC<< NOTICE: [2] >>123<< NOTICE: [3] >>-----<< NOTICE: [4] >><< NOTICE: [5] >>-----<< NOTICE: [6] >>-----<< NOTICE: [7] >><< NOTICE: [8] >><< NOTICE: [9] >>-----<< NOTICE: [10] >>AB<< NOTICE: [11] >>[1=1, 2=2, 3=3, 4=4, 5=5]<< NOTICE: >>1234<< NOTICE: >>5678<< NOTICE: >>90<< NOTICE: finish no data found NOTICE: is_open = t NOTICE: is_open = f read_file ----------- (1 row) SELECT utl_file.fremove(utl_file.tmpdir(), 'regress_orafce.txt'); fremove --------- (1 row) SELECT fexists FROM utl_file.fgetattr(utl_file.tmpdir(), 'regress_orafce.txt'); fexists --------- f (1 row) DROP FUNCTION gen_file(text); DROP FUNCTION read_file(text); SELECT checkFlushFile(utl_file.tmpdir()); NOTICE: [1] >>ABC<< NOTICE: [2] >><< NOTICE: [3] >>123<< NOTICE: [4] >><< NOTICE: [5] >>[1=1, 2=2, 3=3, 4=4, 5=5]<< NOTICE: >><< checkflushfile ---------------- (1 row) SELECT utl_file.fremove(utl_file.tmpdir(), 'regressflush_orafce.txt'); fremove --------- (1 row) DROP FUNCTION checkFlushFile(text); DELETE FROM utl_file.utl_file_dir; orafce-VERSION_3_9_0/expected/init.out000066400000000000000000000000171362147214200176260ustar00rootroot00000000000000\set ECHO none orafce-VERSION_3_9_0/expected/nlssort.out000066400000000000000000000010451362147214200203710ustar00rootroot00000000000000-- Tests for nlssort \set ECHO none name -------- brown Purple red yellow (4 rows) name -------- Purple brown red yellow (4 rows) set_nls_sort -------------- (1 row) ERROR: failed to set the requested LC_COLLATE value [invalid] CONTEXT: SQL function "nlssort" statement 1 set_nls_sort -------------- (1 row) name -------- Purple brown red yellow (4 rows) set_nls_sort -------------- (1 row) name -------- brown Purple red yellow (4 rows) name -------- brown Purple red yellow (5 rows) orafce-VERSION_3_9_0/expected/nvarchar2.out000066400000000000000000000027541362147214200205630ustar00rootroot00000000000000\set VERBOSITY terse SET client_encoding = utf8; -- -- test type modifier related rules -- -- ERROR (typmod >= 1) CREATE TABLE bar (a NVARCHAR2(0)); ERROR: length for type varchar must be at least 1 at character 21 -- ERROR (number of typmods = 1) CREATE TABLE bar (a NVARCHAR2(10, 1)); ERROR: invalid type modifier at character 21 -- OK CREATE TABLE bar (a VARCHAR(5000)); CREATE INDEX ON bar(a); -- cleanup DROP TABLE bar; -- OK CREATE TABLE bar (a NVARCHAR2(5)); -- -- test that no value longer than maxlen is allowed -- -- ERROR (length > 5) INSERT INTO bar VALUES ('abcdef'); ERROR: input value too long for type nvarchar2(5) -- ERROR (length > 5); -- NVARCHAR2 does not truncate blank spaces on implicit coercion INSERT INTO bar VALUES ('abcde '); ERROR: input value too long for type nvarchar2(5) -- OK INSERT INTO bar VALUES ('abcde'); -- OK INSERT INTO bar VALUES ('abcdef'::NVARCHAR2(5)); -- OK INSERT INTO bar VALUES ('abcde '::NVARCHAR2(5)); --OK INSERT INTO bar VALUES ('abc'::NVARCHAR2(5)); -- -- test whitespace semantics on comparison -- -- equal SELECT 'abcde '::NVARCHAR2(10) = 'abcde '::NVARCHAR2(10); ?column? ---------- t (1 row) -- not equal SELECT 'abcde '::NVARCHAR2(10) = 'abcde '::NVARCHAR2(10); ?column? ---------- f (1 row) -- null safe concat (disabled by default) SELECT NULL || 'hello'::varchar2 || NULL; ?column? ---------- (1 row) SET orafce.varchar2_null_safe_concat TO true; SELECT NULL || 'hello'::varchar2 || NULL; ?column? ---------- hello (1 row) orafce-VERSION_3_9_0/expected/orafce.out000066400000000000000000002701651362147214200201370ustar00rootroot00000000000000\set ECHO none -- -- test built-in date type oracle compatibility functions -- SELECT add_months ('2003-08-01', 3); add_months ------------ 2003-11-01 (1 row) SELECT add_months ('2003-08-01', -3); add_months ------------ 2003-05-01 (1 row) SELECT add_months ('2003-08-21', -3); add_months ------------ 2003-05-21 (1 row) SELECT add_months ('2003-01-31', 1); add_months ------------ 2003-02-28 (1 row) SELECT add_months ('2008-02-28', 1); add_months ------------ 2008-03-28 (1 row) SELECT add_months ('2008-02-29', 1); add_months ------------ 2008-03-31 (1 row) SELECT add_months ('2008-01-31', 12); add_months ------------ 2009-01-31 (1 row) SELECT add_months ('2008-01-31', -12); add_months ------------ 2007-01-31 (1 row) SELECT add_months ('2008-01-31', 95903); add_months ------------ 9999-12-31 (1 row) SELECT add_months ('2008-01-31', -80640); add_months --------------- 4712-01-31 BC (1 row) SELECT add_months ('03-21-2008',3); add_months ------------ 2008-06-21 (1 row) SELECT add_months ('21-MAR-2008',3); add_months ------------ 2008-06-21 (1 row) SELECT add_months ('21-MAR-08',3); add_months ------------ 2008-06-21 (1 row) SELECT add_months ('2008-MAR-21',3); add_months ------------ 2008-06-21 (1 row) SELECT add_months ('March 21,2008',3); add_months ------------ 2008-06-21 (1 row) SELECT add_months('03/21/2008',3); add_months ------------ 2008-06-21 (1 row) SELECT add_months('20080321',3); add_months ------------ 2008-06-21 (1 row) SELECT add_months('080321',3); add_months ------------ 2008-06-21 (1 row) SET search_path TO oracle,"$user", public, pg_catalog; SELECT add_months ('2003-08-01 10:12:21', 3); add_months --------------------- 2003-11-01 10:12:21 (1 row) SELECT add_months ('2003-08-01 10:21:21', -3); add_months --------------------- 2003-05-01 10:21:21 (1 row) SELECT add_months ('2003-08-21 12:21:21', -3); add_months --------------------- 2003-05-21 12:21:21 (1 row) SELECT add_months ('2003-01-31 01:12:45', 1); add_months --------------------- 2003-02-28 01:12:45 (1 row) SELECT add_months ('2008-02-28 02:12:12', 1); add_months --------------------- 2008-03-28 02:12:12 (1 row) SELECT add_months ('2008-02-29 12:12:12', 1); add_months --------------------- 2008-03-31 12:12:12 (1 row) SELECT add_months ('2008-01-31 11:11:21', 12); add_months --------------------- 2009-01-31 11:11:21 (1 row) SELECT add_months ('2008-01-31 11:21:21', -12); add_months --------------------- 2007-01-31 11:21:21 (1 row) SELECT add_months ('2008-01-31 12:12:12', 95903); add_months --------------------- 9999-12-31 12:12:12 (1 row) SELECT add_months ('2008-01-31 11:32:12', -80640); add_months ------------------------ 4712-01-31 11:32:12 BC (1 row) SELECT add_months ('03-21-2008 08:12:22',3); add_months --------------------- 2008-06-21 08:12:22 (1 row) SELECT add_months ('21-MAR-2008 06:02:12',3); add_months --------------------- 2008-06-21 06:02:12 (1 row) SELECT add_months ('21-MAR-08 12:11:22',3); add_months --------------------- 2008-06-21 12:11:22 (1 row) SELECT add_months ('2008-MAR-21 11:32:43',3); add_months --------------------- 2008-06-21 11:32:43 (1 row) SELECT add_months ('March 21,2008 12:32:12',3); add_months --------------------- 2008-06-21 12:32:12 (1 row) SELECT add_months('03/21/2008 12:32:12',3); add_months --------------------- 2008-06-21 12:32:12 (1 row) SELECT add_months('20080321 123244',3); add_months --------------------- 2008-06-21 12:32:44 (1 row) SELECT add_months('080321 121212',3); add_months --------------------- 2008-06-21 12:12:12 (1 row) SET search_path TO default; SELECT last_day(to_date('2003/03/15', 'yyyy/mm/dd')); last_day ------------ 2003-03-31 (1 row) SELECT last_day(to_date('2003/02/03', 'yyyy/mm/dd')); last_day ------------ 2003-02-28 (1 row) SELECT last_day(to_date('2004/02/03', 'yyyy/mm/dd')); last_day ------------ 2004-02-29 (1 row) SELECT last_day('1900-02-01'); last_day ------------ 1900-02-28 (1 row) SELECT last_day('2000-02-01'); last_day ------------ 2000-02-29 (1 row) SELECT last_day('2007-02-01'); last_day ------------ 2007-02-28 (1 row) SELECT last_day('2008-02-01'); last_day ------------ 2008-02-29 (1 row) SET search_path TO oracle,"$user", public, pg_catalog; SELECT last_day(to_date('2003/03/15 11:12:21', 'yyyy/mm/dd hh:mi:ss')); last_day --------------------- 2003-03-31 11:12:21 (1 row) SELECT last_day(to_date('2003/02/03 10:21:32', 'yyyy/mm/dd hh:mi:ss')); last_day --------------------- 2003-02-28 10:21:32 (1 row) SELECT last_day(to_date('2004/02/03 11:32:12', 'yyyy/mm/dd hh:mi:ss')); last_day --------------------- 2004-02-29 11:32:12 (1 row) SELECT last_day('1900-02-01 12:12:11'); last_day --------------------- 1900-02-28 12:12:11 (1 row) SELECT last_day('2000-02-01 121143'); last_day --------------------- 2000-02-29 12:11:43 (1 row) SELECT last_day('2007-02-01 12:21:33'); last_day --------------------- 2007-02-28 12:21:33 (1 row) SELECT last_day('2008-02-01 121212'); last_day --------------------- 2008-02-29 12:12:12 (1 row) SET search_path TO default; SELECT next_day ('2003-08-01', 'TUESDAY'); next_day ------------ 2003-08-05 (1 row) SELECT next_day ('2003-08-06', 'WEDNESDAY'); next_day ------------ 2003-08-13 (1 row) SELECT next_day ('2003-08-06', 'SUNDAY'); next_day ------------ 2003-08-10 (1 row) SELECT next_day ('2008-01-01', 'sun'); next_day ------------ 2008-01-06 (1 row) SELECT next_day ('2008-01-01', 'sunAAA'); next_day ------------ 2008-01-06 (1 row) SELECT next_day ('2008-01-01', 1); next_day ------------ 2008-01-06 (1 row) SELECT next_day ('2008-01-01', 7); next_day ------------ 2008-01-05 (1 row) SET search_path TO oracle,"$user", public, pg_catalog; SELECT next_day ('2003-08-01 111211', 'TUESDAY'); next_day --------------------- 2003-08-05 11:12:11 (1 row) SELECT next_day ('2003-08-06 10:11:43', 'WEDNESDAY'); next_day --------------------- 2003-08-13 10:11:43 (1 row) SELECT next_day ('2003-08-06 11:21:21', 'SUNDAY'); next_day --------------------- 2003-08-10 11:21:21 (1 row) SELECT next_day ('2008-01-01 111343', 'sun'); next_day --------------------- 2008-01-06 11:13:43 (1 row) SELECT next_day ('2008-01-01 121212', 'sunAAA'); next_day --------------------- 2008-01-06 12:12:12 (1 row) SELECT next_day ('2008-01-01 111213', 1); next_day --------------------- 2008-01-06 11:12:13 (1 row) SELECT next_day ('2008-01-01 11:12:13', 7); next_day --------------------- 2008-01-05 11:12:13 (1 row) SET search_path TO default; SELECT months_between (to_date ('2003/01/01', 'yyyy/mm/dd'), to_date ('2003/03/14', 'yyyy/mm/dd')); months_between ------------------- -2.41935483870968 (1 row) SELECT months_between (to_date ('2003/07/01', 'yyyy/mm/dd'), to_date ('2003/03/14', 'yyyy/mm/dd')); months_between ------------------ 3.58064516129032 (1 row) SELECT months_between (to_date ('2003/07/02', 'yyyy/mm/dd'), to_date ('2003/07/02', 'yyyy/mm/dd')); months_between ---------------- 0 (1 row) SELECT months_between (to_date ('2003/08/02', 'yyyy/mm/dd'), to_date ('2003/06/02', 'yyyy/mm/dd')); months_between ---------------- 2 (1 row) SELECT months_between ('2007-02-28', '2007-04-30'); months_between ---------------- -2 (1 row) SELECT months_between ('2008-01-31', '2008-02-29'); months_between ---------------- -1 (1 row) SELECT months_between ('2008-02-29', '2008-03-31'); months_between ---------------- -1 (1 row) SELECT months_between ('2008-02-29', '2008-04-30'); months_between ---------------- -2 (1 row) SELECT trunc(months_between('21-feb-2008', '2008-02-29')); trunc ------- 0 (1 row) SET search_path TO oracle,"$user", public, pg_catalog; SELECT months_between (to_date ('2003/01/01 12:12:12', 'yyyy/mm/dd h24:mi:ss'), to_date ('2003/03/14 11:11:11', 'yyyy/mm/dd h24:mi:ss')); months_between ------------------- -2.41935483870968 (1 row) SELECT months_between (to_date ('2003/07/01 10:11:11', 'yyyy/mm/dd h24:mi:ss'), to_date ('2003/03/14 10:12:12', 'yyyy/mm/dd h24:mi:ss')); months_between ------------------ 3.58064516129032 (1 row) SELECT months_between (to_date ('2003/07/02 11:21:21', 'yyyy/mm/dd h24:mi:ss'), to_date ('2003/07/02 11:11:11', 'yyyy/mm/dd h24:mi:ss')); months_between ---------------- 0 (1 row) SELECT months_between (to_timestamp ('2003/08/02 10:11:12', 'yyyy/mm/dd h24:mi:ss'), to_date ('2003/06/02 10:10:11', 'yyyy/mm/dd h24:mi:ss')); months_between ---------------- 2 (1 row) SELECT months_between ('2007-02-28 111111', '2007-04-30 112121'); months_between ---------------- -2 (1 row) SELECT months_between ('2008-01-31 11:32:11', '2008-02-29 11:12:12'); months_between ---------------- -1 (1 row) SELECT months_between ('2008-02-29 10:11:13', '2008-03-31 10:12:11'); months_between ---------------- -1 (1 row) SELECT months_between ('2008-02-29 111111', '2008-04-30 12:12:12'); months_between ---------------- -2 (1 row) SELECT trunc(months_between('21-feb-2008 12:11:11', '2008-02-29 11:11:11')); trunc ------- 0 (1 row) SET search_path TO default; select length('jmenuji se Pavel Stehule'),dbms_pipe.pack_message('jmenuji se Pavel Stehule'); length | pack_message --------+-------------- 24 | (1 row) select length('a bydlim ve Skalici'),dbms_pipe.pack_message('a bydlim ve Skalici'); length | pack_message --------+-------------- 19 | (1 row) select dbms_pipe.send_message('pavel',0,1); send_message -------------- 0 (1 row) select dbms_pipe.send_message('pavel',0,2); send_message -------------- 0 (1 row) select dbms_pipe.receive_message('pavel',0); receive_message ----------------- 0 (1 row) select '>>>>'||dbms_pipe.unpack_message_text()||'<<<<'; ?column? ---------------------------------- >>>>jmenuji se Pavel Stehule<<<< (1 row) select '>>>>'||dbms_pipe.unpack_message_text()||'<<<<'; ?column? ----------------------------- >>>>a bydlim ve Skalici<<<< (1 row) select dbms_pipe.receive_message('pavel',0); receive_message ----------------- 0 (1 row) select dbms_pipe.purge('bob'); purge ------- (1 row) select dbms_pipe.reset_buffer(); reset_buffer -------------- (1 row) select dbms_pipe.pack_message('012345678901234+1'); pack_message -------------- (1 row) select dbms_pipe.send_message('bob',0,10); send_message -------------- 0 (1 row) select dbms_pipe.pack_message('012345678901234+2'); pack_message -------------- (1 row) select dbms_pipe.send_message('bob',0,10); send_message -------------- 0 (1 row) select dbms_pipe.pack_message('012345678901234+3'); pack_message -------------- (1 row) select dbms_pipe.send_message('bob',0,10); send_message -------------- 0 (1 row) -------------------------------------------- select dbms_pipe.receive_message('bob',0); receive_message ----------------- 0 (1 row) select dbms_pipe.unpack_message_text(); unpack_message_text --------------------- 012345678901234+1 (1 row) select dbms_pipe.receive_message('bob',0); receive_message ----------------- 0 (1 row) select dbms_pipe.unpack_message_text(); unpack_message_text --------------------- 012345678901234+2 (1 row) select dbms_pipe.receive_message('bob',0); receive_message ----------------- 0 (1 row) select dbms_pipe.unpack_message_text(); unpack_message_text --------------------- 012345678901234+3 (1 row) select dbms_pipe.unique_session_name() LIKE 'PG$PIPE$%'; ?column? ---------- t (1 row) select dbms_pipe.pack_message('012345678901234-1'); pack_message -------------- (1 row) select dbms_pipe.send_message('bob',0,10); send_message -------------- 0 (1 row) select dbms_pipe.receive_message('bob',0); receive_message ----------------- 0 (1 row) select dbms_pipe.unpack_message_text(); unpack_message_text --------------------- 012345678901234-1 (1 row) select dbms_pipe.pack_message('012345678901234-2'); pack_message -------------- (1 row) select dbms_pipe.send_message('bob',0,10); send_message -------------- 0 (1 row) select dbms_pipe.send_message('bob',0,10); send_message -------------- 0 (1 row) select dbms_pipe.receive_message('bob',0); receive_message ----------------- 0 (1 row) select dbms_pipe.unpack_message_text(); unpack_message_text --------------------- 012345678901234-2 (1 row) select dbms_pipe.pack_message(TO_DATE('2006-10-11', 'YYYY-MM-DD')); pack_message -------------- (1 row) select dbms_pipe.send_message('test_date'); send_message -------------- 0 (1 row) select dbms_pipe.receive_message('test_date'); receive_message ----------------- 0 (1 row) select dbms_pipe.next_item_type(); next_item_type ---------------- 12 (1 row) select dbms_pipe.unpack_message_date(); unpack_message_date --------------------- 2006-10-11 (1 row) select dbms_pipe.pack_message(to_timestamp('2008-10-30 01:23:45', 'YYYY-MM-DD HH24:MI:SS')); pack_message -------------- (1 row) select dbms_pipe.send_message('test_timestamp'); send_message -------------- 0 (1 row) select dbms_pipe.receive_message('test_timestamp'); receive_message ----------------- 0 (1 row) select dbms_pipe.next_item_type(); next_item_type ---------------- 13 (1 row) select to_char(dbms_pipe.unpack_message_timestamp(), 'YYYY-MM-DD HH24:MI:SS'); to_char --------------------- 2008-10-30 01:23:45 (1 row) select dbms_pipe.pack_message(6262626262::numeric); pack_message -------------- (1 row) select dbms_pipe.send_message('test_int'); send_message -------------- 0 (1 row) select dbms_pipe.receive_message('test_int'); receive_message ----------------- 0 (1 row) select dbms_pipe.next_item_type(); next_item_type ---------------- 9 (1 row) select dbms_pipe.unpack_message_number(); unpack_message_number ----------------------- 6262626262 (1 row) select dbms_pipe.purge('bob'); purge ------- (1 row) select name, items, "limit", private, owner from dbms_pipe.db_pipes where name = 'bob'; name | items | limit | private | owner ------+-------+-------+---------+------- (0 rows) select PLVstr.betwn('Harry and Sally are very happy', 7, 9); betwn ------- and (1 row) select PLVstr.betwn('Harry and Sally are very happy', 7, 9, FALSE); betwn ------- n (1 row) select PLVstr.betwn('Harry and Sally are very happy', -3, -1); betwn ------- ppy (1 row) select PLVstr.betwn('Harry and Sally are very happy', 'a', 'ry'); betwn ------- arry (1 row) select PLVstr.betwn('Harry and Sally are very happy', 'a', 'ry', 1,1,FALSE,FALSE); betwn ------- r (1 row) select PLVstr.betwn('Harry and Sally are very happy', 'a', 'ry', 2,1,TRUE,FALSE); betwn -------------------- and Sally are very (1 row) select PLVstr.betwn('Harry and Sally are very happy', 'a', 'y', 2,1); betwn ----------- and Sally (1 row) select PLVstr.betwn('Harry and Sally are very happy', 'a', 'a', 2, 2); betwn ------------- and Sally a (1 row) select PLVstr.betwn('Harry and Sally are very happy', 'a', 'a', 2, 3, FALSE,FALSE); betwn --------------------- nd Sally are very h (1 row) select plvsubst.string('My name is %s %s.', ARRAY['Pavel','Stěhule']); string --------------------------- My name is Pavel Stěhule. (1 row) select plvsubst.string('My name is % %.', ARRAY['Pavel','Stěhule'], '%'); string --------------------------- My name is Pavel Stěhule. (1 row) select plvsubst.string('My name is %s.', ARRAY['Stěhule']); string --------------------- My name is Stěhule. (1 row) select plvsubst.string('My name is %s %s.', 'Pavel,Stěhule'); string --------------------------- My name is Pavel Stěhule. (1 row) select plvsubst.string('My name is %s %s.', 'Pavel|Stěhule','|'); string --------------------------- My name is Pavel Stěhule. (1 row) select plvsubst.string('My name is %s.', 'Stěhule'); string --------------------- My name is Stěhule. (1 row) select plvsubst.string('My name is %s.', ''); ERROR: too few parameters specified for template string select plvsubst.string('My name is empty.', ''); string ------------------- My name is empty. (1 row) select round(to_date ('22-AUG-03', 'DD-MON-YY'),'YEAR') = to_date ('01-JAN-04', 'DD-MON-YY'); ?column? ---------- t (1 row) select round(to_date ('22-AUG-03', 'DD-MON-YY'),'Q') = to_date ('01-OCT-03', 'DD-MON-YY'); ?column? ---------- t (1 row) select round(to_date ('22-AUG-03', 'DD-MON-YY'),'MONTH') = to_date ('01-SEP-03', 'DD-MON-YY'); ?column? ---------- t (1 row) select round(to_date ('22-AUG-03', 'DD-MON-YY'),'DDD') = to_date ('22-AUG-03', 'DD-MON-YY'); ?column? ---------- t (1 row) select round(to_date ('22-AUG-03', 'DD-MON-YY'),'DAY') = to_date ('24-AUG-03', 'DD-MON-YY'); ?column? ---------- t (1 row) select trunc(to_date('22-AUG-03', 'DD-MON-YY'), 'YEAR') = to_date ('01-JAN-03', 'DD-MON-YY'); ?column? ---------- t (1 row) select trunc(to_date('22-AUG-03', 'DD-MON-YY'), 'Q') = to_date ('01-JUL-03', 'DD-MON-YY'); ?column? ---------- t (1 row) select trunc(to_date('22-AUG-03', 'DD-MON-YY'), 'MONTH') = to_date ('01-AUG-03', 'DD-MON-YY'); ?column? ---------- t (1 row) select trunc(to_date('22-AUG-03', 'DD-MON-YY'), 'DDD') = to_date ('22-AUG-03', 'DD-MON-YY'); ?column? ---------- t (1 row) select trunc(to_date('22-AUG-03', 'DD-MON-YY'), 'DAY') = to_date ('17-AUG-03', 'DD-MON-YY'); ?column? ---------- t (1 row) select trunc(TIMESTAMP WITH TIME ZONE '2004-10-19 10:23:54+02','YEAR') = '2004-01-01 00:00:00-08'; ?column? ---------- t (1 row) select trunc(TIMESTAMP WITH TIME ZONE '2004-10-19 10:23:54+02','Q') = '2004-10-01 00:00:00-07'; ?column? ---------- t (1 row) select trunc(TIMESTAMP WITH TIME ZONE '2004-10-19 10:23:54+02','MONTH') = '2004-10-01 00:00:00-07'; ?column? ---------- t (1 row) select trunc(TIMESTAMP WITH TIME ZONE '2004-10-19 10:23:54+02','DDD') = '2004-10-19 00:00:00-07'; ?column? ---------- t (1 row) select trunc(TIMESTAMP WITH TIME ZONE '2004-10-19 10:23:54+02','DAY') = '2004-10-17 00:00:00-07'; ?column? ---------- t (1 row) select trunc(TIMESTAMP WITH TIME ZONE '2004-10-19 10:23:54+02','HH') = '2004-10-19 01:00:00-07'; ?column? ---------- t (1 row) select trunc(TIMESTAMP WITH TIME ZONE '2004-10-19 10:23:54+02','MI') = '2004-10-19 01:23:00-07'; ?column? ---------- t (1 row) select next_day(to_date('01-Aug-03', 'DD-MON-YY'), 'TUESDAY') = to_date ('05-Aug-03', 'DD-MON-YY'); ?column? ---------- t (1 row) select next_day(to_date('06-Aug-03', 'DD-MON-YY'), 'WEDNESDAY') = to_date ('13-Aug-03', 'DD-MON-YY'); ?column? ---------- t (1 row) select next_day(to_date('06-Aug-03', 'DD-MON-YY'), 'SUNDAY') = to_date ('10-Aug-03', 'DD-MON-YY'); ?column? ---------- t (1 row) SET search_path TO oracle,"$user", public, pg_catalog; select next_day(to_date('01-Aug-03 101111', 'DD-MON-YY h24miss'), 'TUESDAY') = to_date ('05-Aug-03 101111', 'DD-MON-YY h24miss'); ?column? ---------- t (1 row) select next_day(to_date('06-Aug-03 10:12:13', 'DD-MON-YY H24:MI:SS'), 'WEDNESDAY') = to_date ('13-Aug-03 10:12:13', 'DD-MON-YY H24:MI:SS'); ?column? ---------- t (1 row) select next_day(to_date('06-Aug-03 11:11:11', 'DD-MON-YY HH:MI:SS'), 'SUNDAY') = to_date ('10-Aug-03 11:11:11', 'DD-MON-YY HH:MI:SS'); ?column? ---------- t (1 row) SET search_path TO default; select instr('Tech on the net', 'e') =2; ?column? ---------- t (1 row) select instr('Tech on the net', 'e', 1, 1) = 2; ?column? ---------- t (1 row) select instr('Tech on the net', 'e', 1, 2) = 11; ?column? ---------- t (1 row) select instr('Tech on the net', 'e', 1, 3) = 14; ?column? ---------- t (1 row) select instr('Tech on the net', 'e', -3, 2) = 2; ?column? ---------- t (1 row) select instr('abc', NULL) IS NULL; ?column? ---------- t (1 row) select 1 = instr('abc', ''); ?column? ---------- t (1 row) select 1 = instr('abc', 'a'); ?column? ---------- t (1 row) select 3 = instr('abc', 'c'); ?column? ---------- t (1 row) select 0 = instr('abc', 'z'); ?column? ---------- t (1 row) select 1 = instr('abcabcabc', 'abca', 1); ?column? ---------- t (1 row) select 4 = instr('abcabcabc', 'abca', 2); ?column? ---------- t (1 row) select 0 = instr('abcabcabc', 'abca', 7); ?column? ---------- t (1 row) select 0 = instr('abcabcabc', 'abca', 9); ?column? ---------- t (1 row) select 4 = instr('abcabcabc', 'abca', -1); ?column? ---------- t (1 row) select 1 = instr('abcabcabc', 'abca', -8); ?column? ---------- t (1 row) select 1 = instr('abcabcabc', 'abca', -9); ?column? ---------- t (1 row) select 0 = instr('abcabcabc', 'abca', -10); ?column? ---------- t (1 row) select 1 = instr('abcabcabc', 'abca', 1, 1); ?column? ---------- t (1 row) select 4 = instr('abcabcabc', 'abca', 1, 2); ?column? ---------- t (1 row) select 0 = instr('abcabcabc', 'abca', 1, 3); ?column? ---------- t (1 row) select oracle.substr('This is a test', 6, 2) = 'is'; ?column? ---------- t (1 row) select oracle.substr('This is a test', 6) = 'is a test'; ?column? ---------- t (1 row) select oracle.substr('TechOnTheNet', 1, 4) = 'Tech'; ?column? ---------- t (1 row) select oracle.substr('TechOnTheNet', -3, 3) = 'Net'; ?column? ---------- t (1 row) select oracle.substr('TechOnTheNet', -6, 3) = 'The'; ?column? ---------- t (1 row) select oracle.substr('TechOnTheNet', -8, 2) = 'On'; ?column? ---------- t (1 row) select oracle.substr('TechOnTheNet', -8, 0) = ''; ?column? ---------- t (1 row) select oracle.substr('TechOnTheNet', -8, -1) = ''; ?column? ---------- (1 row) select oracle.substr(1234567,3.6::smallint)='4567'; ?column? ---------- t (1 row) select oracle.substr(1234567,3.6::int)='4567'; ?column? ---------- t (1 row) select oracle.substr(1234567,3.6::bigint)='4567'; ?column? ---------- t (1 row) select oracle.substr(1234567,3.6::numeric)='34567'; ?column? ---------- t (1 row) select oracle.substr(1234567,-1)='7'; ?column? ---------- t (1 row) select oracle.substr(1234567,3.6::smallint,2.6)='45'; ?column? ---------- t (1 row) select oracle.substr(1234567,3.6::smallint,2.6::smallint)='456'; ?column? ---------- t (1 row) select oracle.substr(1234567,3.6::smallint,2.6::int)='456'; ?column? ---------- t (1 row) select oracle.substr(1234567,3.6::smallint,2.6::bigint)='456'; ?column? ---------- t (1 row) select oracle.substr(1234567,3.6::smallint,2.6::numeric)='45'; ?column? ---------- t (1 row) select oracle.substr(1234567,3.6::int,2.6::smallint)='456'; ?column? ---------- t (1 row) select oracle.substr(1234567,3.6::int,2.6::int)='456'; ?column? ---------- t (1 row) select oracle.substr(1234567,3.6::int,2.6::bigint)='456'; ?column? ---------- t (1 row) select oracle.substr(1234567,3.6::int,2.6::numeric)='45'; ?column? ---------- t (1 row) select oracle.substr(1234567,3.6::bigint,2.6::smallint)='456'; ?column? ---------- t (1 row) select oracle.substr(1234567,3.6::bigint,2.6::int)='456'; ?column? ---------- t (1 row) select oracle.substr(1234567,3.6::bigint,2.6::bigint)='456'; ?column? ---------- t (1 row) select oracle.substr(1234567,3.6::bigint,2.6::numeric)='45'; ?column? ---------- t (1 row) select oracle.substr(1234567,3.6::numeric,2.6::smallint)='345'; ?column? ---------- t (1 row) select oracle.substr(1234567,3.6::numeric,2.6::int)='345'; ?column? ---------- t (1 row) select oracle.substr(1234567,3.6::numeric,2.6::bigint)='345'; ?column? ---------- t (1 row) select oracle.substr(1234567,3.6::numeric,2.6::numeric)='34'; ?column? ---------- t (1 row) select oracle.substr('abcdef'::varchar,3.6::smallint)='def'; ?column? ---------- t (1 row) select oracle.substr('abcdef'::varchar,3.6::int)='def'; ?column? ---------- t (1 row) select oracle.substr('abcdef'::varchar,3.6::bigint)='def'; ?column? ---------- t (1 row) select oracle.substr('abcdef'::varchar,3.6::numeric)='cdef'; ?column? ---------- t (1 row) select oracle.substr('abcdef'::varchar,3.5::int,3.5::int)='def'; ?column? ---------- t (1 row) select oracle.substr('abcdef'::varchar,3.5::numeric,3.5::numeric)='cde'; ?column? ---------- t (1 row) select oracle.substr('abcdef'::varchar,3.5::numeric,3.5::int)='cdef'; ?column? ---------- t (1 row) select concat('Tech on', ' the Net') = 'Tech on the Net'; ?column? ---------- t (1 row) select concat('a', 'b') = 'ab'; ?column? ---------- t (1 row) select concat('a', NULL) = 'a'; ?column? ---------- t (1 row) select concat(NULL, 'b') = 'b'; ?column? ---------- t (1 row) select concat('a', 2) = 'a2'; ?column? ---------- t (1 row) select concat(1, 'b') = '1b'; ?column? ---------- t (1 row) select concat(1, 2) = '12'; ?column? ---------- t (1 row) select concat(1, NULL) = '1'; ?column? ---------- t (1 row) select concat(NULL, 2) = '2'; ?column? ---------- t (1 row) select nvl('A'::text, 'B'); nvl ----- A (1 row) select nvl(NULL::text, 'B'); nvl ----- B (1 row) select nvl(NULL::text, NULL); nvl ----- (1 row) select nvl(1, 2); nvl ----- 1 (1 row) select nvl(NULL, 2); nvl ----- 2 (1 row) select nvl2('A'::text, 'B', 'C'); nvl2 ------ B (1 row) select nvl2(NULL::text, 'B', 'C'); nvl2 ------ C (1 row) select nvl2('A'::text, NULL, 'C'); nvl2 ------ (1 row) select nvl2(NULL::text, 'B', NULL); nvl2 ------ (1 row) select nvl2(1, 2, 3); nvl2 ------ 2 (1 row) select nvl2(NULL, 2, 3); nvl2 ------ 3 (1 row) select lnnvl(true); lnnvl ------- f (1 row) select lnnvl(false); lnnvl ------- t (1 row) select lnnvl(NULL); lnnvl ------- t (1 row) select decode(1, 1, 100, 2, 200); decode -------- 100 (1 row) select decode(2, 1, 100, 2, 200); decode -------- 200 (1 row) select decode(3, 1, 100, 2, 200); decode -------- (1 row) select decode(3, 1, 100, 2, 200, 300); decode -------- 300 (1 row) select decode(NULL, 1, 100, NULL, 200, 300); decode -------- 200 (1 row) select decode('1'::text, '1', 100, '2', 200); decode -------- 100 (1 row) select decode(2, 1, 'ABC', 2, 'DEF'); decode -------- DEF (1 row) select decode('2009-02-05'::date, '2009-02-05', 'ok'); decode -------- ok (1 row) select decode('2009-02-05 01:02:03'::timestamp, '2009-02-05 01:02:03', 'ok'); decode -------- ok (1 row) -- For type 'bpchar' select decode('a'::bpchar, 'a'::bpchar,'postgres'::bpchar); decode ---------- postgres (1 row) select decode('c'::bpchar, 'a'::bpchar,'postgres'::bpchar); decode -------- (1 row) select decode('a'::bpchar, 'a'::bpchar,'postgres'::bpchar,'default value'::bpchar); decode ---------- postgres (1 row) select decode('c', 'a'::bpchar,'postgres'::bpchar,'default value'::bpchar); decode --------------- default value (1 row) select decode('a'::bpchar, 'a'::bpchar,'postgres'::bpchar,'b'::bpchar,'database'::bpchar); decode ---------- postgres (1 row) select decode('d'::bpchar, 'a'::bpchar,'postgres'::bpchar,'b'::bpchar,'database'::bpchar); decode -------- (1 row) select decode('a'::bpchar, 'a'::bpchar,'postgres'::bpchar,'b'::bpchar,'database'::bpchar,'default value'::bpchar); decode ---------- postgres (1 row) select decode('d'::bpchar, 'a'::bpchar,'postgres'::bpchar,'b'::bpchar,'database'::bpchar,'default value'::bpchar); decode --------------- default value (1 row) select decode('a'::bpchar, 'a'::bpchar,'postgres'::bpchar,'b'::bpchar,'database'::bpchar, 'c'::bpchar, 'system'::bpchar); decode ---------- postgres (1 row) select decode('d'::bpchar, 'a'::bpchar,'postgres'::bpchar,'b'::bpchar,'database'::bpchar, 'c'::bpchar, 'system'::bpchar); decode -------- (1 row) select decode('a'::bpchar, 'a'::bpchar,'postgres'::bpchar,'b'::bpchar,'database'::bpchar, 'c'::bpchar, 'system'::bpchar,'default value'::bpchar); decode ---------- postgres (1 row) select decode('d'::bpchar, 'a'::bpchar,'postgres'::bpchar,'b'::bpchar,'database'::bpchar, 'c'::bpchar, 'system'::bpchar,'default value'::bpchar); decode --------------- default value (1 row) select decode(NULL, 'a'::bpchar, 'postgres'::bpchar, NULL,'database'::bpchar); decode ---------- database (1 row) select decode(NULL, 'a'::bpchar, 'postgres'::bpchar, 'b'::bpchar,'database'::bpchar); decode -------- (1 row) select decode(NULL, 'a'::bpchar, 'postgres'::bpchar, NULL,'database'::bpchar,'default value'::bpchar); decode ---------- database (1 row) select decode(NULL, 'a'::bpchar, 'postgres'::bpchar, 'b'::bpchar,'database'::bpchar,'default value'::bpchar); decode --------------- default value (1 row) -- For type 'bigint' select decode(2147483651::bigint, 2147483650::bigint,2147483650::bigint); decode -------- (1 row) select decode(2147483653::bigint, 2147483651::bigint,2147483650::bigint); decode -------- (1 row) select decode(2147483653::bigint, 2147483651::bigint,2147483650::bigint,9999999999::bigint); decode ------------ 9999999999 (1 row) select decode(2147483653::bigint, 2147483651::bigint,2147483650::bigint,9999999999::bigint); decode ------------ 9999999999 (1 row) select decode(2147483651::bigint, 2147483651::bigint,2147483650::bigint,2147483652::bigint,2147483651::bigint); decode ------------ 2147483650 (1 row) select decode(2147483654::bigint, 2147483651::bigint,2147483650::bigint,2147483652::bigint,2147483651::bigint); decode -------- (1 row) select decode(2147483651::bigint, 2147483651::bigint,2147483650::bigint,2147483652::bigint,2147483651::bigint,9999999999::bigint); decode ------------ 2147483650 (1 row) select decode(2147483654::bigint, 2147483651::bigint,2147483650::bigint,2147483652::bigint,2147483651::bigint,9999999999::bigint); decode ------------ 9999999999 (1 row) select decode(2147483651::bigint, 2147483651::bigint,2147483650::bigint, 2147483652::bigint,2147483651::bigint, 2147483653::bigint, 2147483652::bigint); decode ------------ 2147483650 (1 row) select decode(2147483654::bigint, 2147483651::bigint,2147483650::bigint, 2147483652::bigint,2147483651::bigint, 2147483653::bigint, 2147483652::bigint); decode -------- (1 row) select decode(2147483651::bigint, 2147483651::bigint,2147483650::bigint, 2147483652::bigint,2147483651::bigint, 2147483653::bigint, 2147483652::bigint,9999999999::bigint); decode ------------ 2147483650 (1 row) select decode(2147483654::bigint, 2147483651::bigint,2147483650::bigint, 2147483652::bigint,2147483651::bigint, 2147483653::bigint, 2147483652::bigint,9999999999::bigint); decode ------------ 9999999999 (1 row) select decode(NULL, 2147483651::bigint, 2147483650::bigint, NULL,2147483651::bigint); decode ------------ 2147483651 (1 row) select decode(NULL, 2147483651::bigint, 2147483650::bigint, 2147483652::bigint,2147483651::bigint); decode -------- (1 row) select decode(NULL, 2147483651::bigint, 2147483650::bigint, NULL,2147483651::bigint,9999999999::bigint); decode ------------ 2147483651 (1 row) select decode(NULL, 2147483651::bigint, 2147483650::bigint, 2147483652::bigint,2147483651::bigint,9999999999::bigint); decode ------------ 9999999999 (1 row) -- For type 'numeric' select decode(12.001::numeric(5,3), 12.001::numeric(5,3),214748.3650::numeric(10,4)); decode ------------- 214748.3650 (1 row) select decode(12.003::numeric(5,3), 12.001::numeric(5,3),214748.3650::numeric(10,4)); decode -------- (1 row) select decode(12.001::numeric(5,3), 12.001::numeric(5,3),214748.3650::numeric(10,4),999999.9999::numeric(10,4)); decode ------------- 214748.3650 (1 row) select decode(12.003::numeric(5,3), 12.001::numeric(5,3),214748.3650::numeric(10,4),999999.9999::numeric(10,4)); decode ------------- 999999.9999 (1 row) select decode(12.001::numeric(5,3), 12.001::numeric(5,3),214748.3650::numeric(10,4),12.002::numeric(5,3),214748.3651::numeric(10,4)); decode ------------- 214748.3650 (1 row) select decode(12.004::numeric(5,3), 12.001::numeric(5,3),214748.3650::numeric(10,4),12.002::numeric(5,3),214748.3651::numeric(10,4)); decode -------- (1 row) select decode(12.001::numeric(5,3), 12.001::numeric(5,3),214748.3650::numeric(10,4),12.002::numeric(5,3),214748.3651::numeric(10,4),999999.9999::numeric(10,4)); decode ------------- 214748.3650 (1 row) select decode(12.004::numeric(5,3), 12.001::numeric(5,3),214748.3650::numeric(10,4),12.002::numeric(5,3),214748.3651::numeric(10,4),999999.9999::numeric(10,4)); decode ------------- 999999.9999 (1 row) select decode(12.001::numeric(5,3), 12.001::numeric(5,3),214748.3650::numeric(10,4),12.002::numeric(5,3),214748.3651::numeric(10,4), 12.003::numeric(5,3), 214748.3652::numeric(10,4)); decode ------------- 214748.3650 (1 row) select decode(12.004::numeric(5,3), 12.001::numeric(5,3),214748.3650::numeric(10,4),12.002::numeric(5,3),214748.3651::numeric(10,4), 12.003::numeric(5,3), 214748.3652::numeric(10,4)); decode -------- (1 row) select decode(12.001::numeric(5,3), 12.001::numeric(5,3),214748.3650::numeric(10,4),12.002::numeric(5,3),214748.3651::numeric(10,4), 12.003::numeric(5,3), 214748.3652::numeric(10,4),999999.9999::numeric(10,4)); decode ------------- 214748.3650 (1 row) select decode(12.004::numeric(5,3), 12.001::numeric(5,3),214748.3650::numeric(10,4),12.002::numeric(5,3),214748.3651::numeric(10,4), 12.003::numeric(5,3), 214748.3652::numeric(10,4),999999.9999::numeric(10,4)); decode ------------- 999999.9999 (1 row) select decode(NULL, 12.001::numeric(5,3), 214748.3650::numeric(10,4), NULL,214748.3651::numeric(10,4)); decode ------------- 214748.3651 (1 row) select decode(NULL, 12.001::numeric(5,3), 214748.3650::numeric(10,4), 12.002::numeric(5,3),214748.3651::numeric(10,4)); decode -------- (1 row) select decode(NULL, 12.001::numeric(5,3), 214748.3650::numeric(10,4), NULL,214748.3651::numeric(10,4),999999.9999::numeric(10,4)); decode ------------- 214748.3651 (1 row) select decode(NULL, 12.001::numeric(5,3), 214748.3650::numeric(10,4), 12.002::numeric(5,3),214748.3651::numeric(10,4),999999.9999::numeric(10,4)); decode ------------- 999999.9999 (1 row) --For type 'date' select decode('2020-01-01'::date, '2020-01-01'::date,'2012-12-20'::date); decode ------------ 2012-12-20 (1 row) select decode('2020-01-03'::date, '2020-01-01'::date,'2012-12-20'::date); decode -------- (1 row) select decode('2020-01-01'::date, '2020-01-01'::date,'2012-12-20'::date,'2012-12-21'::date); decode ------------ 2012-12-20 (1 row) select decode('2020-01-03'::date, '2020-01-01'::date,'2012-12-20'::date,'2012-12-21'::date); decode ------------ 2012-12-21 (1 row) select decode('2020-01-01'::date, '2020-01-01'::date,'2012-12-20'::date,'2020-01-02'::date,'2012-12-21'::date); decode ------------ 2012-12-20 (1 row) select decode('2020-01-04'::date, '2020-01-01'::date,'2012-12-20'::date,'2020-01-02'::date,'2012-12-21'::date); decode -------- (1 row) select decode('2020-01-01'::date, '2020-01-01'::date,'2012-12-20'::date,'2020-01-02'::date,'2012-12-21'::date,'2012-12-31'::date); decode ------------ 2012-12-20 (1 row) select decode('2020-01-04'::date, '2020-01-01'::date,'2012-12-20'::date,'2020-01-02'::date,'2012-12-21'::date,'2012-12-31'::date); decode ------------ 2012-12-31 (1 row) select decode('2020-01-01'::date, '2020-01-01'::date,'2012-12-20'::date,'2020-01-02'::date,'2012-12-21'::date, '2020-01-03'::date, '2012-12-31'::date); decode ------------ 2012-12-20 (1 row) select decode('2020-01-04'::date, '2020-01-01'::date,'2012-12-20'::date,'2020-01-02'::date,'2012-12-21'::date, '2020-01-03'::date, '2012-12-31'::date); decode -------- (1 row) select decode('2020-01-01'::date, '2020-01-01'::date,'2012-12-20'::date,'2020-01-02'::date,'2012-12-21'::date, '2020-01-03'::date, '2012-12-31'::date,'2013-01-01'::date); decode ------------ 2012-12-20 (1 row) select decode('2020-01-04'::date, '2020-01-01'::date,'2012-12-20'::date,'2020-01-02'::date,'2012-12-21'::date, '2020-01-03'::date, '2012-12-31'::date,'2013-01-01'::date); decode ------------ 2013-01-01 (1 row) select decode(NULL, '2020-01-01'::date, '2012-12-20'::date, NULL,'2012-12-21'::date); decode ------------ 2012-12-21 (1 row) select decode(NULL, '2020-01-01'::date, '2012-12-20'::date, '2020-01-02'::date,'2012-12-21'::date); decode -------- (1 row) select decode(NULL, '2020-01-01'::date, '2012-12-20'::date, NULL,'2012-12-21'::date,'2012-12-31'::date); decode ------------ 2012-12-21 (1 row) select decode(NULL, '2020-01-01'::date, '2012-12-20'::date, '2020-01-02'::date,'2012-12-21'::date,'2012-12-31'::date); decode ------------ 2012-12-31 (1 row) -- For type 'time' select decode('01:00:01'::time, '01:00:01'::time,'09:00:00'::time); decode ---------- 09:00:00 (1 row) select decode('01:00:03'::time, '01:00:01'::time,'09:00:00'::time); decode -------- (1 row) select decode('01:00:01'::time, '01:00:01'::time,'09:00:00'::time,'00:00:00'::time); decode ---------- 09:00:00 (1 row) select decode('01:00:03'::time, '01:00:01'::time,'09:00:00'::time,'00:00:00'::time); decode ---------- 00:00:00 (1 row) select decode('01:00:01'::time, '01:00:01'::time,'09:00:00'::time,'01:00:02'::time,'12:00:00'::time); decode ---------- 09:00:00 (1 row) select decode('01:00:04'::time, '01:00:01'::time,'09:00:00'::time,'01:00:02'::time,'12:00:00'::time); decode -------- (1 row) select decode('01:00:01'::time, '01:00:01'::time,'09:00:00'::time,'01:00:02'::time,'12:00:00'::time,'00:00:00'::time); decode ---------- 09:00:00 (1 row) select decode('01:00:04'::time, '01:00:01'::time,'09:00:00'::time,'01:00:01'::time,'12:00:00'::time,'00:00:00'::time); decode ---------- 00:00:00 (1 row) select decode('01:00:01'::time, '01:00:01'::time,'09:00:00'::time,'01:00:02'::time,'12:00:00'::time, '01:00:03'::time, '15:00:00'::time); decode ---------- 09:00:00 (1 row) select decode('01:00:04'::time, '01:00:01'::time,'09:00:00'::time,'01:00:02'::time,'12:00:00'::time, '01:00:03'::time, '15:00:00'::time); decode -------- (1 row) select decode('01:00:01'::time, '01:00:01'::time,'09:00:00'::time,'01:00:02'::time,'12:00:00'::time, '01:00:03'::time, '15:00:00'::time,'00:00:00'::time); decode ---------- 09:00:00 (1 row) select decode('01:00:04'::time, '01:00:01'::time,'09:00:00'::time,'01:00:02'::time,'12:00:00'::time, '01:00:03'::time, '15:00:00'::time,'00:00:00'::time); decode ---------- 00:00:00 (1 row) select decode(NULL, '01:00:01'::time, '09:00:00'::time, NULL,'12:00:00'::time); decode ---------- 12:00:00 (1 row) select decode(NULL, '01:00:01'::time, '09:00:00'::time, '01:00:02'::time,'12:00:00'::time); decode -------- (1 row) select decode(NULL, '01:00:01'::time, '09:00:00'::time, NULL,'12:00:00'::time,'00:00:00'::time); decode ---------- 12:00:00 (1 row) select decode(NULL, '01:00:01'::time, '09:00:00'::time, '01:00:02'::time,'12:00:00'::time,'00:00:00'::time); decode ---------- 00:00:00 (1 row) -- For type 'timestamp' select decode('2020-01-01 01:00:01'::timestamp, '2020-01-01 01:00:01'::timestamp,'2012-12-20 09:00:00'::timestamp); decode --------------------- 2012-12-20 09:00:00 (1 row) select decode('2020-01-03 01:00:01'::timestamp, '2020-01-01 01:00:01'::timestamp,'2012-12-20 09:00:00'::timestamp); decode -------- (1 row) select decode('2020-01-01 01:00:01'::timestamp, '2020-01-01 01:00:01'::timestamp,'2012-12-20 09:00:00'::timestamp,'2012-12-20 00:00:00'::timestamp); decode --------------------- 2012-12-20 09:00:00 (1 row) select decode('2020-01-03 01:00:01'::timestamp, '2020-01-01 01:00:01'::timestamp,'2012-12-20 09:00:00'::timestamp,'2012-12-20 00:00:00'::timestamp); decode --------------------- 2012-12-20 00:00:00 (1 row) select decode('2020-01-01 01:00:01'::timestamp, '2020-01-01 01:00:01'::timestamp,'2012-12-20 09:00:00'::timestamp,'2020-01-02 01:00:01'::timestamp,'2012-12-20 12:00:00'::timestamp); decode --------------------- 2012-12-20 09:00:00 (1 row) select decode('2020-01-04 01:00:01'::timestamp, '2020-01-01 01:00:01'::timestamp,'2012-12-20 09:00:00'::timestamp,'2020-01-02 01:00:01'::timestamp,'2012-12-20 12:00:00'::timestamp); decode -------- (1 row) select decode('2020-01-01 01:00:01'::timestamp, '2020-01-01 01:00:01'::timestamp,'2012-12-20 09:00:00'::timestamp,'2020-01-02 01:00:01'::timestamp,'2012-12-20 12:00:00'::timestamp,'2012-12-20 00:00:00'::timestamp); decode --------------------- 2012-12-20 09:00:00 (1 row) select decode('2020-01-04 01:00:01'::timestamp, '2020-01-01 01:00:01'::timestamp,'2012-12-20 09:00:00'::timestamp,'2020-01-02 01:00:01'::timestamp,'2012-12-20 12:00:00'::timestamp,'2012-12-20 00:00:00'::timestamp); decode --------------------- 2012-12-20 00:00:00 (1 row) select decode('2020-01-01 01:00:01'::timestamp, '2020-01-01 01:00:01'::timestamp,'2012-12-20 09:00:00'::timestamp,'2020-01-02 01:00:01'::timestamp,'2012-12-20 12:00:00'::timestamp, '2020-01-03 01:00:01'::timestamp, '2012-12-20 15:00:00'::timestamp); decode --------------------- 2012-12-20 09:00:00 (1 row) select decode('2020-01-04 01:00:01'::timestamp, '2020-01-01 01:00:01'::timestamp,'2012-12-20 09:00:00'::timestamp,'2020-01-02 01:00:01'::timestamp,'2012-12-20 12:00:00'::timestamp, '2020-01-03 01:00:01'::timestamp, '2012-12-20 15:00:00'::timestamp); decode -------- (1 row) select decode('2020-01-01 01:00:01'::timestamp, '2020-01-01 01:00:01'::timestamp,'2012-12-20 09:00:00'::timestamp,'2020-01-02 01:00:01'::timestamp,'2012-12-20 12:00:00'::timestamp, '2020-01-03 01:00:01'::timestamp, '2012-12-20 15:00:00'::timestamp,'2012-12-20 00:00:00'::timestamp); decode --------------------- 2012-12-20 09:00:00 (1 row) select decode('2020-01-04 01:00:01'::timestamp, '2020-01-01 01:00:01'::timestamp,'2012-12-20 09:00:00'::timestamp,'2020-01-02 01:00:01'::timestamp,'2012-12-20 12:00:00'::timestamp, '2020-01-03 01:00:01'::timestamp, '2012-12-20 15:00:00'::timestamp,'2012-12-20 00:00:00'::timestamp); decode --------------------- 2012-12-20 00:00:00 (1 row) select decode(NULL, '2020-01-01 01:00:01'::timestamp, '2012-12-20 09:00:00'::timestamp, NULL,'2012-12-20 12:00:00'::timestamp); decode --------------------- 2012-12-20 12:00:00 (1 row) select decode(NULL, '2020-01-01 01:00:01'::timestamp, '2012-12-20 09:00:00'::timestamp, '2020-01-02 01:00:01'::timestamp,'2012-12-20 12:00:00'::timestamp); decode -------- (1 row) select decode(NULL, '2020-01-01 01:00:01'::timestamp, '2012-12-20 09:00:00'::timestamp, NULL,'2012-12-20 12:00:00'::timestamp,'2012-12-20 00:00:00'::timestamp); decode --------------------- 2012-12-20 12:00:00 (1 row) select decode(NULL, '2020-01-01 01:00:01'::timestamp, '2012-12-20 09:00:00'::timestamp, '2020-01-02 01:00:01'::timestamp,'2012-12-20 12:00:00'::timestamp,'2012-12-20 00:00:00'::timestamp); decode --------------------- 2012-12-20 00:00:00 (1 row) -- For type 'timestamptz' select decode('2020-01-01 01:00:01-08'::timestamptz, '2020-01-01 01:00:01-08'::timestamptz,'2012-12-20 09:00:00-08'::timestamptz); decode ------------------------ 2012-12-20 09:00:00-08 (1 row) select decode('2020-01-03 01:00:01-08'::timestamptz, '2020-01-01 01:00:01-08'::timestamptz,'2012-12-20 09:00:00-08'::timestamptz); decode -------- (1 row) select decode('2020-01-01 01:00:01-08'::timestamptz, '2020-01-01 01:00:01-08'::timestamptz,'2012-12-20 09:00:00-08'::timestamptz,'2012-12-20 00:00:00-08'::timestamptz); decode ------------------------ 2012-12-20 09:00:00-08 (1 row) select decode('2020-01-03 01:00:01-08'::timestamptz, '2020-01-01 01:00:01-08'::timestamptz,'2012-12-20 09:00:00-08'::timestamptz,'2012-12-20 00:00:00-08'::timestamptz); decode ------------------------ 2012-12-20 00:00:00-08 (1 row) select decode('2020-01-01 01:00:01-08'::timestamptz, '2020-01-01 01:00:01-08'::timestamptz,'2012-12-20 09:00:00-08'::timestamptz,'2020-01-02 01:00:01-08'::timestamptz,'2012-12-20 12:00:00-08'::timestamptz); decode ------------------------ 2012-12-20 09:00:00-08 (1 row) select decode('2020-01-04 01:00:01-08'::timestamptz, '2020-01-01 01:00:01-08'::timestamptz,'2012-12-20 09:00:00-08'::timestamptz,'2020-01-02 01:00:01-08'::timestamptz,'2012-12-20 12:00:00-08'::timestamptz); decode -------- (1 row) select decode('2020-01-01 01:00:01-08'::timestamptz, '2020-01-01 01:00:01-08'::timestamptz,'2012-12-20 09:00:00-08'::timestamptz,'2020-01-02 01:00:01-08'::timestamptz,'2012-12-20 12:00:00-08'::timestamptz,'2012-12-20 00:00:00-08'::timestamptz); decode ------------------------ 2012-12-20 09:00:00-08 (1 row) select decode('2020-01-04 01:00:01-08'::timestamptz, '2020-01-01 01:00:01-08'::timestamptz,'2012-12-20 09:00:00-08'::timestamptz,'2020-01-02 01:00:01-08'::timestamptz,'2012-12-20 12:00:00-08'::timestamptz,'2012-12-20 00:00:00-08'::timestamptz); decode ------------------------ 2012-12-20 00:00:00-08 (1 row) select decode('2020-01-01 01:00:01-08'::timestamptz, '2020-01-01 01:00:01-08'::timestamptz,'2012-12-20 09:00:00-08'::timestamptz,'2020-01-02 01:00:01-08'::timestamptz,'2012-12-20 12:00:00-08'::timestamptz, '2020-01-03 01:00:01-08'::timestamptz, '2012-12-20 15:00:00-08'::timestamptz); decode ------------------------ 2012-12-20 09:00:00-08 (1 row) select decode('2020-01-04 01:00:01-08'::timestamptz, '2020-01-01 01:00:01-08'::timestamptz,'2012-12-20 09:00:00-08'::timestamptz,'2020-01-02 01:00:01-08'::timestamptz,'2012-12-20 12:00:00-08'::timestamptz, '2020-01-03 01:00:01-08'::timestamptz, '2012-12-20 15:00:00-08'::timestamptz); decode -------- (1 row) select decode('2020-01-01 01:00:01-08'::timestamptz, '2020-01-01 01:00:01-08'::timestamptz,'2012-12-20 09:00:00-08'::timestamptz,'2020-01-02 01:00:01-08'::timestamptz,'2012-12-20 12:00:00-08'::timestamptz, '2020-01-03 01:00:01-08'::timestamptz, '2012-12-20 15:00:00-08'::timestamptz,'2012-12-20 00:00:00-08'::timestamptz); decode ------------------------ 2012-12-20 09:00:00-08 (1 row) select decode(4, 1,'2012-12-20 09:00:00-08'::timestamptz,2,'2012-12-20 12:00:00-08'::timestamptz, 3, '2012-12-20 15:00:00-08'::timestamptz,'2012-12-20 00:00:00-08'::timestamptz); decode ------------------------ 2012-12-20 00:00:00-08 (1 row) select decode(NULL, '2020-01-01 01:00:01-08'::timestamptz, '2012-12-20 09:00:00-08'::timestamptz, NULL,'2012-12-20 12:00:00-08'::timestamptz); decode ------------------------ 2012-12-20 12:00:00-08 (1 row) select decode(NULL, '2020-01-01 01:00:01-08'::timestamptz, '2012-12-20 09:00:00-08'::timestamptz, '2020-01-02 01:00:01-08'::timestamptz,'2012-12-20 12:00:00-08'::timestamptz); decode -------- (1 row) select decode(NULL, '2020-01-01 01:00:01-08'::timestamptz, '2012-12-20 09:00:00-08'::timestamptz, NULL,'2012-12-20 12:00:00-08'::timestamptz,'2012-12-20 00:00:00-08'::timestamptz); decode ------------------------ 2012-12-20 12:00:00-08 (1 row) select decode(NULL, '2020-01-01 01:00:01-08'::timestamptz, '2012-12-20 09:00:00-08'::timestamptz, '2020-01-02 01:00:01-08'::timestamptz,'2012-12-20 12:00:00-08'::timestamptz,'2012-12-20 00:00:00-08'::timestamptz); decode ------------------------ 2012-12-20 00:00:00-08 (1 row) --Test case to check if decode accepts other expressions as a key CREATE OR REPLACE FUNCTION five() RETURNS integer AS $$ BEGIN RETURN 5; END; $$ LANGUAGE plpgsql; select decode(five(), 1, 'one', 2, 'two', 5, 'five'); decode -------- five (1 row) DROP FUNCTION five(); -- Test case to check duplicate keys in search list select decode(1, 1, 'one', 2, 'two', 1, 'one-again') = 'one'; ?column? ---------- t (1 row) /* Test case to check explicit type casting of keys in search list in * case of ambiguous key (1st argument) provided. */ -- 1) succeed and return 'result-1' select decode('2012-01-01', '2012-01-01'::date,'result-1','2012-01-02', 'result-2'); decode ---------- result-1 (1 row) select decode('2012-01-01', '2012-01-01', 'result-1', '2012-02-01'::date, 'result-2'); decode ---------- result-1 (1 row) select PLVstr.rvrs ('Jumping Jack Flash') ='hsalF kcaJ gnipmuJ'; ?column? ---------- t (1 row) select PLVstr.rvrs ('Jumping Jack Flash', 9) = 'hsalF kcaJ'; ?column? ---------- t (1 row) select PLVstr.rvrs ('Jumping Jack Flash', 4, 6) = 'nip'; ?column? ---------- t (1 row) select PLVstr.rvrs (NULL, 10, 20); rvrs ------ (1 row) select PLVstr.rvrs ('alphabet', -2, -5); rvrs ------ ebah (1 row) select PLVstr.rvrs ('alphabet', -2); rvrs --------- ebahpla (1 row) select PLVstr.rvrs ('alphabet', 2, 200); rvrs --------- tebahpl (1 row) select PLVstr.rvrs ('alphabet', 20, 200); rvrs ------ (1 row) select PLVstr.lstrip ('*val1|val2|val3|*', '*') = 'val1|val2|val3|*'; ?column? ---------- t (1 row) select PLVstr.lstrip (',,,val1,val2,val3,', ',', 3)= 'val1,val2,val3,'; ?column? ---------- t (1 row) select PLVstr.lstrip ('WHERE WHITE = ''FRONT'' AND COMP# = 1500', 'WHERE ') = 'WHITE = ''FRONT'' AND COMP# = 1500'; ?column? ---------- t (1 row) select plvstr.left('Příliš žluťoučký kůň',4) = pg_catalog.substr('Příl', 1, 4); ?column? ---------- t (1 row) select pos,token from plvlex.tokens('select * from a.b.c join d ON x=y', true, true); pos | token -----+-------- 0 | select 7 | * 9 | from 14 | a.b.c 20 | join 25 | d 27 | on 30 | x 31 | = 32 | y (10 rows) SET lc_numeric TO 'C'; select to_char(22); to_char --------- 22 (1 row) select to_char(99::smallint); to_char --------- 99 (1 row) select to_char(-44444); to_char --------- -44444 (1 row) select to_char(1234567890123456::bigint); to_char ------------------ 1234567890123456 (1 row) select to_char(123.456::real); to_char --------- 123.456 (1 row) select to_char(1234.5678::double precision); to_char ----------- 1234.5678 (1 row) select to_char(12345678901234567890::numeric); to_char ---------------------- 12345678901234567890 (1 row) select to_char(1234567890.12345); to_char ------------------ 1234567890.12345 (1 row) select to_char('4.00'::numeric); to_char --------- 4 (1 row) select to_char('4.0010'::numeric); to_char --------- 4.001 (1 row) SELECT to_number('123'::text); to_number ----------- 123 (1 row) SELECT to_number('123.456'::text); to_number ----------- 123.456 (1 row) SELECT to_number(123); to_number ----------- 123 (1 row) SELECT to_number(123::smallint); to_number ----------- 123 (1 row) SELECT to_number(123::int); to_number ----------- 123 (1 row) SELECT to_number(123::bigint); to_number ----------- 123 (1 row) SELECT to_number(123::numeric); to_number ----------- 123 (1 row) SELECT to_number(123.456); to_number ----------- 123.456 (1 row) SELECT to_number(1210.73, 9999.99); to_number ----------- 1210.73 (1 row) SELECT to_number(1210::smallint, 9999::smallint); to_number ----------- 1210 (1 row) SELECT to_number(1210::int, 9999::int); to_number ----------- 1210 (1 row) SELECT to_number(1210::bigint, 9999::bigint); to_number ----------- 1210 (1 row) SELECT to_number(1210.73::numeric, 9999.99::numeric); to_number ----------- 1210.73 (1 row) SELECT to_date('2009-01-02'); to_date --------------------- 2009-01-02 00:00:00 (1 row) SELECT bitand(5,1), bitand(5,2), bitand(5,4); bitand | bitand | bitand --------+--------+-------- 1 | 0 | 4 (1 row) SELECT sinh(1.570796)::numeric(10, 8), cosh(1.570796)::numeric(10, 8), tanh(4)::numeric(10, 8); sinh | cosh | tanh ------------+------------+------------ 2.30129808 | 2.50917773 | 0.99932930 (1 row) SELECT nanvl(12345, 1), nanvl('NaN', 1); nanvl | nanvl -------+------- 12345 | 1 (1 row) SELECT nanvl(12345::float4, 1), nanvl('NaN'::float4, 1); nanvl | nanvl -------+------- 12345 | 1 (1 row) SELECT nanvl(12345::float8, 1), nanvl('NaN'::float8, 1); nanvl | nanvl -------+------- 12345 | 1 (1 row) SELECT nanvl(12345::numeric, 1), nanvl('NaN'::numeric, 1); nanvl | nanvl -------+------- 12345 | 1 (1 row) SELECT nanvl(12345, '1'::varchar), nanvl('NaN', 1::varchar); nanvl | nanvl -------+------- 12345 | 1 (1 row) SELECT nanvl(12345::float4, '1'::varchar), nanvl('NaN'::float4, '1'::varchar); nanvl | nanvl -------+------- 12345 | 1 (1 row) SELECT nanvl(12345::float8, '1'::varchar), nanvl('NaN'::float8, '1'::varchar); nanvl | nanvl -------+------- 12345 | 1 (1 row) SELECT nanvl(12345::numeric, '1'::varchar), nanvl('NaN'::numeric, '1'::varchar); nanvl | nanvl -------+------- 12345 | 1 (1 row) SELECT nanvl(12345, '1'::char), nanvl('NaN', 1::char); nanvl | nanvl -------+------- 12345 | 1 (1 row) SELECT nanvl(12345::float4, '1'::char), nanvl('NaN'::float4, '1'::char); nanvl | nanvl -------+------- 12345 | 1 (1 row) SELECT nanvl(12345::float8, '1'::char), nanvl('NaN'::float8, '1'::char); nanvl | nanvl -------+------- 12345 | 1 (1 row) SELECT nanvl(12345::numeric, '1'::char), nanvl('NaN'::numeric, '1'::char); nanvl | nanvl -------+------- 12345 | 1 (1 row) select dbms_assert.enquote_literal('some text '' some text'); enquote_literal -------------------------- 'some text '' some text' (1 row) select dbms_assert.enquote_name('''"AAA'); enquote_name -------------- "'""aaa" (1 row) select dbms_assert.enquote_name('''"AAA', false); enquote_name -------------- "'""AAA" (1 row) select dbms_assert.noop('some string'); noop ------------- some string (1 row) select dbms_assert.qualified_sql_name('aaa.bbb.ccc."aaaa""aaa"'); qualified_sql_name ------------------------- aaa.bbb.ccc."aaaa""aaa" (1 row) select dbms_assert.qualified_sql_name('aaa.bbb.cc%c."aaaa""aaa"'); ERROR: string is not qualified SQL name select dbms_assert.schema_name('dbms_assert'); schema_name ------------- dbms_assert (1 row) select dbms_assert.schema_name('jabadabado'); ERROR: invalid schema name select dbms_assert.simple_sql_name('"Aaa dghh shsh"'); simple_sql_name ----------------- "Aaa dghh shsh" (1 row) select dbms_assert.simple_sql_name('ajajaj -- ajaj'); ERROR: string is not simple SQL name select dbms_assert.object_name('pg_catalog.pg_class'); object_name --------------------- pg_catalog.pg_class (1 row) select dbms_assert.object_name('dbms_assert.fooo'); ERROR: invalid object name select dbms_assert.enquote_literal(NULL); enquote_literal ----------------- (1 row) select dbms_assert.enquote_name(NULL); enquote_name -------------- (1 row) select dbms_assert.enquote_name(NULL, false); enquote_name -------------- (1 row) select dbms_assert.noop(NULL); noop ------ (1 row) select dbms_assert.qualified_sql_name(NULL); ERROR: string is not qualified SQL name select dbms_assert.qualified_sql_name(NULL); ERROR: string is not qualified SQL name select dbms_assert.schema_name(NULL); ERROR: invalid schema name select dbms_assert.schema_name(NULL); ERROR: invalid schema name select dbms_assert.simple_sql_name(NULL); ERROR: string is not simple SQL name select dbms_assert.simple_sql_name(NULL); ERROR: string is not simple SQL name select dbms_assert.object_name(NULL); ERROR: invalid object name select dbms_assert.object_name(NULL); ERROR: invalid object name select plunit.assert_true(NULL); ERROR: plunit.assert_true exception DETAIL: Plunit.assertation fails (assert_true). select plunit.assert_true(1 = 2); ERROR: plunit.assert_true exception DETAIL: Plunit.assertation fails (assert_true). select plunit.assert_true(1 = 2, 'one is not two'); ERROR: one is not two DETAIL: Plunit.assertation fails (assert_true). select plunit.assert_true(1 = 1); assert_true ------------- (1 row) select plunit.assert_false(1 = 1); ERROR: plunit.assert_false exception DETAIL: Plunit.assertation fails (assert_false). select plunit.assert_false(1 = 1, 'trap is open'); ERROR: trap is open DETAIL: Plunit.assertation fails (assert_false). select plunit.assert_false(NULL); ERROR: plunit.assert_false exception DETAIL: Plunit.assertation fails (assert_false). select plunit.assert_null(current_date); ERROR: plunit.assert_null exception DETAIL: Plunit.assertation fails (assert_null). select plunit.assert_null(NULL::date); assert_null ------------- (1 row) select plunit.assert_not_null(current_date); assert_not_null ----------------- (1 row) select plunit.assert_not_null(NULL::date); ERROR: plunit.assert_not_null exception DETAIL: Plunit.assertation fails (assert_not_null). select plunit.assert_equals('Pavel','Pa'||'vel'); assert_equals --------------- (1 row) select plunit.assert_equals(current_date, current_date + 1, 'diff dates'); ERROR: diff dates DETAIL: Plunit.assertation fails (assert_equals). select plunit.assert_equals(10.2, 10.3, 0.5); assert_equals --------------- (1 row) select plunit.assert_equals(10.2, 10.3, 0.01, 'attention some diff'); ERROR: attention some diff DETAIL: Plunit.assertation fails (assert_equals). select plunit.assert_not_equals(current_date, current_date + 1, 'yestarday is today'); assert_not_equals ------------------- (1 row) select plunit.fail(); ERROR: plunit.assert_fail exception DETAIL: Plunit.assertation (assert_fail). select plunit.fail('custom exception'); ERROR: custom exception DETAIL: Plunit.assertation (assert_fail). SELECT dump('Yellow dog'::text) ~ E'^Typ=25 Len=(\\d+): \\d+(,\\d+)*$' AS t; t --- t (1 row) SELECT dump('Yellow dog'::text, 10) ~ E'^Typ=25 Len=(\\d+): \\d+(,\\d+)*$' AS t; t --- t (1 row) SELECT dump('Yellow dog'::text, 17) ~ E'^Typ=25 Len=(\\d+): .(,.)*$' AS t; t --- t (1 row) SELECT dump(10::int2) ~ E'^Typ=21 Len=2: \\d+(,\\d+){1}$' AS t; t --- t (1 row) SELECT dump(10::int4) ~ E'^Typ=23 Len=4: \\d+(,\\d+){3}$' AS t; t --- t (1 row) SELECT dump(10::int8) ~ E'^Typ=20 Len=8: \\d+(,\\d+){7}$' AS t; t --- t (1 row) SELECT dump(10.23::float4) ~ E'^Typ=700 Len=4: \\d+(,\\d+){3}$' AS t; t --- t (1 row) SELECT dump(10.23::float8) ~ E'^Typ=701 Len=8: \\d+(,\\d+){7}$' AS t; t --- t (1 row) SELECT dump(10.23::numeric) ~ E'^Typ=1700 Len=(\\d+): \\d+(,\\d+)*$' AS t; t --- t (1 row) SELECT dump('2008-10-10'::date) ~ E'^Typ=1082 Len=4: \\d+(,\\d+){3}$' AS t; t --- t (1 row) SELECT dump('2008-10-10'::timestamp) ~ E'^Typ=1114 Len=8: \\d+(,\\d+){7}$' AS t; t --- t (1 row) SELECT dump('2009-10-10'::timestamp) ~ E'^Typ=1114 Len=8: \\d+(,\\d+){7}$' AS t; t --- t (1 row) -- Tests for to_multi_byte SELECT to_multi_byte('123$test'); to_multi_byte ------------------ 123$test (1 row) -- Check internal representation difference SELECT octet_length('abc'); octet_length -------------- 3 (1 row) SELECT octet_length(to_multi_byte('abc')); octet_length -------------- 9 (1 row) -- Tests for to_single_byte SELECT to_single_byte('123$test'); to_single_byte ---------------- 123$test (1 row) SELECT to_single_byte('123$test'); to_single_byte ---------------- 123$test (1 row) -- Check internal representation difference SELECT octet_length('abc'); octet_length -------------- 9 (1 row) SELECT octet_length(to_single_byte('abc')); octet_length -------------- 3 (1 row) -- Tests for round(TIMESTAMP WITH TIME ZONE) select round(TIMESTAMP WITH TIME ZONE'12/08/1990 05:35:25','YEAR') = '1991-01-01 00:00:00'; ?column? ---------- t (1 row) select round(TIMESTAMP WITH TIME ZONE'05/08/1990 05:35:25','Q') = '1990-04-01 00:00:00'; ?column? ---------- t (1 row) select round(TIMESTAMP WITH TIME ZONE'12/08/1990 05:35:25','MONTH') = '1990-12-01 00:00:00'; ?column? ---------- t (1 row) select round(TIMESTAMP WITH TIME ZONE'12/08/1990 05:35:25','DDD') = '1990-12-08 00:00:00'; ?column? ---------- t (1 row) select round(TIMESTAMP WITH TIME ZONE'12/08/1990 05:35:25','DAY') = '1990-12-09 00:00:00'; ?column? ---------- t (1 row) select round(TIMESTAMP WITH TIME ZONE'12/08/1990 05:35:25','hh') = '1990-12-08 06:00:00'; ?column? ---------- t (1 row) select round(TIMESTAMP WITH TIME ZONE'12/08/1990 05:35:25','mi') = '1990-12-08 05:35:00'; ?column? ---------- t (1 row) -- Tests for to_date SET DATESTYLE TO SQL, MDY; SELECT to_date('2009-01-02'); to_date --------------------- 01/02/2009 00:00:00 (1 row) select to_date('January 8,1999'); to_date --------------------- 01/08/1999 00:00:00 (1 row) SET DATESTYLE TO POSTGRES, MDY; select to_date('1999-01-08'); to_date -------------------------- Fri Jan 08 00:00:00 1999 (1 row) select to_date('1/12/1999'); to_date -------------------------- Tue Jan 12 00:00:00 1999 (1 row) SET DATESTYLE TO SQL, DMY; select to_date('01/02/03'); to_date --------------------- 01/02/2003 00:00:00 (1 row) select to_date('1999-Jan-08'); to_date --------------------- 08/01/1999 00:00:00 (1 row) select to_date('Jan-08-1999'); to_date --------------------- 08/01/1999 00:00:00 (1 row) select to_date('08-Jan-1999'); to_date --------------------- 08/01/1999 00:00:00 (1 row) SET DATESTYLE TO ISO, YMD; select to_date('99-Jan-08'); to_date --------------------- 1999-01-08 00:00:00 (1 row) SET DATESTYLE TO ISO, DMY; select to_date('08-Jan-99'); to_date --------------------- 1999-01-08 00:00:00 (1 row) select to_date('Jan-08-99'); to_date --------------------- 1999-01-08 00:00:00 (1 row) select to_date('19990108'); to_date --------------------- 1999-01-08 00:00:00 (1 row) select to_date('990108'); to_date --------------------- 1999-01-08 00:00:00 (1 row) select to_date('J2451187'); to_date --------------------- 1999-01-08 00:00:00 (1 row) set orafce.nls_date_format='YY-MonDD HH24:MI:SS'; select to_date('14-Jan08 11:44:49+05:30'); to_date --------------------- 2014-01-08 11:44:49 (1 row) set orafce.nls_date_format='YY-DDMon HH24:MI:SS'; select to_date('14-08Jan 11:44:49+05:30'); to_date --------------------- 2014-01-08 11:44:49 (1 row) set orafce.nls_date_format='DDMMYYYY HH24:MI:SS'; select to_date('21052014 12:13:44+05:30'); to_date --------------------- 2014-05-21 12:13:44 (1 row) set orafce.nls_date_format='DDMMYY HH24:MI:SS'; select to_date('210514 12:13:44+05:30'); to_date --------------------- 2014-05-21 12:13:44 (1 row) set orafce.nls_date_format='DDMMYY HH24:MI:SS.MS'; select pg_catalog.to_date('210514 12:13:44.55'); to_date ------------------------ 2014-05-21 12:13:44.55 (1 row) select oracle.to_date('210514 12:13:44.55'); to_date --------------------- 2014-05-21 12:13:45 (1 row) -- Tests for oracle.to_date(text,text) SET search_path TO oracle,"$user", public, pg_catalog; select to_date('2014/04/25 10:13', 'YYYY/MM/DD HH:MI'); to_date --------------------- 2014-04-25 10:13:00 (1 row) select to_date('16-Feb-09 10:11:11', 'DD-Mon-YY HH:MI:SS'); to_date --------------------- 2009-02-16 10:11:11 (1 row) select to_date('02/16/09 04:12:12', 'MM/DD/YY HH24:MI:SS'); to_date --------------------- 2009-02-16 04:12:12 (1 row) select to_date('021609 111213', 'MMDDYY HHMISS'); to_date --------------------- 2009-02-16 11:12:13 (1 row) select to_date('16-Feb-09 11:12:12', 'DD-Mon-YY HH:MI:SS'); to_date --------------------- 2009-02-16 11:12:12 (1 row) select to_date('Feb/16/09 11:21:23', 'Mon/DD/YY HH:MI:SS'); to_date --------------------- 2009-02-16 11:21:23 (1 row) select to_date('February.16.2009 10:11:12', 'Month.DD.YYYY HH:MI:SS'); to_date --------------------- 2009-02-16 10:11:12 (1 row) select to_date('20020315111212', 'yyyymmddhh12miss'); to_date --------------------- 2002-03-15 11:12:12 (1 row) select to_date('January 15, 1989, 11:00 A.M.','Month dd, YYYY, HH:MI A.M.'); to_date --------------------- 1989-01-15 11:00:00 (1 row) select to_date('14-Jan08 11:44:49+05:30' ,'YY-MonDD HH24:MI:SS'); to_date --------------------- 2014-01-08 11:44:49 (1 row) select to_date('14-08Jan 11:44:49+05:30','YY-DDMon HH24:MI:SS'); to_date --------------------- 2014-01-08 11:44:49 (1 row) select to_date('21052014 12:13:44+05:30','DDMMYYYY HH24:MI:SS'); to_date --------------------- 2014-05-21 12:13:44 (1 row) select to_date('210514 12:13:44+05:30','DDMMYY HH24:MI:SS'); to_date --------------------- 2014-05-21 12:13:44 (1 row) SET search_path TO default; -- Tests for + operator with DATE and number(smallint,integer,bigint,numeric) SET search_path TO oracle,"$user", public, pg_catalog; SET orafce.nls_date_format='YYYY-MM-DD HH24:MI:SS'; SELECT to_date('2014-07-02 10:08:55') + 9::smallint; ?column? --------------------- 2014-07-11 10:08:55 (1 row) SET orafce.nls_date_format='MM-DD-YYYY HH24:MI:SS'; SELECT to_date('07-02-2014 10:08:55') + 9::smallint; ?column? --------------------- 2014-07-11 10:08:55 (1 row) SET orafce.nls_date_format='DD-MM-YYYY HH24:MI:SS'; SELECT to_date('02-07-2014 10:08:55') + 9::smallint; ?column? --------------------- 2014-07-11 10:08:55 (1 row) SET orafce.nls_date_format='YYYY-MM-DD HH24:MI:SS'; SELECT to_date('2014-07-02 10:08:55') + 9; ?column? --------------------- 2014-07-11 10:08:55 (1 row) SELECT to_date('2014-07-02 10:08:55','YYYY-MM-DD HH:MI:SS') + 9::smallint; ?column? --------------------- 2014-07-11 10:08:55 (1 row) SELECT to_date('02-07-2014 10:08:55','DD-MM-YYYY HH:MI:SS') + 9::smallint; ?column? --------------------- 2014-07-11 10:08:55 (1 row) SELECT to_date('07-02-2014 10:08:55','MM-DD-YYYY HH:MI:SS') + 9::smallint; ?column? --------------------- 2014-07-11 10:08:55 (1 row) SET orafce.nls_date_format='YYYY-MM-DD HH24:MI:SS'; SELECT to_date('2014-07-02 10:08:55') + 9::bigint; ?column? --------------------- 2014-07-11 10:08:55 (1 row) SET orafce.nls_date_format='MM-DD-YYYY HH24:MI:SS'; SELECT to_date('07-02-2014 10:08:55') + 9::bigint; ?column? --------------------- 2014-07-11 10:08:55 (1 row) SET orafce.nls_date_format='DD-MM-YYYY HH24:MI:SS'; SELECT to_date('02-07-2014 10:08:55') + 9::bigint; ?column? --------------------- 2014-07-11 10:08:55 (1 row) SELECT to_date('2014-07-02 10:08:55','YYYY-MM-DD HH:MI:SS') + 9::bigint; ?column? --------------------- 2014-07-11 10:08:55 (1 row) SELECT to_date('02-07-2014 10:08:55','DD-MM-YYYY HH:MI:SS') + 9::bigint; ?column? --------------------- 2014-07-11 10:08:55 (1 row) SELECT to_date('07-02-2014 10:08:55','MM-DD-YYYY HH:MI:SS') + 9::bigint; ?column? --------------------- 2014-07-11 10:08:55 (1 row) SET orafce.nls_date_format='YYYY-MM-DD HH24:MI:SS'; SELECT to_date('2014-07-02 10:08:55') + 9::integer; ?column? --------------------- 2014-07-11 10:08:55 (1 row) SET orafce.nls_date_format='MM-DD-YYYY HH24:MI:SS'; SELECT to_date('07-02-2014 10:08:55') + 9::integer; ?column? --------------------- 2014-07-11 10:08:55 (1 row) SET orafce.nls_date_format='DD-MM-YYYY HH24:MI:SS'; SELECT to_date('02-07-2014 10:08:55') + 9::integer; ?column? --------------------- 2014-07-11 10:08:55 (1 row) SELECT to_date('2014-07-02 10:08:55','YYYY-MM-DD HH:MI:SS') + 9::integer; ?column? --------------------- 2014-07-11 10:08:55 (1 row) SELECT to_date('02-07-2014 10:08:55','DD-MM-YYYY HH:MI:SS') + 9::integer; ?column? --------------------- 2014-07-11 10:08:55 (1 row) SELECT to_date('07-02-2014 10:08:55','MM-DD-YYYY HH:MI:SS') + 9::integer; ?column? --------------------- 2014-07-11 10:08:55 (1 row) SET orafce.nls_date_format='YYYY-MM-DD HH24:MI:SS'; SELECT to_date('2014-07-02 10:08:55') + 9::numeric; ?column? --------------------- 2014-07-11 10:08:55 (1 row) SET orafce.nls_date_format='MM-DD-YYYY HH24:MI:SS'; SELECT to_date('07-02-2014 10:08:55') + 9::numeric; ?column? --------------------- 2014-07-11 10:08:55 (1 row) SET orafce.nls_date_format='DD-MM-YYYY HH24:MI:SS'; SELECT to_date('02-07-2014 10:08:55') + 9::numeric; ?column? --------------------- 2014-07-11 10:08:55 (1 row) SELECT to_date('2014-07-02 10:08:55','YYYY-MM-DD HH:MI:SS') + 9::numeric; ?column? --------------------- 2014-07-11 10:08:55 (1 row) SELECT to_date('02-07-2014 10:08:55','DD-MM-YYYY HH:MI:SS') + 9::numeric; ?column? --------------------- 2014-07-11 10:08:55 (1 row) SELECT to_date('07-02-2014 10:08:55','MM-DD-YYYY HH:MI:SS') + 9::numeric; ?column? --------------------- 2014-07-11 10:08:55 (1 row) SET orafce.nls_date_format='YYYY-MM-DD HH24:MI:SS'; SELECT to_date('2014-01-01 00:00:00') + 1.5; ?column? --------------------- 2014-01-02 12:00:00 (1 row) SELECT to_date('2014-01-01 00:00:00','yyyy-mm-dd hh24:mi:ss') + 1.5; ?column? --------------------- 2014-01-02 12:00:00 (1 row) SET search_path TO default; -- Tests for - operator with DATE and number(smallint,integer,bigint,numeric) SET search_path TO oracle,"$user", public, pg_catalog; SET orafce.nls_date_format='YYYY-MM-DD HH24:MI:SS'; SELECT to_date('2014-07-02 10:08:55') - 9::smallint; ?column? --------------------- 2014-06-23 10:08:55 (1 row) SET orafce.nls_date_format='MM-DD-YYYY HH24:MI:SS'; SELECT to_date('07-02-2014 10:08:55') - 9::smallint; ?column? --------------------- 2014-06-23 10:08:55 (1 row) SET orafce.nls_date_format='DD-MM-YYYY HH24:MI:SS'; SELECT to_date('02-07-2014 10:08:55') - 9::smallint; ?column? --------------------- 2014-06-23 10:08:55 (1 row) SET orafce.nls_date_format='YYYY-MM-DD HH24:MI:SS'; SELECT to_date('2014-07-02 10:08:55') - 9; ?column? --------------------- 2014-06-23 10:08:55 (1 row) SELECT to_date('2014-07-02 10:08:55','YYYY-MM-DD HH:MI:SS') - 9::smallint; ?column? --------------------- 2014-06-23 10:08:55 (1 row) SELECT to_date('02-07-2014 10:08:55','DD-MM-YYYY HH:MI:SS') - 9::smallint; ?column? --------------------- 2014-06-23 10:08:55 (1 row) SELECT to_date('07-02-2014 10:08:55','MM-DD-YYYY HH:MI:SS') - 9::smallint; ?column? --------------------- 2014-06-23 10:08:55 (1 row) SET orafce.nls_date_format='YYYY-MM-DD HH24:MI:SS'; SELECT to_date('2014-07-02 10:08:55') - 9::bigint; ?column? --------------------- 2014-06-23 10:08:55 (1 row) SET orafce.nls_date_format='MM-DD-YYYY HH24:MI:SS'; SELECT to_date('07-02-2014 10:08:55') - 9::bigint; ?column? --------------------- 2014-06-23 10:08:55 (1 row) SET orafce.nls_date_format='DD-MM-YYYY HH24:MI:SS'; SELECT to_date('02-07-2014 10:08:55') - 9::bigint; ?column? --------------------- 2014-06-23 10:08:55 (1 row) SELECT to_date('2014-07-02 10:08:55','YYYY-MM-DD HH:MI:SS') - 9::bigint; ?column? --------------------- 2014-06-23 10:08:55 (1 row) SELECT to_date('02-07-2014 10:08:55','DD-MM-YYYY HH:MI:SS') - 9::bigint; ?column? --------------------- 2014-06-23 10:08:55 (1 row) SELECT to_date('07-02-2014 10:08:55','MM-DD-YYYY HH:MI:SS') - 9::bigint; ?column? --------------------- 2014-06-23 10:08:55 (1 row) SET orafce.nls_date_format='YYYY-MM-DD HH24:MI:SS'; SELECT to_date('2014-07-02 10:08:55') - 9::integer; ?column? --------------------- 2014-06-23 10:08:55 (1 row) SET orafce.nls_date_format='MM-DD-YYYY HH24:MI:SS'; SELECT to_date('07-02-2014 10:08:55') - 9::integer; ?column? --------------------- 2014-06-23 10:08:55 (1 row) SET orafce.nls_date_format='DD-MM-YYYY HH24:MI:SS'; SELECT to_date('02-07-2014 10:08:55') - 9::integer; ?column? --------------------- 2014-06-23 10:08:55 (1 row) SELECT to_date('2014-07-02 10:08:55','YYYY-MM-DD HH:MI:SS') - 9::integer; ?column? --------------------- 2014-06-23 10:08:55 (1 row) SELECT to_date('02-07-2014 10:08:55','DD-MM-YYYY HH:MI:SS') - 9::integer; ?column? --------------------- 2014-06-23 10:08:55 (1 row) SELECT to_date('07-02-2014 10:08:55','MM-DD-YYYY HH:MI:SS') - 9::integer; ?column? --------------------- 2014-06-23 10:08:55 (1 row) SET orafce.nls_date_format='YYYY-MM-DD HH24:MI:SS'; SELECT to_date('2014-07-02 10:08:55') - 9::numeric; ?column? --------------------- 2014-06-23 10:08:55 (1 row) SET orafce.nls_date_format='MM-DD-YYYY HH24:MI:SS'; SELECT to_date('07-02-2014 10:08:55') - 9::numeric; ?column? --------------------- 2014-06-23 10:08:55 (1 row) SET orafce.nls_date_format='DD-MM-YYYY HH24:MI:SS'; SELECT to_date('02-07-2014 10:08:55') - 9::numeric; ?column? --------------------- 2014-06-23 10:08:55 (1 row) SELECT to_date('2014-07-02 10:08:55','YYYY-MM-DD HH:MI:SS') - 9::numeric; ?column? --------------------- 2014-06-23 10:08:55 (1 row) SELECT to_date('02-07-2014 10:08:55','DD-MM-YYYY HH:MI:SS') - 9::numeric; ?column? --------------------- 2014-06-23 10:08:55 (1 row) SELECT to_date('07-02-2014 10:08:55','MM-DD-YYYY HH:MI:SS') - 9::numeric; ?column? --------------------- 2014-06-23 10:08:55 (1 row) SET orafce.nls_date_format='YYYY-MM-DD HH24:MI:SS'; SELECT to_date('2014-01-01 00:00:00') - 1.5; ?column? --------------------- 2013-12-30 12:00:00 (1 row) SELECT to_date('2014-01-01 00:00:00','yyyy-mm-dd hh24:mi:ss') - 1.5; ?column? --------------------- 2013-12-30 12:00:00 (1 row) SET search_path TO default; --Tests for oracle.to_char(timestamp)-used to set the DATE output format SET search_path TO oracle,"$user", public, pg_catalog; SET orafce.nls_date_format to default; select oracle.to_char(to_date('19-APR-16 21:41:48')); to_char --------------------- 2016-04-19 21:41:48 (1 row) set orafce.nls_date_format='YY-MonDD HH24:MI:SS'; select oracle.to_char(to_date('14-Jan08 11:44:49+05:30')); to_char ------------------- 14-Jan08 11:44:49 (1 row) set orafce.nls_date_format='YY-DDMon HH24:MI:SS'; select oracle.to_char(to_date('14-08Jan 11:44:49+05:30')); to_char ------------------- 14-08Jan 11:44:49 (1 row) set orafce.nls_date_format='DDMMYYYY HH24:MI:SS'; select oracle.to_char(to_date('21052014 12:13:44+05:30')); to_char ------------------- 21052014 12:13:44 (1 row) set orafce.nls_date_format='DDMMYY HH24:MI:SS'; select oracle.to_char(to_date('210514 12:13:44+05:30')); to_char ----------------- 210514 12:13:44 (1 row) set orafce.nls_date_format='DDMMYYYY HH24:MI:SS'; select oracle.to_char(oracle.to_date('2014/04/25 10:13', 'YYYY/MM/DD HH:MI')); to_char ------------------- 25042014 10:13:00 (1 row) set orafce.nls_date_format='YY-DDMon HH24:MI:SS'; select oracle.to_char(oracle.to_date('16-Feb-09 10:11:11', 'DD-Mon-YY HH:MI:SS')); to_char ------------------- 09-16Feb 10:11:11 (1 row) set orafce.nls_date_format='YY-DDMon HH24:MI:SS'; select oracle.to_char(oracle.to_date('02/16/09 04:12:12', 'MM/DD/YY HH24:MI:SS')); to_char ------------------- 09-16Feb 04:12:12 (1 row) set orafce.nls_date_format='YY-MonDD HH24:MI:SS'; select oracle.to_char(oracle.to_date('021609 111213', 'MMDDYY HHMISS')); to_char ------------------- 09-Feb16 11:12:13 (1 row) set orafce.nls_date_format='DDMMYYYY HH24:MI:SS'; select oracle.to_char(oracle.to_date('16-Feb-09 11:12:12', 'DD-Mon-YY HH:MI:SS')); to_char ------------------- 16022009 11:12:12 (1 row) set orafce.nls_date_format='DDMMYYYY HH24:MI:SS'; select oracle.to_char(oracle.to_date('Feb/16/09 11:21:23', 'Mon/DD/YY HH:MI:SS')); to_char ------------------- 16022009 11:21:23 (1 row) set orafce.nls_date_format='DDMMYYYY HH24:MI:SS'; select oracle.to_char(oracle.to_date('February.16.2009 10:11:12', 'Month.DD.YYYY HH:MI:SS')); to_char ------------------- 16022009 10:11:12 (1 row) set orafce.nls_date_format='YY-MonDD HH24:MI:SS'; select oracle.to_char(oracle.to_date('20020315111212', 'yyyymmddhh12miss')); to_char ------------------- 02-Mar15 11:12:12 (1 row) set orafce.nls_date_format='DDMMYYYY HH24:MI:SS'; select oracle.to_char(oracle.to_date('January 15, 1989, 11:00 A.M.','Month dd, YYYY, HH:MI A.M.')); to_char ------------------- 15011989 11:00:00 (1 row) set orafce.nls_date_format='DDMMYY HH24:MI:SS'; select oracle.to_char(oracle.to_date('14-Jan08 11:44:49+05:30' ,'YY-MonDD HH24:MI:SS')); to_char ----------------- 080114 11:44:49 (1 row) set orafce.nls_date_format='DDMMYYYY HH24:MI:SS'; select oracle.to_char(oracle.to_date('14-08Jan 11:44:49+05:30','YY-DDMon HH24:MI:SS')); to_char ------------------- 08012014 11:44:49 (1 row) set orafce.nls_date_format='YY-MonDD HH24:MI:SS'; select oracle.to_char(oracle.to_date('21052014 12:13:44+05:30','DDMMYYYY HH24:MI:SS')); to_char ------------------- 14-May21 12:13:44 (1 row) set orafce.nls_date_format='DDMMYY HH24:MI:SS'; select oracle.to_char(oracle.to_date('210514 12:13:44+05:30','DDMMYY HH24:MI:SS')); to_char ----------------- 210514 12:13:44 (1 row) SET search_path TO default; --Tests for oracle.-(oracle.date,oracle.date) SET search_path TO oracle,"$user", public, pg_catalog; SELECT (to_date('2014-07-17 11:10:15', 'yyyy-mm-dd hh24:mi:ss') - to_date('2014-02-01 10:00:00', 'yyyy-mm-dd hh24:mi:ss'))::numeric(10,4); numeric ---------- 166.0488 (1 row) SELECT (to_date('2014-07-17 13:14:15', 'yyyy-mm-dd hh24:mi:ss') - to_date('2014-02-01 10:00:00', 'yyyy-mm-dd hh24:mi:ss'))::numeric(10,4); numeric ---------- 166.1349 (1 row) SELECT (to_date('07-17-2014 13:14:15', 'mm-dd-yyyy hh24:mi:ss') - to_date('2014-02-01 10:00:00', 'yyyy-mm-dd hh24:mi:ss'))::numeric(10,4); numeric ---------- 166.1349 (1 row) SELECT (to_date('07-17-2014 13:14:15', 'mm-dd-yyyy hh24:mi:ss') - to_date('2015-02-01 10:00:00', 'yyyy-mm-dd hh24:mi:ss'))::numeric(10,4); numeric ----------- -198.8651 (1 row) SELECT (to_date('07-17-2014 13:14:15', 'mm-dd-yyyy hh24:mi:ss') - to_date('01-01-2013 10:00:00', 'mm-dd-yyyy hh24:mi:ss'))::numeric(10,4); numeric ---------- 562.1349 (1 row) SELECT (to_date('17-07-2014 13:14:15', 'dd-mm-yyyy hh24:mi:ss') - to_date('01-01-2013 10:00:00', 'dd--mm-yyyy hh24:mi:ss'))::numeric(10,4); numeric ---------- 562.1349 (1 row) SELECT (to_date('2014/02/01 10:11:12', 'YYYY/MM/DD hh12:mi:ss') - to_date('2013/02/01 10:11:12', 'YYYY/MM/DD hh12:mi:ss'))::numeric(10,4); numeric ---------- 365.0000 (1 row) SELECT (to_date('17-Jul-14 10:11:11', 'DD-Mon-YY HH:MI:SS') - to_date('17-Jan-14 00:00:00', 'DD-Mon-YY HH24:MI:SS'))::numeric(10,4); numeric ---------- 181.4244 (1 row) SELECT (to_date('July.17.2014 10:11:12', 'Month.DD.YYYY HH:MI:SS') - to_date('February.16.2014 10:21:12', 'Month.DD.YYYY HH:MI:SS'))::numeric(10,4); numeric ---------- 150.9931 (1 row) SELECT (to_date('20140717111211', 'yyyymmddhh12miss') - to_date('20140315111212', 'yyyymmddhh12miss'))::numeric(10,4); numeric ---------- 124.0000 (1 row) SELECT (to_date('January 15, 1990, 11:00 A.M.','Month dd, YYYY, HH:MI A.M.') - to_date('January 15, 1989, 10:00 A.M.','Month dd, YYYY, HH:MI A.M.'))::numeric(10,4); numeric ---------- 365.0417 (1 row) SELECT (to_date('14-Jul14 11:44:49' ,'YY-MonDD HH24:MI:SS') - to_date('14-Jan14 12:44:49' ,'YY-MonDD HH24:MI:SS'))::numeric(10,4); numeric ---------- 180.9583 (1 row) SELECT (to_date('210514 12:13:44','DDMMYY HH24:MI:SS') - to_date('210114 10:13:44','DDMMYY HH24:MI:SS'))::numeric(10,4); numeric ---------- 120.0833 (1 row) SELECT trunc(to_date('210514 12:13:44','DDMMYY HH24:MI:SS')); trunc --------------------- 2014-05-21 00:00:00 (1 row) SELECT round(to_date('210514 12:13:44','DDMMYY HH24:MI:SS')); round --------------------- 2014-05-22 00:00:00 (1 row) SET search_path TO default; -- -- Note: each Japanese character used below has display width of 2, otherwise 1. -- Note: each output string is surrounded by '|' for improved readability -- -- -- test LPAD family of functions -- /* cases where one or more arguments are of type CHAR */ SELECT '|' || oracle.lpad('あbcd'::char(8), 10) || '|'; ?column? -------------- | あbcd | (1 row) SELECT '|' || oracle.lpad('あbcd'::char(8), 5) || '|'; ?column? ---------- |あbcd| (1 row) SELECT '|' || oracle.lpad('あbcd'::char(8), 1) || '|'; ?column? ---------- | | (1 row) SELECT '|' || oracle.lpad('あbcd'::char(5), 10, 'xい'::char(3)) || '|'; ?column? -------------- |xい あbcd | (1 row) SELECT '|' || oracle.lpad('あbcd'::char(5), 5, 'xい'::char(3)) || '|'; ?column? ---------- |あbcd| (1 row) SELECT '|' || oracle.lpad('あbcd'::char(5), 10, 'xい'::text) || '|'; ?column? -------------- |xいxあbcd | (1 row) SELECT '|' || oracle.lpad('あbcd'::char(5), 10, 'xい'::varchar2(5)) || '|'; ?column? -------------- |xいxあbcd | (1 row) SELECT '|' || oracle.lpad('あbcd'::char(5), 10, 'xい'::nvarchar2(3)) || '|'; ?column? -------------- |xいxあbcd | (1 row) SELECT '|' || oracle.lpad('あbcd'::text, 10, 'xい'::char(3)) || '|'; ?column? -------------- |xい xあbcd| (1 row) SELECT '|' || oracle.lpad('あbcd'::text, 5, 'xい'::char(3)) || '|'; ?column? ---------- |あbcd| (1 row) SELECT '|' || oracle.lpad('あbcd'::varchar2(5), 10, 'xい'::char(3)) || '|'; ?column? -------------- | xい xあbc| (1 row) SELECT '|' || oracle.lpad('あbcd'::varchar2(5), 5, 'xい'::char(3)) || '|'; ?column? ---------- |xあbc| (1 row) SELECT '|' || oracle.lpad('あbcd'::nvarchar2(5), 10, 'xい'::char(3)) || '|'; ?column? -------------- |xい xあbcd| (1 row) SELECT '|' || oracle.lpad('あbcd'::nvarchar2(5), 5, 'xい'::char(3)) || '|'; ?column? ---------- |あbcd| (1 row) /* test oracle.lpad(text, int [, text]) */ SELECT '|' || oracle.lpad('あbcd'::text, 10) || '|'; ?column? -------------- | あbcd| (1 row) SELECT '|' || oracle.lpad('あbcd'::text, 5) || '|'; ?column? ---------- |あbcd| (1 row) SELECT '|' || oracle.lpad('あbcd'::varchar2(10), 10) || '|'; ?column? -------------- | あbcd| (1 row) SELECT '|' || oracle.lpad('あbcd'::varchar2(10), 5) || '|'; ?column? ---------- |あbcd| (1 row) SELECT '|' || oracle.lpad('あbcd'::nvarchar2(10), 10) || '|'; ?column? -------------- | あbcd| (1 row) SELECT '|' || oracle.lpad('あbcd'::nvarchar2(10), 5) || '|'; ?column? ---------- |あbcd| (1 row) SELECT '|' || oracle.lpad('あbcd'::text, 10, 'xい'::text) || '|'; ?column? -------------- | xいxあbcd| (1 row) SELECT '|' || oracle.lpad('あbcd'::text, 10, 'xい'::varchar2(5)) || '|'; ?column? -------------- | xいxあbcd| (1 row) SELECT '|' || oracle.lpad('あbcd'::text, 10, 'xい'::nvarchar2(3)) || '|'; ?column? -------------- | xいxあbcd| (1 row) SELECT '|' || oracle.lpad('あbcd'::varchar2(5), 10, 'xい'::text) || '|'; ?column? -------------- |xいxいあbc| (1 row) SELECT '|' || oracle.lpad('あbcd'::varchar2(5), 10, 'xい'::varchar2(5)) || '|'; ?column? -------------- |xいxいあbc| (1 row) SELECT '|' || oracle.lpad('あbcd'::varchar2(5), 10, 'xい'::nvarchar2(5)) || '|'; ?column? -------------- |xいxいあbc| (1 row) SELECT '|' || oracle.lpad('あbcd'::nvarchar2(5), 10, 'xい'::text) || '|'; ?column? -------------- | xいxあbcd| (1 row) SELECT '|' || oracle.lpad('あbcd'::nvarchar2(5), 10, 'xい'::varchar2(5)) || '|'; ?column? -------------- | xいxあbcd| (1 row) SELECT '|' || oracle.lpad('あbcd'::nvarchar2(5), 10, 'xい'::nvarchar2(5)) || '|'; ?column? -------------- | xいxあbcd| (1 row) -- -- test RPAD family of functions -- /* cases where one or more arguments are of type CHAR */ SELECT '|' || oracle.rpad('あbcd'::char(8), 10) || '|'; ?column? -------------- |あbcd | (1 row) SELECT '|' || oracle.rpad('あbcd'::char(8), 5) || '|'; ?column? ---------- |あbcd| (1 row) SELECT '|' || oracle.rpad('あbcd'::char(8), 1) || '|'; ?column? ---------- | | (1 row) SELECT '|' || oracle.rpad('あbcd'::char(5), 10, 'xい'::char(3)) || '|'; ?column? -------------- |あbcd xい | (1 row) SELECT '|' || oracle.rpad('あbcd'::char(5), 5, 'xい'::char(3)) || '|'; ?column? ---------- |あbcd| (1 row) SELECT '|' || oracle.rpad('あbcd'::char(5), 10, 'xい'::text) || '|'; ?column? -------------- |あbcd xいx| (1 row) SELECT '|' || oracle.rpad('あbcd'::char(5), 10, 'xい'::varchar2(5)) || '|'; ?column? -------------- |あbcd xいx| (1 row) SELECT '|' || oracle.rpad('あbcd'::char(5), 10, 'xい'::nvarchar2(3)) || '|'; ?column? -------------- |あbcd xいx| (1 row) SELECT '|' || oracle.rpad('あbcd'::text, 10, 'xい'::char(3)) || '|'; ?column? -------------- |あbcdxい x| (1 row) SELECT '|' || oracle.rpad('あbcd'::text, 5, 'xい'::char(3)) || '|'; ?column? ---------- |あbcd| (1 row) SELECT '|' || oracle.rpad('あbcd'::varchar2(5), 10, 'xい'::char(3)) || '|'; ?column? -------------- |あbcxい x | (1 row) SELECT '|' || oracle.rpad('あbcd'::varchar2(5), 5, 'xい'::char(3)) || '|'; ?column? ---------- |あbcx| (1 row) SELECT '|' || oracle.rpad('あbcd'::nvarchar2(5), 10, 'xい'::char(3)) || '|'; ?column? -------------- |あbcdxい x| (1 row) SELECT '|' || oracle.rpad('あbcd'::nvarchar2(5), 5, 'xい'::char(3)) || '|'; ?column? ---------- |あbcd| (1 row) /* test oracle.lpad(text, int [, text]) */ SELECT '|' || oracle.rpad('あbcd'::text, 10) || '|'; ?column? -------------- |あbcd | (1 row) SELECT '|' || oracle.rpad('あbcd'::text, 5) || '|'; ?column? ---------- |あbcd| (1 row) SELECT '|' || oracle.rpad('あbcd'::varchar2(10), 10) || '|'; ?column? -------------- |あbcd | (1 row) SELECT '|' || oracle.rpad('あbcd'::varchar2(10), 5) || '|'; ?column? ---------- |あbcd| (1 row) SELECT '|' || oracle.rpad('あbcd'::nvarchar2(10), 10) || '|'; ?column? -------------- |あbcd | (1 row) SELECT '|' || oracle.rpad('あbcd'::nvarchar2(10), 5) || '|'; ?column? ---------- |あbcd| (1 row) SELECT '|' || oracle.rpad('あbcd'::text, 10, 'xい'::text) || '|'; ?column? -------------- |あbcdxいx | (1 row) SELECT '|' || oracle.rpad('あbcd'::text, 10, 'xい'::varchar2(5)) || '|'; ?column? -------------- |あbcdxいx | (1 row) SELECT '|' || oracle.rpad('あbcd'::text, 10, 'xい'::nvarchar2(3)) || '|'; ?column? -------------- |あbcdxいx | (1 row) SELECT '|' || oracle.rpad('あbcd'::varchar2(5), 10, 'xい'::text) || '|'; ?column? -------------- |あbcxいxい| (1 row) SELECT '|' || oracle.rpad('あbcd'::varchar2(5), 10, 'xい'::varchar2(5)) || '|'; ?column? -------------- |あbcxいxい| (1 row) SELECT '|' || oracle.rpad('あbcd'::varchar2(5), 10, 'xい'::nvarchar2(5)) || '|'; ?column? -------------- |あbcxいxい| (1 row) SELECT '|' || oracle.rpad('あbcd'::nvarchar2(5), 10, 'xい'::text) || '|'; ?column? -------------- |あbcdxいx | (1 row) SELECT '|' || oracle.rpad('あbcd'::nvarchar2(5), 10, 'xい'::varchar2(5)) || '|'; ?column? -------------- |あbcdxいx | (1 row) SELECT '|' || oracle.rpad('あbcd'::nvarchar2(5), 10, 'xい'::nvarchar2(5)) || '|'; ?column? -------------- |あbcdxいx | (1 row) -- -- test TRIM family of functions -- /* test that trailing blanks of CHAR arguments are not removed and are significant */ -- -- LTRIM -- SELECT '|' || oracle.ltrim(' abcd'::char(10)) || '|' as LTRIM; ltrim ------------- |abcd | (1 row) SELECT '|' || oracle.ltrim(' abcd'::char(10),'a'::char(3)) || '|' as LTRIM; ltrim ------------ |bcd | (1 row) SELECT '|' || oracle.ltrim(' abcd'::char(10),'a'::text) || '|' as LTRIM; ltrim -------------- | abcd | (1 row) SELECT '|' || oracle.ltrim(' abcd'::char(10),'a'::varchar2(3)) || '|' as LTRIM; ltrim -------------- | abcd | (1 row) SELECT '|' || oracle.ltrim(' abcd'::char(10),'a'::nvarchar2(3)) || '|' as LTRIM; ltrim -------------- | abcd | (1 row) SELECT '|' || oracle.ltrim(' abcd '::text,'a'::char(3)) || '|' as LTRIM; ltrim --------- |bcd | (1 row) SELECT '|' || oracle.ltrim(' abcd '::varchar2(10),'a'::char(3)) || '|' as LTRIM; ltrim --------- |bcd | (1 row) SELECT '|' || oracle.ltrim(' abcd '::nvarchar2(10),'a'::char(3)) || '|' as LTRIM; ltrim --------- |bcd | (1 row) -- -- RTRIM -- SELECT '|' || oracle.rtrim(' abcd'::char(10)) || '|' as LTRIM; ltrim --------- | abcd| (1 row) SELECT '|' || oracle.rtrim(' abcd'::char(10),'d'::char(3)) || '|' as LTRIM; ltrim -------- | abc| (1 row) SELECT '|' || oracle.rtrim(' abcd'::char(10),'d'::text) || '|' as LTRIM; ltrim -------------- | abcd | (1 row) SELECT '|' || oracle.rtrim(' abcd'::char(10),'d'::varchar2(3)) || '|' as LTRIM; ltrim -------------- | abcd | (1 row) SELECT '|' || oracle.rtrim(' abcd'::char(10),'d'::nvarchar2(3)) || '|' as LTRIM; ltrim -------------- | abcd | (1 row) SELECT '|' || oracle.rtrim(' abcd '::text,'d'::char(3)) || '|' as LTRIM; ltrim -------- | abc| (1 row) SELECT '|' || oracle.rtrim(' abcd '::varchar2(10),'d'::char(3)) || '|' as LTRIM; ltrim -------- | abc| (1 row) SELECT '|' || oracle.rtrim(' abcd '::nvarchar2(10),'d'::char(3)) || '|' as LTRIM; ltrim -------- | abc| (1 row) -- -- BTRIM -- SELECT '|' || oracle.btrim(' abcd'::char(10)) || '|' as LTRIM; ltrim -------- |abcd| (1 row) SELECT '|' || oracle.btrim(' abcd'::char(10),'ad'::char(3)) || '|' as LTRIM; ltrim ------- |bc| (1 row) SELECT '|' || oracle.btrim(' abcd'::char(10),'ad'::text) || '|' as LTRIM; ltrim -------------- | abcd | (1 row) SELECT '|' || oracle.btrim(' abcd'::char(10),'ad'::varchar2(3)) || '|' as LTRIM; ltrim -------------- | abcd | (1 row) SELECT '|' || oracle.btrim(' abcd'::char(10),'ad'::nvarchar2(3)) || '|' as LTRIM; ltrim -------------- | abcd | (1 row) SELECT '|' || oracle.btrim(' abcd '::text,'d'::char(3)) || '|' as LTRIM; ltrim ------- |abc| (1 row) SELECT '|' || oracle.btrim(' abcd '::varchar2(10),'d'::char(3)) || '|' as LTRIM; ltrim ------- |abc| (1 row) SELECT '|' || oracle.btrim(' abcd '::nvarchar2(10),'d'::char(3)) || '|' as LTRIM; ltrim ------- |abc| (1 row) -- -- test oracle.length() -- /* test that trailing blanks are not ignored */ SELECT oracle.length('あbb'::char(6)); length -------- 6 (1 row) SELECT oracle.length(''::char(6)); length -------- 6 (1 row) -- -- test plvdate.bizdays_between -- SELECT plvdate.including_start(); including_start ----------------- t (1 row) SELECT plvdate.bizdays_between('2016-02-24','2016-02-26'); bizdays_between ----------------- 3 (1 row) SELECT plvdate.bizdays_between('2016-02-21','2016-02-27'); bizdays_between ----------------- 5 (1 row) SELECT plvdate.include_start(false); include_start --------------- (1 row) SELECT plvdate.bizdays_between('2016-02-24','2016-02-26'); bizdays_between ----------------- 2 (1 row) SELECT plvdate.bizdays_between('2016-02-21','2016-02-27'); bizdays_between ----------------- 5 (1 row) SELECT oracle.round(1.234::double precision, 2), oracle.trunc(1.234::double precision, 2); round | trunc -------+------- 1.23 | 1.23 (1 row) SELECT oracle.round(1.234::float, 2), oracle.trunc(1.234::float, 2); round | trunc -------+------- 1.23 | 1.23 (1 row) -- -- should not fail - fix: Crashes due to insufficent argument checking (#59) -- select dbms_random.string(null, 42); ERROR: an argument is NULL select dbms_pipe.create_pipe(null); ERROR: pipe name is NULL DETAIL: Pipename may not be NULL. select plunit.assert_not_equals(1,2,3); ERROR: plunit.assert_not_equal exception DETAIL: Plunit.assertation fails (assert_not_equals). -- -- lexer text -- SELECT pos, token, class, mod FROM plvlex.tokens('select * from a.b.c join d on x=y', true, true); pos | token | class | mod -----+--------+---------+------ 0 | select | KEYWORD | 7 | * | OTHERS | self 9 | from | KEYWORD | 14 | a.b.c | IDENT | 20 | join | KEYWORD | 25 | d | IDENT | 27 | on | KEYWORD | 30 | x | IDENT | 31 | = | OTHERS | self 32 | y | IDENT | (10 rows) orafce-VERSION_3_9_0/expected/orafce2.out000066400000000000000000000003771362147214200202150ustar00rootroot00000000000000-- 2) fails and throws error: 'ERROR: could not determine polymorphic type -- because input has type "unknown"' select decode('2012-01-01', '2012-01-01', 23, '2012-01-02', 24); ERROR: could not determine polymorphic type because input has type unknown orafce-VERSION_3_9_0/expected/orafce2_1.out000066400000000000000000000004011362147214200204210ustar00rootroot00000000000000-- 2) fails and throws error: 'ERROR: could not determine polymorphic type -- because input has type "unknown"' select decode('2012-01-01', '2012-01-01', 23, '2012-01-02', 24); ERROR: could not determine polymorphic type because input has type "unknown" orafce-VERSION_3_9_0/expected/varchar2.out000066400000000000000000000055071362147214200204040ustar00rootroot00000000000000\set VERBOSITY terse SET client_encoding = utf8; -- -- test type modifier related rules -- -- ERROR (typmod >= 1) CREATE TABLE foo (a VARCHAR2(0)); ERROR: length for type varchar must be at least 1 at character 21 -- ERROR (number of typmods = 1) CREATE TABLE foo (a VARCHAR2(10, 1)); ERROR: invalid type modifier at character 21 -- OK CREATE TABLE foo (a VARCHAR(5000)); -- cleanup DROP TABLE foo; -- OK CREATE TABLE foo (a VARCHAR2(5)); CREATE INDEX ON foo(a); -- -- test that no value longer than maxlen is allowed -- -- ERROR (length > 5) INSERT INTO foo VALUES ('abcdef'); ERROR: input value length is 6; too long for type varchar2(5) -- ERROR (length > 5); -- VARCHAR2 does not truncate blank spaces on implicit coercion INSERT INTO foo VALUES ('abcde '); ERROR: input value length is 7; too long for type varchar2(5) -- OK INSERT INTO foo VALUES ('abcde'); -- OK INSERT INTO foo VALUES ('abcdef'::VARCHAR2(5)); -- OK INSERT INTO foo VALUES ('abcde '::VARCHAR2(5)); --OK INSERT INTO foo VALUES ('abc'::VARCHAR2(5)); -- -- test whitespace semantics on comparison -- -- equal SELECT 'abcde '::VARCHAR2(10) = 'abcde '::VARCHAR2(10); ?column? ---------- t (1 row) -- not equal SELECT 'abcde '::VARCHAR2(10) = 'abcde '::VARCHAR2(10); ?column? ---------- f (1 row) -- -- test string functions created for varchar2 -- -- substrb(varchar2, int, int) SELECT substrb('ABCありがとう'::VARCHAR2, 7, 6); substrb --------- りが (1 row) -- returns 'f' (emtpy string is not NULL) SELECT substrb('ABCありがとう'::VARCHAR2, 7, 0) IS NULL; ?column? ---------- f (1 row) -- If the starting position is zero or less, then return from the start -- of the string adjusting the length to be consistent with the "negative start" -- per SQL. SELECT substrb('ABCありがとう'::VARCHAR2, 0, 4); substrb --------- ABC (1 row) -- substrb(varchar2, int) SELECT substrb('ABCありがとう', 5); substrb ---------- りがとう (1 row) -- strposb(varchar2, varchar2) SELECT strposb('ABCありがとう', 'りが'); strposb --------- 7 (1 row) -- returns 1 (start of the source string) SELECT strposb('ABCありがとう', ''); strposb --------- 1 (1 row) -- returns 0 SELECT strposb('ABCありがとう', 'XX'); strposb --------- 0 (1 row) -- returns 't' SELECT strposb('ABCありがとう', NULL) IS NULL; ?column? ---------- t (1 row) -- lengthb(varchar2) SELECT lengthb('ABCありがとう'); lengthb --------- 18 (1 row) -- returns 0 SELECT lengthb(''); lengthb --------- 0 (1 row) -- returs 't' SELECT lengthb(NULL) IS NULL; ?column? ---------- t (1 row) -- null safe concat (disabled by default) SELECT NULL || 'hello'::varchar2 || NULL; ?column? ---------- (1 row) SET orafce.varchar2_null_safe_concat TO true; SELECT NULL || 'hello'::varchar2 || NULL; ?column? ---------- hello (1 row) orafce-VERSION_3_9_0/file.c000066400000000000000000000614701362147214200154260ustar00rootroot00000000000000/* * This functionality doesn't work on Microsoft Windows. Probably, there are more * than one issue: * * functions fwrite, fclose, .. fails on segfault when file is locked. Probably * PostgreSQL process and extension is not fully initialized and these "safe" * functions crashes. Possible solution is nolock thread unsafe functions like * _fwrite_nolock, It doesn't crash, but doesn't work. Returned file - file handler * is not valid (although fileptr is not NULL). * * From these reasons, this functionality is blocked on MS Windows. */ #ifdef _MSC_VER #define _CRT_SECURE_NO_DEPRECATE #endif #include "postgres.h" #include #include #include #include "executor/spi.h" #include "access/htup_details.h" #include "catalog/pg_type.h" #include "fmgr.h" #include "funcapi.h" #include "mb/pg_wchar.h" #include "miscadmin.h" #include "port.h" #include "storage/fd.h" #include "utils/builtins.h" #include "utils/memutils.h" #include "orafce.h" #include "builtins.h" #ifndef ERRCODE_NO_DATA_FOUND #define ERRCODE_NO_DATA_FOUND MAKE_SQLSTATE('P','0', '0','0','2') #endif #define INVALID_OPERATION "UTL_FILE_INVALID_OPERATION" #define WRITE_ERROR "UTL_FILE_WRITE_ERROR" #define READ_ERROR "UTL_FILE_READ_ERROR" #define INVALID_FILEHANDLE "UTL_FILE_INVALID_FILEHANDLE" #define INVALID_MAXLINESIZE "UTL_FILE_INVALID_MAXLINESIZE" #define INVALID_MODE "UTL_FILE_INVALID_MODE" #define INVALID_PATH "UTL_FILE_INVALID_PATH" #define VALUE_ERROR "UTL_FILE_VALUE_ERROR" PG_FUNCTION_INFO_V1(utl_file_fopen); PG_FUNCTION_INFO_V1(utl_file_is_open); PG_FUNCTION_INFO_V1(utl_file_get_line); PG_FUNCTION_INFO_V1(utl_file_get_nextline); PG_FUNCTION_INFO_V1(utl_file_put); PG_FUNCTION_INFO_V1(utl_file_put_line); PG_FUNCTION_INFO_V1(utl_file_new_line); PG_FUNCTION_INFO_V1(utl_file_putf); PG_FUNCTION_INFO_V1(utl_file_fflush); PG_FUNCTION_INFO_V1(utl_file_fclose); PG_FUNCTION_INFO_V1(utl_file_fclose_all); PG_FUNCTION_INFO_V1(utl_file_fremove); PG_FUNCTION_INFO_V1(utl_file_frename); PG_FUNCTION_INFO_V1(utl_file_fcopy); PG_FUNCTION_INFO_V1(utl_file_fgetattr); PG_FUNCTION_INFO_V1(utl_file_tmpdir); #define CUSTOM_EXCEPTION(msg, detail) \ ereport(ERROR, \ (errcode(ERRCODE_RAISE_EXCEPTION), \ errmsg("%s", msg), \ errdetail("%s", detail))) #define STRERROR_EXCEPTION(msg) \ do { char *strerr = strerror(errno); CUSTOM_EXCEPTION(msg, strerr); } while(0); #define INVALID_FILEHANDLE_EXCEPTION() CUSTOM_EXCEPTION(INVALID_FILEHANDLE, "Used file handle isn't valid.") #define CHECK_FILE_HANDLE() \ if (PG_ARGISNULL(0)) \ CUSTOM_EXCEPTION(INVALID_FILEHANDLE, "Used file handle isn't valid.") #define NON_EMPTY_TEXT(dat) \ if (VARSIZE(dat) - VARHDRSZ == 0) \ ereport(ERROR, \ (errcode(ERRCODE_INVALID_PARAMETER_VALUE), \ errmsg("invalid parameter"), \ errdetail("Empty string isn't allowed."))); #define NOT_NULL_ARG(n) \ if (PG_ARGISNULL(n)) \ ereport(ERROR, \ (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), \ errmsg("null value not allowed"), \ errhint("%dth argument is NULL.", n))); #define MAX_LINESIZE 32767 #define CHECK_LINESIZE(max_linesize) \ do { \ if ((max_linesize) < 1 || (max_linesize) > MAX_LINESIZE) \ CUSTOM_EXCEPTION(INVALID_MAXLINESIZE, "maxlinesize is out of range"); \ } while(0) typedef struct FileSlot { FILE *file; int max_linesize; int encoding; int32 id; } FileSlot; #define MAX_SLOTS 50 /* Oracle 10g supports 50 files */ #define INVALID_SLOTID 0 /* invalid slot id */ static FileSlot slots[MAX_SLOTS]; /* initilaized with zeros */ static int32 slotid = 0; /* next slot id */ static void check_secure_locality(const char *path); static char *get_safe_path(text *location, text *filename); static int copy_text_file(FILE *srcfile, FILE *dstfile, int start_line, int end_line); /* * get_descriptor(FILE *file) find any free slot for FILE pointer. * If isn't realloc array slots and add 32 new free slots. * */ static int get_descriptor(FILE *file, int max_linesize, int encoding) { int i; for (i = 0; i < MAX_SLOTS; i++) { if (slots[i].id == INVALID_SLOTID) { slots[i].id = ++slotid; if (slots[i].id == INVALID_SLOTID) slots[i].id = ++slotid; /* skip INVALID_SLOTID */ slots[i].file = file; slots[i].max_linesize = max_linesize; slots[i].encoding = encoding; return slots[i].id; } } return INVALID_SLOTID; } /* return stored pointer to FILE */ static FILE * get_stream(int d, int *max_linesize, int *encoding) { int i; if (d == INVALID_SLOTID) INVALID_FILEHANDLE_EXCEPTION(); for (i = 0; i < MAX_SLOTS; i++) { if (slots[i].id == d) { if (max_linesize) *max_linesize = slots[i].max_linesize; if (encoding) *encoding = slots[i].encoding; return slots[i].file; } } INVALID_FILEHANDLE_EXCEPTION(); return NULL; /* keep compiler quiet */ } static void IO_EXCEPTION(void) { switch (errno) { case EACCES: case ENAMETOOLONG: case ENOENT: case ENOTDIR: STRERROR_EXCEPTION(INVALID_PATH); break; default: STRERROR_EXCEPTION(INVALID_OPERATION); } } /* * FUNCTION UTL_FILE.FOPEN(location text, * filename text, * open_mode text, * max_linesize integer) * RETURNS UTL_FILE.FILE_TYPE; * * The FOPEN function opens specified file and returns file handle. * open_mode: ['R', 'W', 'A'] * max_linesize: [1 .. 32767] * * Exceptions: * INVALID_MODE, INVALID_OPERATION, INVALID_PATH, INVALID_MAXLINESIZE */ Datum utl_file_fopen(PG_FUNCTION_ARGS) { text *open_mode; int max_linesize; int encoding; const char *mode = NULL; FILE *file; char *fullname; int d; #ifdef _MSC_VER elog(ERROR, "utl_file package is not supported on Microsoft Windows"); #endif NOT_NULL_ARG(0); NOT_NULL_ARG(1); NOT_NULL_ARG(2); NOT_NULL_ARG(3); open_mode = PG_GETARG_TEXT_P(2); NON_EMPTY_TEXT(open_mode); max_linesize = PG_GETARG_INT32(3); CHECK_LINESIZE(max_linesize); if (PG_NARGS() > 4 && !PG_ARGISNULL(4)) { const char *encname = NameStr(*PG_GETARG_NAME(4)); encoding = pg_char_to_encoding(encname); if (encoding < 0) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid encoding name \"%s\"", encname))); } else encoding = GetDatabaseEncoding(); if (VARSIZE(open_mode) - VARHDRSZ != 1) CUSTOM_EXCEPTION(INVALID_MODE, "open mode is different than [R,W,A]"); switch (*((char*)VARDATA(open_mode))) { case 'a': case 'A': mode = "a"; break; case 'r': case 'R': mode = "r"; break; case 'w': case 'W': mode = "w"; break; default: CUSTOM_EXCEPTION(INVALID_MODE, "open mode is different than [R,W,A]"); } /* open file */ fullname = get_safe_path(PG_GETARG_TEXT_P(0), PG_GETARG_TEXT_P(1)); /* * We cannot use AllocateFile here because those files are automatically * closed at the end of (sub)transactions, but we want to keep them open * for oracle compatibility. */ #if NOT_USED fullname = convert_encoding_server_to_platform(fullname); #endif file = fopen(fullname, mode); if (!file) IO_EXCEPTION(); d = get_descriptor(file, max_linesize, encoding); if (d == INVALID_SLOTID) { fclose(file); ereport(ERROR, (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("program limit exceeded"), errdetail("Too much concurent opened files"), errhint("You can only open a maximum of ten files for each session"))); } PG_RETURN_INT32(d); } Datum utl_file_is_open(PG_FUNCTION_ARGS) { #ifdef _MSC_VER elog(ERROR, "utl_file package is not supported on Microsoft Windows"); #endif if (!PG_ARGISNULL(0)) { int i; int d = PG_GETARG_INT32(0); for (i = 0; i < MAX_SLOTS; i++) { if (slots[i].id == d) PG_RETURN_BOOL(slots[i].file != NULL); } } PG_RETURN_BOOL(false); } #define CHECK_LENGTH(l) \ if (l > max_linesize) \ CUSTOM_EXCEPTION(VALUE_ERROR, "buffer is too short"); /* read line from file. set eof if is EOF */ static text * get_line(FILE *f, int max_linesize, int encoding, bool *iseof) { int c; char *buffer = NULL; char *bpt; int csize = 0; text *result = NULL; bool eof = true; #ifdef _MSC_VER elog(ERROR, "utl_file package is not supported on Microsoft Windows"); #endif buffer = palloc(max_linesize + 2); bpt = buffer; errno = 0; while (csize < max_linesize && (c = fgetc(f)) != EOF) { eof = false; /* I was able read one char */ if (c == '\r') /* lookin ahead \n */ { c = fgetc(f); if (c == EOF) break; /* last char */ if (c != '\n') ungetc(c, f); /* skip \r\n */ break; } else if (c == '\n') break; ++csize; *bpt++ = c; } if (!eof) { char *decoded; size_t len; pg_verify_mbstr(encoding, buffer, csize, false); decoded = (char *) pg_do_encoding_conversion((unsigned char *) buffer, csize, encoding, GetDatabaseEncoding()); len = (decoded == buffer ? csize : strlen(decoded)); result = palloc(len + VARHDRSZ); memcpy(VARDATA(result), decoded, len); SET_VARSIZE(result, len + VARHDRSZ); if (decoded != buffer) pfree(decoded); *iseof = false; } else { switch (errno) { case 0: break; case EBADF: CUSTOM_EXCEPTION(INVALID_OPERATION, "file descriptor isn't valid for reading"); break; default: STRERROR_EXCEPTION(READ_ERROR); break; } *iseof = true; } pfree(buffer); return result; } /* * FUNCTION UTL_FILE.GET_LINE(file UTL_TYPE.FILE_TYPE, line int DEFAULT NULL) * RETURNS text; * * Reads one line from file. * * Exceptions: * NO_DATA_FOUND, INVALID_FILEHANDLE, INVALID_OPERATION, READ_ERROR */ Datum utl_file_get_line(PG_FUNCTION_ARGS) { int max_linesize = 0; /* keep compiler quiet */ int encoding = 0; /* keep compiler quiet */ FILE *f; text *result; bool iseof; #ifdef _MSC_VER elog(ERROR, "utl_file package is not supported on Microsoft Windows"); #endif CHECK_FILE_HANDLE(); f = get_stream(PG_GETARG_INT32(0), &max_linesize, &encoding); /* 'len' overwrites max_linesize, but must be smaller than max_linesize */ if (PG_NARGS() > 1 && !PG_ARGISNULL(1)) { int len = PG_GETARG_INT32(1); CHECK_LINESIZE(len); if (max_linesize > len) max_linesize = len; } result = get_line(f, max_linesize, encoding, &iseof); if (iseof) ereport(ERROR, (errcode(ERRCODE_NO_DATA_FOUND), errmsg("no data found"))); PG_RETURN_TEXT_P(result); } /* * FUNCTION UTL_FILE.GET_NEXTLINE(file UTL_TYPE.FILE_TYPE) * RETURNS text; * * Reads one line from file or retutns NULL * by Steven Feuerstein. * * Exceptions: * INVALID_FILEHANDLE, INVALID_OPERATION, READ_ERROR */ Datum utl_file_get_nextline(PG_FUNCTION_ARGS) { int max_linesize = 0; /* keep compiler quiet */ int encoding = 0; /* keep compiler quiet */ FILE *f; text *result; bool iseof; #ifdef _MSC_VER elog(ERROR, "utl_file package is not supported on Microsoft Windows"); #endif CHECK_FILE_HANDLE(); f = get_stream(PG_GETARG_INT32(0), &max_linesize, &encoding); result = get_line(f, max_linesize, encoding, &iseof); if (iseof) PG_RETURN_NULL(); PG_RETURN_TEXT_P(result); } static void do_flush(FILE *f) { if (fflush(f) != 0) { if (errno == EBADF) CUSTOM_EXCEPTION(INVALID_OPERATION, "File is not an opened, or is not open for writing"); else STRERROR_EXCEPTION(WRITE_ERROR); } } /* * FUNCTION UTL_FILE.PUT(file UTL_FILE.FILE_TYPE, buffer text) * RETURNS bool; * * The PUT function puts data out to specified file. Buffer length allowed is * 32K or 1024 (max_linesize); * * Exceptions: * INVALID_FILEHANDLE, INVALID_OPERATION, WRITE_ERROR, VALUE_ERROR * * Note: returns bool because I cannot do envelope over void function */ #define CHECK_ERRNO_PUT() \ switch (errno) \ { \ case EBADF: \ CUSTOM_EXCEPTION(INVALID_OPERATION, "file descriptor isn't valid for writing"); \ break; \ default: \ STRERROR_EXCEPTION(WRITE_ERROR); \ } /* encode(t, encoding) */ static char * encode_text(int encoding, text *t, size_t *length) { char *src = VARDATA_ANY(t); char *encoded; encoded = (char *) pg_do_encoding_conversion((unsigned char *) src, VARSIZE_ANY_EXHDR(t), GetDatabaseEncoding(), encoding); *length = (src == encoded ? VARSIZE_ANY_EXHDR(t) : strlen(encoded)); return encoded; } /* fwrite(encode(args[n], encoding), f) */ static size_t do_write(PG_FUNCTION_ARGS, int n, FILE *f, size_t max_linesize, int encoding) { text *arg = PG_GETARG_TEXT_P(n); char *str; size_t len; str = encode_text(encoding, arg, &len); CHECK_LENGTH(len); if (fwrite(str, 1, len, f) != len) CHECK_ERRNO_PUT(); if (VARDATA(arg) != str) pfree(str); PG_FREE_IF_COPY(arg, n); return len; } static FILE * do_put(PG_FUNCTION_ARGS) { FILE *f; int max_linesize = 0; /* keep compiler quiet */ int encoding = 0; /* keep compiler quiet */ CHECK_FILE_HANDLE(); f = get_stream(PG_GETARG_INT32(0), &max_linesize, &encoding); NOT_NULL_ARG(1); do_write(fcinfo, 1, f, max_linesize, encoding); return f; } Datum utl_file_put(PG_FUNCTION_ARGS) { #ifdef _MSC_VER elog(ERROR, "utl_file package is not supported on Microsoft Windows"); #endif do_put(fcinfo); PG_RETURN_BOOL(true); } static void do_new_line(FILE *f, int lines) { int i; for (i = 0; i < lines; i++) { #ifndef WIN32 if (fputc('\n', f) == EOF) CHECK_ERRNO_PUT(); #else if (fputs("\r\n", f) == EOF) CHECK_ERRNO_PUT(); #endif } } Datum utl_file_put_line(PG_FUNCTION_ARGS) { FILE *f; bool autoflush; #ifdef _MSC_VER elog(ERROR, "utl_file package is not supported on Microsoft Windows"); #endif f = do_put(fcinfo); autoflush = PG_GETARG_IF_EXISTS(2, BOOL, false); do_new_line(f, 1); if (autoflush) do_flush(f); PG_RETURN_BOOL(true); } Datum utl_file_new_line(PG_FUNCTION_ARGS) { FILE *f; int lines; #ifdef _MSC_VER elog(ERROR, "utl_file package is not supported on Microsoft Windows"); #endif CHECK_FILE_HANDLE(); f = get_stream(PG_GETARG_INT32(0), NULL, NULL); lines = PG_GETARG_IF_EXISTS(1, INT32, 1); do_new_line(f, lines); PG_RETURN_BOOL(true); } /* * FUNCTION UTL_FILE.PUTF(file UTL_FILE.FILE_TYPE, * format text, * arg1 text, * arg2 text, * arg3 text, * arg4 text, * arg5 text) * RETURNS bool; * * Puts formated data to file. Allows %s like subst symbol. * * Exception: * INVALID_FILEHANDLE, INVALID_OPERATION, WRITE_ERROR */ Datum utl_file_putf(PG_FUNCTION_ARGS) { FILE *f; char *format; int max_linesize; int encoding; size_t format_length; char *fpt; int cur_par = 0; size_t cur_len = 0; #ifdef _MSC_VER elog(ERROR, "utl_file package is not supported on Microsoft Windows"); #endif CHECK_FILE_HANDLE(); f = get_stream(PG_GETARG_INT32(0), &max_linesize, &encoding); NOT_NULL_ARG(1); format = encode_text(encoding, PG_GETARG_TEXT_P(1), &format_length); for (fpt = format; format_length > 0; fpt++, format_length--) { if (format_length == 1) { /* last char */ CHECK_LENGTH(++cur_len); if (fputc(*fpt, f) == EOF) CHECK_ERRNO_PUT(); continue; } /* ansi compatible string */ if (fpt[0] == '\\' && fpt[1] == 'n') { CHECK_LENGTH(++cur_len); if (fputc('\n', f) == EOF) CHECK_ERRNO_PUT(); fpt++; format_length--; continue; } if (fpt[0] == '%') { if (fpt[1] == '%') { CHECK_LENGTH(++cur_len); if (fputc('%', f) == EOF) CHECK_ERRNO_PUT(); } else if (fpt[1] == 's' && ++cur_par <= 5 && !PG_ARGISNULL(cur_par + 1)) { cur_len += do_write(fcinfo, cur_par + 1, f, max_linesize - cur_len, encoding); } fpt++; format_length--; continue; } CHECK_LENGTH(++cur_len); if (fputc(fpt[0], f) == EOF) CHECK_ERRNO_PUT(); } PG_RETURN_BOOL(true); } /* * FUNCTION UTL_FILE.FFLUSH(file UTL_FILE.FILE_TYPE) * RETURNS void; * * This function makes sure that all pending data for the specified file is written * physically out to file. * * Exceptions: * INVALID_FILEHANDLE, INVALID_OPERATION, WRITE_ERROR */ Datum utl_file_fflush(PG_FUNCTION_ARGS) { FILE *f; #ifdef _MSC_VER elog(ERROR, "utl_file package is not supported on Microsoft Windows"); #endif CHECK_FILE_HANDLE(); f = get_stream(PG_GETARG_INT32(0), NULL, NULL); do_flush(f); PG_RETURN_VOID(); } /* * FUNCTION UTL_FILE.FCLOSE(file UTL_FILE.FILE_TYPE) * RETURNS NULL * * Close an open file. This function reset file handle to NULL on Oracle platform. * It isn't possible in PostgreSQL, and then you have to call fclose function * like: * file := utl_file.fclose(file); * * Exception: * INVALID_FILEHANDLE, WRITE_ERROR */ Datum utl_file_fclose(PG_FUNCTION_ARGS) { int i; int d = PG_GETARG_INT32(0); #ifdef _MSC_VER elog(ERROR, "utl_file package is not supported on Microsoft Windows"); #endif for (i = 0; i < MAX_SLOTS; i++) { if (slots[i].id == d) { if (slots[i].file && fclose(slots[i].file) != 0) { if (errno == EBADF) CUSTOM_EXCEPTION(INVALID_FILEHANDLE, "File is not an opened"); else STRERROR_EXCEPTION(WRITE_ERROR); } slots[i].file = NULL; slots[i].id = INVALID_SLOTID; PG_RETURN_NULL(); } } INVALID_FILEHANDLE_EXCEPTION(); PG_RETURN_NULL(); } /* * FUNCTION UTL_FILE.FCLOSE_ALL() * RETURNS void * * Close all opened files. * * Exceptions: WRITE_ERROR */ Datum utl_file_fclose_all(PG_FUNCTION_ARGS) { int i; #ifdef _MSC_VER elog(ERROR, "utl_file package is not supported on Microsoft Windows"); #endif for (i = 0; i < MAX_SLOTS; i++) { if (slots[i].id != INVALID_SLOTID) { if (slots[i].file && fclose(slots[i].file) != 0) { if (errno == EBADF) CUSTOM_EXCEPTION(INVALID_FILEHANDLE, "File is not an opened"); else STRERROR_EXCEPTION(WRITE_ERROR); } slots[i].file = NULL; slots[i].id = INVALID_SLOTID; } } PG_RETURN_VOID(); } /* * utl_file_dir security .. is solved with aux. table. * * Raise exception if don't find string in table. */ static void check_secure_locality(const char *path) { static SPIPlanPtr plan = NULL; Oid argtypes[] = {TEXTOID}; Datum values[1]; char nulls[1] = {' '}; values[0] = CStringGetTextDatum(path); /* * SELECT 1 FROM utl_file.utl_file_dir * WHERE CASE WHEN substring(dir from '.$') = '/' THEN * substring($1, 1, length(dir)) = dir * ELSE * substring($1, 1, length(dir) + 1) = dir || '/' * END */ if (SPI_connect() < 0) ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), errmsg("SPI_connect failed"))); if (!plan) { /* Don't use LIKE not to escape '_' and '%' */ SPIPlanPtr p = SPI_prepare( "SELECT 1 FROM utl_file.utl_file_dir" " WHERE CASE WHEN substring(dir from '.$') = '/' THEN" " substring($1, 1, length(dir)) = dir" " ELSE" " substring($1, 1, length(dir) + 1) = dir || '/'" " END", 1, argtypes); if (p == NULL || (plan = SPI_saveplan(p)) == NULL) ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), errmsg("SPI_prepare_failed"))); } if (SPI_OK_SELECT != SPI_execute_plan(plan, values, nulls, false, 1)) ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), errmsg("can't execute sql"))); if (SPI_processed == 0) ereport(ERROR, (errcode(ERRCODE_RAISE_EXCEPTION), errmsg(INVALID_PATH), errdetail("you cannot access locality"), errhint("locality is not found in utl_file_dir table"))); SPI_finish(); } /* * get_safe_path - make a fullpath and check security. */ static char * get_safe_path(text *location, text *filename) { char *fullname; int aux_pos; int aux_len; NON_EMPTY_TEXT(location); NON_EMPTY_TEXT(filename); aux_pos = VARSIZE_ANY_EXHDR(location); aux_len = VARSIZE_ANY_EXHDR(filename); fullname = palloc(aux_pos + 1 + aux_len + 1); memcpy(fullname, VARDATA(location), aux_pos); fullname[aux_pos] = '/'; memcpy(fullname + aux_pos + 1, VARDATA(filename), aux_len); fullname[aux_pos + aux_len + 1] = '\0'; /* check locality in canonizalized form of path */ canonicalize_path(fullname); check_secure_locality(fullname); return fullname; } /* * CREATE FUNCTION utl_file.fremove( * location text, * filename text) */ Datum utl_file_fremove(PG_FUNCTION_ARGS) { char *fullname; #ifdef _MSC_VER elog(ERROR, "utl_file package is not supported on Microsoft Windows"); #endif NOT_NULL_ARG(0); NOT_NULL_ARG(1); fullname = get_safe_path(PG_GETARG_TEXT_P(0), PG_GETARG_TEXT_P(1)); if (unlink(fullname) != 0) IO_EXCEPTION(); PG_RETURN_VOID(); } /* * CREATE FUNCTION utl_file.frename( * location text, * filename text, * dest_dir text, * dest_file text, * overwrite boolean DEFAULT false) */ Datum utl_file_frename(PG_FUNCTION_ARGS) { char *srcpath; char *dstpath; bool overwrite; #ifdef _MSC_VER elog(ERROR, "utl_file package is not supported on Microsoft Windows"); #endif NOT_NULL_ARG(0); NOT_NULL_ARG(1); NOT_NULL_ARG(2); NOT_NULL_ARG(3); overwrite = PG_GETARG_IF_EXISTS(4, BOOL, false); srcpath = get_safe_path(PG_GETARG_TEXT_P(0), PG_GETARG_TEXT_P(1)); dstpath = get_safe_path(PG_GETARG_TEXT_P(2), PG_GETARG_TEXT_P(3)); if (!overwrite) { struct stat st; if (stat(dstpath, &st) == 0) CUSTOM_EXCEPTION(WRITE_ERROR, "File exists"); else if (errno != ENOENT) IO_EXCEPTION(); } /* rename() overwrites existing files. */ if (rename(srcpath, dstpath) != 0) IO_EXCEPTION(); PG_RETURN_VOID(); } /* * CREATE FUNCTION utl_file.fcopy( * src_location text, * src_filename text, * dest_location text, * dest_filename text, * start_line integer DEFAULT NULL * end_line integer DEFAULT NULL) */ Datum utl_file_fcopy(PG_FUNCTION_ARGS) { char *srcpath; char *dstpath; int start_line; int end_line; FILE *srcfile; FILE *dstfile; #ifdef _MSC_VER elog(ERROR, "utl_file package is not supported on Microsoft Windows"); #endif NOT_NULL_ARG(0); NOT_NULL_ARG(1); NOT_NULL_ARG(2); NOT_NULL_ARG(3); srcpath = get_safe_path(PG_GETARG_TEXT_P(0), PG_GETARG_TEXT_P(1)); dstpath = get_safe_path(PG_GETARG_TEXT_P(2), PG_GETARG_TEXT_P(3)); start_line = PG_GETARG_IF_EXISTS(4, INT32, 1); if (start_line <= 0) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("start_line must be positive (%d passed)", start_line))); end_line = PG_GETARG_IF_EXISTS(5, INT32, INT_MAX); if (end_line <= 0) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("end_line must be positive (%d passed)", end_line))); srcfile = AllocateFile(srcpath, "rt"); if (srcfile == NULL) { /* failed to open src file. */ IO_EXCEPTION(); } dstfile = AllocateFile(dstpath, "wt"); if (dstfile == NULL) { /* failed to open dst file. */ fclose(srcfile); IO_EXCEPTION(); } if (copy_text_file(srcfile, dstfile, start_line, end_line)) IO_EXCEPTION(); FreeFile(srcfile); FreeFile(dstfile); PG_RETURN_VOID(); } /* * Copy srcfile to dstfile. Return 0 if succeeded, or non-0 if error. */ static int copy_text_file(FILE *srcfile, FILE *dstfile, int start_line, int end_line) { char buffer[MAX_LINESIZE]; size_t len; int i; errno = 0; /* skip first start_line. */ for (i = 1; i < start_line; i++) { CHECK_FOR_INTERRUPTS(); do { if (fgets(buffer, lengthof(buffer), srcfile) == NULL) return errno; len = strlen(buffer); } while(buffer[len - 1] != '\n'); } /* copy until end_line. */ for (; i <= end_line; i++) { CHECK_FOR_INTERRUPTS(); do { if (fgets(buffer, lengthof(buffer), srcfile) == NULL) return errno; len = strlen(buffer); if (fwrite(buffer, 1, len, dstfile) != len) return errno; } while(buffer[len - 1] != '\n'); } return 0; } /* * CREATE FUNCTION utl_file.fgetattr( * location text, * filename text * ) RETURNS ( * fexists boolean, * file_length bigint, * blocksize integer) */ Datum utl_file_fgetattr(PG_FUNCTION_ARGS) { char *fullname; struct stat st; TupleDesc tupdesc; Datum result; HeapTuple tuple; Datum values[3]; bool nulls[3] = { 0 }; #ifdef _MSC_VER elog(ERROR, "utl_file package is not supported on Microsoft Windows"); #endif NOT_NULL_ARG(0); NOT_NULL_ARG(1); /* Build a tuple descriptor for our result type */ if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) elog(ERROR, "return type must be a row type"); fullname = get_safe_path(PG_GETARG_TEXT_P(0), PG_GETARG_TEXT_P(1)); if (stat(fullname, &st) == 0) { values[0] = BoolGetDatum(true); values[1] = Int64GetDatum(st.st_size); #ifndef WIN32 values[2] = Int32GetDatum(st.st_blksize); #else values[2] = 512; /* NTFS block size */ #endif } else { values[0] = BoolGetDatum(false); nulls[1] = true; nulls[2] = true; } tuple = heap_form_tuple(tupdesc, values, nulls); result = HeapTupleGetDatum(tuple); PG_RETURN_DATUM(result); } Datum utl_file_tmpdir(PG_FUNCTION_ARGS) { #ifndef WIN32 const char *tmpdir = getenv("TMPDIR"); if (!tmpdir) tmpdir = "/tmp"; #else char tmpdir[MAXPGPATH]; int ret; ret = GetTempPathA(MAXPGPATH, tmpdir); if (ret == 0 || ret > MAXPGPATH) CUSTOM_EXCEPTION(INVALID_PATH, strerror(errno)); canonicalize_path(tmpdir); #endif #ifdef _MSC_VER elog(ERROR, "utl_file package is not supported on Microsoft Windows"); #endif PG_RETURN_TEXT_P(cstring_to_text(tmpdir)); } orafce-VERSION_3_9_0/magic.c000066400000000000000000000001301362147214200155510ustar00rootroot00000000000000#include "postgres.h" #include "fmgr.h" #ifdef PG_MODULE_MAGIC PG_MODULE_MAGIC; #endif orafce-VERSION_3_9_0/msvc/000077500000000000000000000000001362147214200153035ustar00rootroot00000000000000orafce-VERSION_3_9_0/msvc/orafce.2010.sln000066400000000000000000000041671362147214200176510ustar00rootroot00000000000000 Microsoft Visual Studio Solution File, Format Version 11.00 # Visual Studio 2010 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "orafce", "orafce.2010.vcxproj", "{B6B37F22-9E44-4240-AAA0-650D4AC2C2E2}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution 10.3|Win32 = 10.3|Win32 10.3|x64 = 10.3|x64 8.3|Win32 = 8.3|Win32 8.3|x64 = 8.3|x64 8.4|Win32 = 8.4|Win32 8.4|x64 = 8.4|x64 9.0|Win32 = 9.0|Win32 9.0|x64 = 9.0|x64 9.6|Win32 = 9.6|Win32 9.6|x64 = 9.6|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {B6B37F22-9E44-4240-AAA0-650D4AC2C2E2}.10.3|Win32.ActiveCfg = 10.3|Win32 {B6B37F22-9E44-4240-AAA0-650D4AC2C2E2}.10.3|Win32.Build.0 = 10.3|Win32 {B6B37F22-9E44-4240-AAA0-650D4AC2C2E2}.10.3|x64.ActiveCfg = 10.3|x64 {B6B37F22-9E44-4240-AAA0-650D4AC2C2E2}.10.3|x64.Build.0 = 10.3|x64 {B6B37F22-9E44-4240-AAA0-650D4AC2C2E2}.8.3|Win32.ActiveCfg = 8.3|Win32 {B6B37F22-9E44-4240-AAA0-650D4AC2C2E2}.8.3|Win32.Build.0 = 8.3|Win32 {B6B37F22-9E44-4240-AAA0-650D4AC2C2E2}.8.3|x64.ActiveCfg = 8.3|x64 {B6B37F22-9E44-4240-AAA0-650D4AC2C2E2}.8.3|x64.Build.0 = 8.3|x64 {B6B37F22-9E44-4240-AAA0-650D4AC2C2E2}.8.4|Win32.ActiveCfg = 8.4|Win32 {B6B37F22-9E44-4240-AAA0-650D4AC2C2E2}.8.4|Win32.Build.0 = 8.4|Win32 {B6B37F22-9E44-4240-AAA0-650D4AC2C2E2}.8.4|x64.ActiveCfg = 8.4|x64 {B6B37F22-9E44-4240-AAA0-650D4AC2C2E2}.8.4|x64.Build.0 = 8.4|x64 {B6B37F22-9E44-4240-AAA0-650D4AC2C2E2}.9.0|Win32.ActiveCfg = 9.0|Win32 {B6B37F22-9E44-4240-AAA0-650D4AC2C2E2}.9.0|Win32.Build.0 = 9.0|Win32 {B6B37F22-9E44-4240-AAA0-650D4AC2C2E2}.9.0|x64.ActiveCfg = 9.0|x64 {B6B37F22-9E44-4240-AAA0-650D4AC2C2E2}.9.0|x64.Build.0 = 9.0|x64 {B6B37F22-9E44-4240-AAA0-650D4AC2C2E2}.9.6|Win32.ActiveCfg = 9.6|Win32 {B6B37F22-9E44-4240-AAA0-650D4AC2C2E2}.9.6|Win32.Build.0 = 9.6|Win32 {B6B37F22-9E44-4240-AAA0-650D4AC2C2E2}.9.6|x64.ActiveCfg = 9.6|x64 {B6B37F22-9E44-4240-AAA0-650D4AC2C2E2}.9.6|x64.Build.0 = 9.6|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal orafce-VERSION_3_9_0/msvc/orafce.2010.vcxproj000066400000000000000000000777531362147214200205630ustar00rootroot00000000000000 10.3 Win32 10.3 x64 8.3 Win32 8.3 x64 8.4 Win32 8.4 x64 9.0 Win32 9.0 x64 9.6 Win32 9.6 x64 {B6B37F22-9E44-4240-AAA0-650D4AC2C2E2} lib Win32Proj orafce DynamicLibrary Unicode true Windows7.1SDK DynamicLibrary Unicode true Windows7.1SDK DynamicLibrary Unicode true Windows7.1SDK DynamicLibrary Unicode true Windows7.1SDK DynamicLibrary Unicode true Windows7.1SDK DynamicLibrary Unicode true Windows7.1SDK DynamicLibrary Unicode true Windows7.1SDK DynamicLibrary Unicode true Windows7.1SDK DynamicLibrary Unicode true Windows7.1SDK DynamicLibrary Unicode true Windows7.1SDK <_ProjectFileVersion>10.0.30319.1 $(SolutionDir)/bin/x86/$(Configuration)/lib/ $(SolutionDir)/bin/x86/$(Configuration)/lib/ $(SolutionDir)/bin/x86/$(Configuration)/lib/ $(SolutionDir)/bin/$(Platform)/$(Configuration)/lib/ $(SolutionDir)/bin/$(Platform)/$(Configuration)/lib/ $(SolutionDir)/bin/$(Platform)/$(Configuration)/lib/ $(SolutionDir)/bin/x86/$(Configuration)/lib/ $(SolutionDir)/bin/$(Platform)/$(Configuration)/lib/ $(SolutionDir)/bin/x86/$(Configuration)/lib/ $(SolutionDir)/bin/$(Platform)/$(Configuration)/lib/ $(SolutionDir)/obj/x86/$(Configuration)/$(ProjectName)/ $(SolutionDir)/obj/x86/$(Configuration)/$(ProjectName)/ $(SolutionDir)/obj/x86/$(Configuration)/$(ProjectName)/ $(SolutionDir)/obj/$(Platform)/$(Configuration)/$(ProjectName)/ $(SolutionDir)/obj/$(Platform)/$(Configuration)/$(ProjectName)/ $(SolutionDir)/obj/$(Platform)/$(Configuration)/$(ProjectName)/ $(SolutionDir)/obj/x86/$(Configuration)/$(ProjectName)/ $(SolutionDir)/obj/$(Platform)/$(Configuration)/$(ProjectName)/ $(SolutionDir)/obj/x86/$(Configuration)/$(ProjectName)/ $(SolutionDir)/obj/$(Platform)/$(Configuration)/$(ProjectName)/ false false false false false false false false false false C:\Program Files %28x86%29\PostgreSQL\9.0\include\server\port\win32_msvc;C:\Program Files %28x86%29\PostgreSQL\9.0\include\server\port\win32;C:\Program Files %28x86%29\PostgreSQL\9.0\include\server;C:\Program Files %28x86%29\PostgreSQL\9.0\include;$(IncludePath) C:\Program Files %28x86%29\PostgreSQL\9.6\include\server\port\win32_msvc;C:\Program Files %28x86%29\PostgreSQL\9.6\include\server\port\win32;C:\Program Files %28x86%29\PostgreSQL\9.6\include\server;C:\Program Files %28x86%29\PostgreSQL\9.6\include;$(IncludePath) C:\Program Files %28x86%29\PostgreSQL\10\include\server\port\win32_msvc;C:\Program Files %28x86%29\PostgreSQL\10\include\server\port\win32;C:\Program Files %28x86%29\PostgreSQL\10\include\server;C:\Program Files %28x86%29\PostgreSQL\10\include;$(IncludePath) C:\Program Files\PostgreSQL\9.0\include\server\port\win32_msvc;C:\Program Files\PostgreSQL\9.0\include\server\port\win32;C:\Program Files\PostgreSQL\9.0\include\server;C:\Program Files\PostgreSQL\9.0\include;$(IncludePath) C:\Program Files\PostgreSQL\9.6\include\server\port\win32_msvc;C:\Program Files\PostgreSQL\9.6\include\server\port\win32;C:\Program Files\PostgreSQL\9.6\include\server;C:\Program Files\PostgreSQL\9.6\include;$(IncludePath) C:\Program Files\PostgreSQL\10\include\server\port\win32_msvc;C:\Program Files\PostgreSQL\10\include\server\port\win32;C:\Program Files\PostgreSQL\10\include\server;C:\Program Files\PostgreSQL\10\include;C:\icu\include;$(IncludePath) C:\Program Files %28x86%29\PostgreSQL\8.4\include\server\port\win32_msvc;C:\Program Files %28x86%29\PostgreSQL\8.4\include\server\port\win32;C:\Program Files %28x86%29\PostgreSQL\8.4\include\server;C:\Program Files %28x86%29\PostgreSQL\8.4\include;$(IncludePath) C:\Program Files %28x86%29\PostgreSQL\8.4\include\server\port\win32_msvc;C:\Program Files %28x86%29\PostgreSQL\8.4\include\server\port\win32;C:\Program Files %28x86%29\PostgreSQL\8.4\include\server;C:\Program Files %28x86%29\PostgreSQL\8.4\include;$(IncludePath) C:\Program Files %28x86%29\PostgreSQL\8.3\include\server\port\win32_msvc;C:\Program Files %28x86%29\PostgreSQL\8.3\include\server\port\win32;C:\Program Files %28x86%29\PostgreSQL\8.3\include\server;C:\Program Files %28x86%29\PostgreSQL\8.3\include;$(IncludePath) C:\Program Files %28x86%29\PostgreSQL\8.3\include\server\port\win32_msvc;C:\Program Files %28x86%29\PostgreSQL\8.3\include\server\port\win32;C:\Program Files %28x86%29\PostgreSQL\8.3\include\server;C:\Program Files %28x86%29\PostgreSQL\8.3\include;$(IncludePath) C:\Program Files %28x86%29\PostgreSQL\9.0\lib;$(LibraryPath) C:\Program Files %28x86%29\PostgreSQL\9.6\lib;$(LibraryPath) C:\Program Files %28x86%29\PostgreSQL\10\lib;$(LibraryPath) C:\Program Files\PostgreSQL\9.0\lib;$(LibraryPath) C:\Program Files\PostgreSQL\9.6\lib;$(LibraryPath) C:\icu\lib64;C:\Program Files\PostgreSQL\10\lib;$(LibraryPath) C:\Program Files %28x86%29\PostgreSQL\8.4\lib;$(LibraryPath) C:\Program Files %28x86%29\PostgreSQL\8.4\lib;$(LibraryPath) C:\Program Files %28x86%29\PostgreSQL\8.3\lib;$(LibraryPath) C:\Program Files %28x86%29\PostgreSQL\8.3\lib;$(LibraryPath) orafce orafce orafce orafce orafce orafce orafce orafce orafce orafce ../include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) MultiThreadedDLL Level3 false CompileAsC 4005;4996;4018;%(DisableSpecificWarnings) postgres.lib $(OutDir)/$(TargetFileName) false Console true true MachineX86 ../include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) MultiThreadedDLL Level3 false CompileAsC 4005;4996;4018;%(DisableSpecificWarnings) postgres.lib $(OutDir)/$(TargetFileName) false Console true true MachineX86 ../include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) MultiThreadedDLL Level3 false CompileAsC 4005;4996;4018;%(DisableSpecificWarnings) postgres.lib $(OutDir)/$(TargetFileName) false Console true true MachineX86 ../include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) MultiThreadedDLL Level3 false CompileAsC 4005;4996;4018;%(DisableSpecificWarnings) postgres.lib $(OutDir)/$(TargetFileName) false Console true true ../include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) MultiThreadedDLL Level3 false CompileAsC 4005;4996;4018;%(DisableSpecificWarnings) postgres.lib $(OutDir)/$(TargetFileName) false Console true true ../include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) MultiThreadedDLL Level3 false CompileAsC 4005;4996;4018;%(DisableSpecificWarnings) postgres.lib $(OutDir)/$(TargetFileName) false Console true true ../include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) MultiThreadedDLL Level3 false CompileAsC 4005;4996;4018;%(DisableSpecificWarnings) postgres.lib $(OutDir)/$(TargetFileName) false Console true true MachineX86 ../include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) MultiThreadedDLL Level3 false CompileAsC 4005;4996;4018;%(DisableSpecificWarnings) postgres.lib $(OutDir)/$(TargetFileName) false Console true true ../include;%(AdditionalIncludeDirectories) _USE_32BIT_TIME_T;WIN32;NDEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) MultiThreadedDLL Level3 false CompileAsC 4005;4996;4018;%(DisableSpecificWarnings) postgres.lib $(OutDir)/$(TargetFileName) false Console true true MachineX86 ../include;%(AdditionalIncludeDirectories) _USE_32BIT_TIME_T;WIN32;NDEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) MultiThreadedDLL Level3 false CompileAsC 4005;4996;4018;%(DisableSpecificWarnings) postgres.lib $(OutDir)/$(TargetFileName) false Console true true orafce-VERSION_3_9_0/msvc/orafce.2010.vcxproj.filters000066400000000000000000000107331362147214200222130ustar00rootroot00000000000000 {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {c12fa9ac-05f6-45cb-bb38-f575a3a78f47} {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hpp;hxx;hm;inl;inc;xsd {bc5d92fe-cfa8-4220-b3cf-c63aede7db41} src src regress regress regress regress regress src src src src src src src src src src src src src src src src src src src src src src src include include include include include include orafce-VERSION_3_9_0/nvarchar2.c000066400000000000000000000115251362147214200163710ustar00rootroot00000000000000/*---------------------------------------------------------------------------- * * nvarchar2.c * NVARCHAR2 type for PostgreSQL. * *---------------------------------------------------------------------------- */ #include "postgres.h" #include "access/hash.h" #include "access/tuptoaster.h" #include "libpq/pqformat.h" #include "nodes/nodeFuncs.h" #include "utils/array.h" #include "utils/builtins.h" #include "mb/pg_wchar.h" #include "fmgr.h" #include "orafce.h" #include "builtins.h" PG_FUNCTION_INFO_V1(nvarchar2in); PG_FUNCTION_INFO_V1(nvarchar2out); PG_FUNCTION_INFO_V1(nvarchar2); PG_FUNCTION_INFO_V1(nvarchar2recv); /* * nvarchar2_input -- common guts of nvarchar2in and nvarchar2recv * * s is the input text of length len (may not be null-terminated) * atttypmod is the typmod value to apply * * If the input string is too long, raise an error * * Uses the C string to text conversion function, which is only appropriate * if VarChar and text are equivalent types. */ static VarChar * nvarchar2_input(const char *s, size_t len, int32 atttypmod) { VarChar *result; /* input data */ size_t maxlen; maxlen = atttypmod - VARHDRSZ; /* * Perform the typmod check; error out if value too long for NVARCHAR2 */ if (atttypmod >= (int32) VARHDRSZ && len > maxlen) { /* Verify that input length is within typmod limit. * * NOTE: blankspace is not truncated */ size_t mbmaxlen = pg_mbstrlen(s); if (mbmaxlen > maxlen) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("input value length is %zd; too long for type nvarchar2(%zd)", mbmaxlen , maxlen))); } result = (VarChar *) cstring_to_text_with_len(s, len); return result; } /* * Converts a C string to NVARCHAR2 internal representation. atttypmod * is the declared length of the type plus VARHDRSZ. */ Datum nvarchar2in(PG_FUNCTION_ARGS) { char *s = PG_GETARG_CSTRING(0); #ifdef NOT_USED Oid typelem = PG_GETARG_OID(1); #endif int32 atttypmod = PG_GETARG_INT32(2); VarChar *result; result = nvarchar2_input(s, strlen(s), atttypmod); PG_RETURN_VARCHAR_P(result); } /* * converts a NVARCHAR2 value to a C string. * * Uses the text to C string conversion function, which is only appropriate * if VarChar and text are equivalent types. */ Datum nvarchar2out(PG_FUNCTION_ARGS) { Datum txt = PG_GETARG_DATUM(0); PG_RETURN_CSTRING(TextDatumGetCString(txt)); } /* * converts external binary format to nvarchar */ Datum nvarchar2recv(PG_FUNCTION_ARGS) { StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); #ifdef NOT_USED Oid typelem = PG_GETARG_OID(1); #endif int32 atttypmod = PG_GETARG_INT32(2); /* typmod of the receiving column */ VarChar *result; char *str; /* received data */ int nbytes; /* length in bytes of recived data */ str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes); result = nvarchar2_input(str, nbytes, atttypmod); pfree(str); PG_RETURN_VARCHAR_P(result); } /* * nvarchar2send -- convert nvarchar2 to binary value * * just use varcharsend() */ /* * nvarchar2_transform() * Flatten calls to varchar's length coercion function that set the new maximum * length >= the previous maximum length. We can ignore the isExplicit * argument, since that only affects truncation cases. * * just use varchar_transform() */ /* * Converts a NVARCHAR2 type to the specified size. * * maxlen is the typmod, ie, declared length plus VARHDRSZ bytes. * isExplicit is true if this is for an explicit cast to nvarchar2(N). * * Truncation rules: for an explicit cast, silently truncate to the given * length; for an implicit cast, raise error if length limit is exceeded */ Datum nvarchar2(PG_FUNCTION_ARGS) { VarChar *source = PG_GETARG_VARCHAR_PP(0); int32 typmod = PG_GETARG_INT32(1); bool isExplicit = PG_GETARG_BOOL(2); int32 len, maxlen; int maxmblen; char *s_data; len = VARSIZE_ANY_EXHDR(source); s_data = VARDATA_ANY(source); maxlen = typmod - VARHDRSZ; /* No work if typmod is invalid or supplied data fits it already */ if (maxlen < 0 || len <= maxlen) PG_RETURN_VARCHAR_P(source); /* only reach here if string is too long... */ /* truncate multibyte string preserving multibyte boundary */ maxmblen = pg_mbcharcliplen(s_data, len, maxlen); /* error out if value too long unless it's an explicit cast */ if (!isExplicit) { /* if there is still data beyond maxmblen, error out * * Remember - no blankspace truncation on implicit cast */ if (len > maxmblen) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("input value too long for type nvarchar2(%d)", maxlen))); } PG_RETURN_VARCHAR_P((VarChar *) cstring_to_text_with_len(s_data, maxmblen)); } /* * nvarchar2typmodin -- type modifier input function * * just use varchartypmodin() */ /* * nvarchar2typmodout -- type modifier output function * * just use varchartypmodout() */ orafce-VERSION_3_9_0/orafce--3.2--3.3.sql000066400000000000000000000055241362147214200172540ustar00rootroot00000000000000ALTER FUNCTION dbms_assert.enquote_name ( character varying ) STRICT; ALTER FUNCTION dbms_assert.enquote_name ( character varying, boolean ) STRICT; ALTER FUNCTION dbms_assert.noop ( character varying ) STRICT; CREATE FUNCTION pg_catalog.trunc(value timestamp without time zone, fmt text) RETURNS timestamp without time zone AS 'MODULE_PATHNAME', 'ora_timestamp_trunc' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION pg_catalog.trunc(timestamp without time zone, text) IS 'truncate date according to the specified format'; CREATE FUNCTION pg_catalog.round(value timestamp without time zone, fmt text) RETURNS timestamp without time zone AS 'MODULE_PATHNAME','ora_timestamp_round' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION pg_catalog.round(timestamp with time zone, text) IS 'round dates according to the specified format'; CREATE FUNCTION pg_catalog.round(value timestamp without time zone) RETURNS timestamp without time zone AS $$ SELECT pg_catalog.round($1, 'DDD'); $$ LANGUAGE SQL IMMUTABLE STRICT; COMMENT ON FUNCTION pg_catalog.round(timestamp without time zone) IS 'will round dates according to the specified format'; CREATE FUNCTION pg_catalog.trunc(value timestamp without time zone) RETURNS timestamp without time zone AS $$ SELECT pg_catalog.trunc($1, 'DDD'); $$ LANGUAGE SQL IMMUTABLE STRICT; COMMENT ON FUNCTION pg_catalog.trunc(timestamp without time zone) IS 'truncate date according to the specified format'; CREATE FUNCTION plvdate.use_great_friday(bool) RETURNS void AS 'MODULE_PATHNAME','plvdate_use_great_friday' LANGUAGE C VOLATILE STRICT; COMMENT ON FUNCTION plvdate.use_great_friday(bool) IS 'Great Friday will be holiday'; CREATE FUNCTION plvdate.use_great_friday() RETURNS bool AS $$SELECT plvdate.use_great_friday(true); SELECT NULL::boolean;$$ LANGUAGE SQL VOLATILE STRICT; COMMENT ON FUNCTION plvdate.use_great_friday() IS 'Great Friday will be holiday'; CREATE FUNCTION plvdate.unuse_great_friday() RETURNS bool AS $$SELECT plvdate.use_great_friday(false); SELECT NULL::boolean;$$ LANGUAGE SQL VOLATILE STRICT; COMMENT ON FUNCTION plvdate.unuse_great_friday() IS 'Great Friday will not be holiday'; CREATE FUNCTION plvdate.using_great_friday() RETURNS bool AS 'MODULE_PATHNAME','plvdate_using_great_friday' LANGUAGE C VOLATILE STRICT; COMMENT ON FUNCTION plvdate.using_great_friday() IS 'Use Great Friday?'; CREATE OR REPLACE FUNCTION oracle.round(double precision, int) RETURNS numeric AS $$SELECT pg_catalog.round($1::numeric, $2)$$ LANGUAGE sql; CREATE OR REPLACE FUNCTION oracle.trunc(double precision, int) RETURNS numeric AS $$SELECT pg_catalog.trunc($1::numeric, $2)$$ LANGUAGE sql; CREATE OR REPLACE FUNCTION oracle.round(float, int) RETURNS numeric AS $$SELECT pg_catalog.round($1::numeric, $2)$$ LANGUAGE sql; CREATE OR REPLACE FUNCTION oracle.trunc(float, int) RETURNS numeric AS $$SELECT pg_catalog.trunc($1::numeric, $2)$$ LANGUAGE sql; orafce-VERSION_3_9_0/orafce--3.3--3.4.sql000066400000000000000000000005551362147214200172550ustar00rootroot00000000000000/* * Undocumented function wm_concat - removed from * Oracle 12c. */ CREATE FUNCTION pg_catalog.wm_concat_transfn(internal, text) RETURNS internal AS 'MODULE_PATHNAME','orafce_wm_concat_transfn' LANGUAGE C IMMUTABLE; CREATE AGGREGATE pg_catalog.wm_concat(text) ( SFUNC=pg_catalog.wm_concat_transfn, STYPE=internal, FINALFUNC=pg_catalog.listagg_finalfn ); orafce-VERSION_3_9_0/orafce--3.4--3.5.sql000066400000000000000000000004371362147214200172560ustar00rootroot00000000000000update pg_proc set provolatile = 'i' from pg_namespace where pg_namespace.oid = pronamespace and nspname = 'oracle' and proname in ('trunc','round','length','btrim','ltrim','rtrim','lpad','rpad'); update pg_type set typcollation = 100 where typname in ('varchar2', 'nvarchar2'); orafce-VERSION_3_9_0/orafce--3.5--3.6.sql000066400000000000000000000162531362147214200172630ustar00rootroot00000000000000CREATE FUNCTION oracle.get_major_version() RETURNS text AS 'MODULE_PATHNAME','ora_get_major_version' LANGUAGE 'c' STRICT IMMUTABLE; CREATE FUNCTION oracle.get_major_version_num() RETURNS text AS 'MODULE_PATHNAME','ora_get_major_version_num' LANGUAGE 'c' STRICT IMMUTABLE; CREATE FUNCTION oracle.get_full_version_num() RETURNS text AS 'MODULE_PATHNAME','ora_get_full_version_num' LANGUAGE 'c' STRICT IMMUTABLE; CREATE FUNCTION oracle.get_platform() RETURNS text AS 'MODULE_PATHNAME','ora_get_platform' LANGUAGE 'c' STRICT IMMUTABLE; CREATE FUNCTION oracle.get_status() RETURNS text AS 'MODULE_PATHNAME','ora_get_status' LANGUAGE 'c' STRICT IMMUTABLE; -- Oracle system views create view oracle.user_tab_columns as select table_name, column_name, data_type, coalesce(character_maximum_length, numeric_precision) AS data_length, numeric_precision AS data_precision, numeric_scale AS data_scale, is_nullable AS nullable, ordinal_position AS column_id, is_updatable AS data_upgraded, table_schema from information_schema.columns; create view oracle.user_tables as select table_name from information_schema.tables where table_type = 'BASE TABLE'; create view oracle.user_cons_columns as select constraint_name, column_name, table_name from information_schema.constraint_column_usage ; create view oracle.user_constraints as select conname as constraint_name, conindid::regclass as index_name, case contype when 'p' then 'P' when 'f' then 'R' end as constraint_type, relname as table_name, case contype when 'f' then (select conname from pg_constraint c2 where contype = 'p' and c2.conindid = c1.conindid) end as r_constraint_name from pg_constraint c1, pg_class where conrelid = pg_class.oid; create view oracle.product_component_version as select oracle.get_major_version() as product, oracle.get_full_version_num() as version, oracle.get_platform() || ' ' || oracle.get_status() as status union all select extname, case when extname = 'plpgsql' then oracle.get_full_version_num() else extversion end, oracle.get_platform() || ' ' || oracle.get_status() from pg_extension; create view oracle.user_objects as select relname as object_name, null::text as subject_name, c.oid as object_id, case relkind when 'r' then 'TABLE' when 'i' then 'INDEX' when 'S' then 'SEQUENCE' when 'v' then 'VIEW' when 'm' then 'VIEW' when 'f' then 'FOREIGN TABLE' end as object_type, null::timestamp(0) as created, null::timestamp(0) as last_ddl_time, case when relkind = 'i' then (select case when indisvalid then 'VALID' else 'INVALID' end from pg_index where indexrelid = c.oid) else case when relispopulated then 'VALID' else 'INVALID' end end as status, relnamespace as namespace from pg_class c join pg_namespace n on c.relnamespace = n.oid where relkind not in ('t','c') and nspname not in ('pg_toast','pg_catalog','information_schema') union all select tgname, null, t.oid, 'TRIGGER',null, null,'VALID', relnamespace from pg_trigger t join pg_class c on t.tgrelid = c.oid where not tgisinternal union all select proname, null, p.oid, 'FUNCTION', null, null, 'VALID', pronamespace from pg_proc p join pg_namespace n on p.pronamespace = n.oid where nspname not in ('pg_toast','pg_catalog','information_schema') order by 1; create view oracle.user_procedures as select proname as object_name from pg_proc p join pg_namespace n on p.pronamespace = n.oid and nspname <> 'pg_catalog'; create view oracle.user_source as select row_number() over (partition by oid) as line, * from ( select oid, unnest(string_to_array(prosrc, e'\n')) as text, proname as name, 'FUNCTION'::text as type from pg_proc) s; create view oracle.user_views as select c.relname as view_name, pg_catalog.pg_get_userbyid(c.relowner) as owner from pg_catalog.pg_class c left join pg_catalog.pg_namespace n on n.oid = c.relnamespace where c.relkind in ('v','') and n.nspname <> 'pg_catalog' and n.nspname <> 'information_schema' and n.nspname !~ '^pg_toast' and pg_catalog.pg_table_is_visible(c.oid); create view oracle.user_ind_columns as select attname as column_name, c1.relname as index_name, c2.relname as table_name from (select unnest(indkey) attno, indexrelid, indrelid from pg_index) s join pg_attribute on attno = attnum and attrelid = indrelid join pg_class c1 on indexrelid = c1.oid join pg_class c2 on indrelid = c2.oid join pg_namespace n on c2.relnamespace = n.oid where attno > 0 and nspname not in ('pg_catalog','information_schema'); CREATE VIEW oracle.dba_segments AS SELECT pg_namespace.nspname AS owner, pg_class.relname AS segment_name, CASE WHEN pg_class.relkind = 'r' THEN CAST( 'TABLE' AS VARCHAR( 18 ) ) WHEN pg_class.relkind = 'i' THEN CAST( 'INDEX' AS VARCHAR( 18 ) ) WHEN pg_class.relkind = 'f' THEN CAST( 'FOREIGN TABLE' AS VARCHAR( 18 ) ) WHEN pg_class.relkind = 'S' THEN CAST( 'SEQUENCE' AS VARCHAR( 18 ) ) WHEN pg_class.relkind = 's' THEN CAST( 'SPECIAL' AS VARCHAR( 18 ) ) WHEN pg_class.relkind = 't' THEN CAST( 'TOAST TABLE' AS VARCHAR( 18 ) ) WHEN pg_class.relkind = 'v' THEN CAST( 'VIEW' AS VARCHAR( 18 ) ) ELSE CAST( pg_class.relkind AS VARCHAR( 18 ) ) END AS segment_type, spcname AS tablespace_name, relfilenode AS header_file, NULL::oid AS header_block, pg_relation_size( pg_class.oid ) AS bytes, relpages AS blocks FROM pg_class INNER JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid LEFT OUTER JOIN pg_tablespace ON pg_class.reltablespace = pg_tablespace.oid WHERE pg_class.relkind not in ('f','S','v'); -- Oracle dirty functions CREATE OR REPLACE FUNCTION oracle.lpad(int, int, int) RETURNS text AS $$ SELECT pg_catalog.lpad($1::text,$2,$3::text) $$ LANGUAGE sql IMMUTABLE STRICT; CREATE OR REPLACE FUNCTION oracle.lpad(bigint, int, int) RETURNS text AS $$ SELECT pg_catalog.lpad($1::text,$2,$3::text) $$ LANGUAGE sql IMMUTABLE STRICT; CREATE OR REPLACE FUNCTION oracle.lpad(smallint, int, int) RETURNS text AS $$ SELECT pg_catalog.lpad($1::text,$2,$3::text) $$ LANGUAGE sql IMMUTABLE STRICT; CREATE OR REPLACE FUNCTION oracle.lpad(numeric, int, int) RETURNS text AS $$ SELECT pg_catalog.lpad($1::text,$2,$3::text) $$ LANGUAGE sql IMMUTABLE STRICT; CREATE OR REPLACE FUNCTION oracle.nvl(bigint, int) RETURNS bigint AS $$ SELECT coalesce($1, $2) $$ LANGUAGE sql IMMUTABLE; CREATE OR REPLACE FUNCTION oracle.nvl(numeric, int) RETURNS numeric AS $$ SELECT coalesce($1, $2) $$ LANGUAGE sql IMMUTABLE; orafce-VERSION_3_9_0/orafce--3.6--3.7.sql000066400000000000000000000032241362147214200172570ustar00rootroot00000000000000-- bugfixes GRANT USAGE ON SCHEMA oracle TO PUBLIC; GRANT USAGE ON SCHEMA plunit TO PUBLIC; CREATE OR REPLACE FUNCTION oracle.round(float4, int) RETURNS numeric AS $$SELECT pg_catalog.round($1::numeric, $2)$$ LANGUAGE sql IMMUTABLE STRICT; CREATE OR REPLACE FUNCTION oracle.trunc(float4, int) RETURNS numeric AS $$SELECT pg_catalog.trunc($1::numeric, $2)$$ LANGUAGE sql IMMUTABLE STRICT; COMMENT ON FUNCTION oracle.sessiontimezone() IS 'Ruturns session time zone'; COMMENT ON FUNCTION oracle.dbtimezone() IS 'Ruturns server time zone (orafce.timezone)'; CREATE OR REPLACE FUNCTION oracle.nvl(bigint, int) RETURNS bigint AS $$ SELECT coalesce($1, $2) $$ LANGUAGE sql IMMUTABLE; CREATE OR REPLACE FUNCTION oracle.nvl(numeric, int) RETURNS numeric AS $$ SELECT coalesce($1, $2) $$ LANGUAGE sql IMMUTABLE; CREATE OR REPLACE FUNCTION oracle.add_months(TIMESTAMP WITH TIME ZONE,INTEGER) RETURNS TIMESTAMP AS $$ SELECT (pg_catalog.add_months($1::pg_catalog.date, $2) + $1::time)::oracle.date; $$ LANGUAGE SQL IMMUTABLE STRICT; -- new functionality CREATE FUNCTION oracle.orafce_concat2(varchar2, varchar2) RETURNS varchar2 AS 'MODULE_PATHNAME','orafce_concat2' LANGUAGE C IMMUTABLE; CREATE FUNCTION oracle.orafce_concat2(nvarchar2, nvarchar2) RETURNS nvarchar2 AS 'MODULE_PATHNAME','orafce_concat2' LANGUAGE C STABLE; CREATE OPERATOR || (procedure = oracle.orafce_concat2, leftarg = varchar2, rightarg = varchar2); CREATE OPERATOR || (procedure = oracle.orafce_concat2, leftarg = nvarchar2, rightarg = nvarchar2); CREATE OR REPLACE FUNCTION oracle.numtodsinterval(double precision, text) RETURNS interval AS $$ SELECT $1 * ('1' || $2)::interval $$ LANGUAGE sql IMMUTABLE STRICT; orafce-VERSION_3_9_0/orafce--3.7--3.8.sql000066400000000000000000000010321362147214200172540ustar00rootroot00000000000000-- bugfixes CREATE OR REPLACE FUNCTION oracle.nvl(int, int) RETURNS int AS $$ SELECT coalesce($1, $2) $$ LANGUAGE sql IMMUTABLE; -- this routine was renamed on PostgreSQL 12, so the wrapping should be -- more complex and more dynamic. CREATE OR REPLACE FUNCTION varchar2_transform(internal) RETURNS internal AS 'MODULE_PATHNAME','orafce_varchar_transform' LANGUAGE C STRICT IMMUTABLE; CREATE OR REPLACE FUNCTION nvarchar2_transform(internal) RETURNS internal AS 'MODULE_PATHNAME','orafce_varchar_transform' LANGUAGE C STRICT IMMUTABLE; orafce-VERSION_3_9_0/orafce--3.8--3.9.sql000066400000000000000000000011711362147214200172620ustar00rootroot00000000000000drop view oracle.user_constraints; create view oracle.user_constraints as select conname as constraint_name, conindid::regclass as index_name, case contype when 'p' then 'P' when 'f' then 'R' end as constraint_type, conrelid::regclass as table_name, case contype when 'f' then (select conname from pg_constraint c2 where contype = 'p' and c2.conindid = c1.conindid) end as r_constraint_name from pg_constraint c1, pg_class where conrelid = pg_class.oid; orafce-VERSION_3_9_0/orafce--3.9.sql000066400000000000000000003253301362147214200167050ustar00rootroot00000000000000/* orafce--3.8.sql */ -- complain if script is sourced in psql, rather than via CREATE EXTENSION \echo Use "CREATE EXTENSION orafce" to load this file. \quit CREATE FUNCTION pg_catalog.trunc(value date, fmt text) RETURNS date AS 'MODULE_PATHNAME','ora_date_trunc' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION pg_catalog.trunc(date,text) IS 'truncate date according to the specified format'; CREATE FUNCTION pg_catalog.round(value date, fmt text) RETURNS date AS 'MODULE_PATHNAME','ora_date_round' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION pg_catalog.round(date, text) IS 'round dates according to the specified format'; CREATE FUNCTION pg_catalog.next_day(value date, weekday text) RETURNS date AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION pg_catalog.next_day (date, text) IS 'returns the first weekday that is greater than a date value'; CREATE FUNCTION pg_catalog.next_day(value date, weekday integer) RETURNS date AS 'MODULE_PATHNAME', 'next_day_by_index' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION pg_catalog.next_day (date, integer) IS 'returns the first weekday that is greater than a date value'; CREATE FUNCTION pg_catalog.last_day(value date) RETURNS date AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION pg_catalog.last_day(date) IS 'returns last day of the month based on a date value'; CREATE FUNCTION pg_catalog.months_between(date1 date, date2 date) RETURNS numeric AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION pg_catalog.months_between(date, date) IS 'returns the number of months between date1 and date2'; CREATE FUNCTION pg_catalog.add_months(day date, value int) RETURNS date AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION pg_catalog.add_months(date, int) IS 'returns date plus n months'; CREATE FUNCTION pg_catalog.trunc(value timestamp with time zone, fmt text) RETURNS timestamp with time zone AS 'MODULE_PATHNAME', 'ora_timestamptz_trunc' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION pg_catalog.trunc(timestamp with time zone, text) IS 'truncate date according to the specified format'; CREATE FUNCTION pg_catalog.round(value timestamp with time zone, fmt text) RETURNS timestamp with time zone AS 'MODULE_PATHNAME','ora_timestamptz_round' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION pg_catalog.round(timestamp with time zone, text) IS 'round dates according to the specified format'; CREATE FUNCTION pg_catalog.round(value timestamp with time zone) RETURNS timestamp with time zone AS $$ SELECT pg_catalog.round($1, 'DDD'); $$ LANGUAGE SQL IMMUTABLE STRICT; COMMENT ON FUNCTION pg_catalog.round(timestamp with time zone) IS 'will round dates according to the specified format'; CREATE FUNCTION pg_catalog.round(value date) RETURNS date AS $$ SELECT $1; $$ LANGUAGE SQL IMMUTABLE STRICT; COMMENT ON FUNCTION pg_catalog.round(value date)IS 'will round dates according to the specified format'; CREATE FUNCTION pg_catalog.trunc(value timestamp with time zone) RETURNS timestamp with time zone AS $$ SELECT pg_catalog.trunc($1, 'DDD'); $$ LANGUAGE SQL IMMUTABLE STRICT; COMMENT ON FUNCTION pg_catalog.trunc(timestamp with time zone) IS 'truncate date according to the specified format'; CREATE FUNCTION pg_catalog.trunc(value date) RETURNS date AS $$ SELECT $1; $$ LANGUAGE SQL IMMUTABLE STRICT; COMMENT ON FUNCTION pg_catalog.trunc(date) IS 'truncate date according to the specified format'; CREATE FUNCTION pg_catalog.nlssort(text, text) RETURNS bytea AS 'MODULE_PATHNAME', 'ora_nlssort' LANGUAGE C IMMUTABLE; COMMENT ON FUNCTION pg_catalog.nlssort(text, text) IS ''; CREATE FUNCTION pg_catalog.nlssort(text) RETURNS bytea AS $$ SELECT pg_catalog.nlssort($1, null); $$ LANGUAGE SQL IMMUTABLE STRICT; COMMENT ON FUNCTION pg_catalog.nlssort(text)IS ''; CREATE FUNCTION pg_catalog.set_nls_sort(text) RETURNS void AS 'MODULE_PATHNAME', 'ora_set_nls_sort' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION pg_catalog.set_nls_sort(text) IS ''; CREATE FUNCTION pg_catalog.instr(str text, patt text, start int, nth int) RETURNS int AS 'MODULE_PATHNAME','plvstr_instr4' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION pg_catalog.instr(text, text, int, int) IS 'Search pattern in string'; CREATE FUNCTION pg_catalog.instr(str text, patt text, start int) RETURNS int AS 'MODULE_PATHNAME','plvstr_instr3' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION pg_catalog.instr(text, text, int) IS 'Search pattern in string'; CREATE FUNCTION pg_catalog.instr(str text, patt text) RETURNS int AS 'MODULE_PATHNAME','plvstr_instr2' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION pg_catalog.instr(text, text) IS 'Search pattern in string'; CREATE FUNCTION pg_catalog.to_char(num smallint) RETURNS text AS 'MODULE_PATHNAME','orafce_to_char_int4' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION pg_catalog.to_char(smallint) IS 'Convert number to string'; CREATE FUNCTION pg_catalog.to_char(num int) RETURNS text AS 'MODULE_PATHNAME','orafce_to_char_int4' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION pg_catalog.to_char(int) IS 'Convert number to string'; CREATE FUNCTION pg_catalog.to_char(num bigint) RETURNS text AS 'MODULE_PATHNAME','orafce_to_char_int8' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION pg_catalog.to_char(bigint) IS 'Convert number to string'; CREATE FUNCTION pg_catalog.to_char(num real) RETURNS text AS 'MODULE_PATHNAME','orafce_to_char_float4' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION pg_catalog.to_char(real) IS 'Convert number to string'; CREATE FUNCTION pg_catalog.to_char(num double precision) RETURNS text AS 'MODULE_PATHNAME','orafce_to_char_float8' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION pg_catalog.to_char(double precision) IS 'Convert number to string'; CREATE FUNCTION pg_catalog.to_char(num numeric) RETURNS text AS 'MODULE_PATHNAME','orafce_to_char_numeric' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION pg_catalog.to_char(numeric) IS 'Convert number to string'; CREATE FUNCTION pg_catalog.to_number(str text) RETURNS numeric AS 'MODULE_PATHNAME','orafce_to_number' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION pg_catalog.to_number(text) IS 'Convert string to number'; CREATE OR REPLACE FUNCTION pg_catalog.to_number(numeric) RETURNS numeric AS $$ SELECT pg_catalog.to_number($1::text); $$ LANGUAGE SQL IMMUTABLE; CREATE OR REPLACE FUNCTION pg_catalog.to_number(numeric,numeric) RETURNS numeric AS $$ SELECT pg_catalog.to_number($1::text,$2::text); $$ LANGUAGE SQL IMMUTABLE; CREATE FUNCTION pg_catalog.to_date(str text) RETURNS timestamp AS 'MODULE_PATHNAME','ora_to_date' LANGUAGE C STABLE STRICT; COMMENT ON FUNCTION pg_catalog.to_date(text) IS 'Convert string to timestamp'; CREATE FUNCTION to_multi_byte(str text) RETURNS text AS 'MODULE_PATHNAME','orafce_to_multi_byte' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION to_multi_byte(text) IS 'Convert all single-byte characters to their corresponding multibyte characters'; CREATE FUNCTION to_single_byte(str text) RETURNS text AS 'MODULE_PATHNAME','orafce_to_single_byte' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION to_single_byte(text) IS 'Convert characters to their corresponding single-byte characters if possible'; CREATE FUNCTION bitand(bigint, bigint) RETURNS bigint AS $$ SELECT $1 & $2; $$ LANGUAGE sql IMMUTABLE STRICT; CREATE FUNCTION sinh(float8) RETURNS float8 AS $$ SELECT (exp($1) - exp(-$1)) / 2; $$ LANGUAGE sql IMMUTABLE STRICT; CREATE FUNCTION cosh(float8) RETURNS float8 AS $$ SELECT (exp($1) + exp(-$1)) / 2; $$ LANGUAGE sql IMMUTABLE STRICT; CREATE FUNCTION tanh(float8) RETURNS float8 AS $$ SELECT sinh($1) / cosh($1); $$ LANGUAGE sql IMMUTABLE STRICT; CREATE FUNCTION nanvl(float4, float4) RETURNS float4 AS $$ SELECT CASE WHEN $1 = 'NaN' THEN $2 ELSE $1 END; $$ LANGUAGE sql IMMUTABLE STRICT; CREATE FUNCTION nanvl(float8, float8) RETURNS float8 AS $$ SELECT CASE WHEN $1 = 'NaN' THEN $2 ELSE $1 END; $$ LANGUAGE sql IMMUTABLE STRICT; CREATE FUNCTION nanvl(numeric, numeric) RETURNS numeric AS $$ SELECT CASE WHEN $1 = 'NaN' THEN $2 ELSE $1 END; $$ LANGUAGE sql IMMUTABLE STRICT; CREATE FUNCTION nanvl(float4, varchar) RETURNS float4 AS $$ SELECT CASE WHEN $1 = 'NaN' THEN $2::float4 ELSE $1 END; $$ LANGUAGE sql IMMUTABLE STRICT; CREATE FUNCTION nanvl(float8, varchar) RETURNS float8 AS $$ SELECT CASE WHEN $1 = 'NaN' THEN $2::float8 ELSE $1 END; $$ LANGUAGE sql IMMUTABLE STRICT; CREATE FUNCTION nanvl(numeric, varchar) RETURNS numeric AS $$ SELECT CASE WHEN $1 = 'NaN' THEN $2::numeric ELSE $1 END; $$ LANGUAGE sql IMMUTABLE STRICT; CREATE FUNCTION dump("any") RETURNS varchar AS 'MODULE_PATHNAME', 'orafce_dump' LANGUAGE C; CREATE FUNCTION dump("any", integer) RETURNS varchar AS 'MODULE_PATHNAME', 'orafce_dump' LANGUAGE C; CREATE SCHEMA plvstr; CREATE FUNCTION plvstr.rvrs(str text, start int, _end int) RETURNS text AS 'MODULE_PATHNAME','plvstr_rvrs' LANGUAGE C IMMUTABLE; COMMENT ON FUNCTION plvstr.rvrs(text, int, int) IS 'Reverse string or part of string'; CREATE FUNCTION plvstr.rvrs(str text, start int) RETURNS text AS $$ SELECT plvstr.rvrs($1,$2,NULL);$$ LANGUAGE SQL IMMUTABLE STRICT; COMMENT ON FUNCTION plvstr.rvrs(text, int) IS 'Reverse string or part of string'; CREATE FUNCTION plvstr.rvrs(str text) RETURNS text AS $$ SELECT plvstr.rvrs($1,1,NULL);$$ LANGUAGE SQL IMMUTABLE STRICT; COMMENT ON FUNCTION plvstr.rvrs(text) IS 'Reverse string or part of string'; CREATE FUNCTION pg_catalog.lnnvl(bool) RETURNS bool AS 'MODULE_PATHNAME','ora_lnnvl' LANGUAGE C IMMUTABLE; COMMENT ON FUNCTION pg_catalog.lnnvl(bool) IS ''; -- can't overwrite PostgreSQL functions!!!! CREATE SCHEMA oracle; CREATE FUNCTION oracle.substr(str text, start int) RETURNS text AS 'MODULE_PATHNAME','oracle_substr2' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION oracle.substr(text, int) IS 'Returns substring started on start_in to end'; CREATE FUNCTION oracle.substr(str text, start int, len int) RETURNS text AS 'MODULE_PATHNAME','oracle_substr3' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION oracle.substr(text, int, int) IS 'Returns substring started on start_in len chars'; CREATE OR REPLACE FUNCTION oracle.substr(numeric,numeric) RETURNS text AS $$ SELECT oracle.substr($1::text,trunc($2)::int); $$ LANGUAGE SQL IMMUTABLE; CREATE OR REPLACE FUNCTION oracle.substr(numeric,numeric,numeric) RETURNS text AS $$ SELECT oracle.substr($1::text,trunc($2)::int,trunc($3)::int); $$ LANGUAGE SQL IMMUTABLE; CREATE OR REPLACE FUNCTION oracle.substr(varchar,numeric) RETURNS text AS $$ SELECT oracle.substr($1,trunc($2)::int); $$ LANGUAGE SQL IMMUTABLE; CREATE OR REPLACE FUNCTION oracle.substr(varchar,numeric,numeric) RETURNS text AS $$ SELECT oracle.substr($1,trunc($2)::int,trunc($3)::int); $$ LANGUAGE SQL IMMUTABLE; --can't overwrite PostgreSQL DATE data type!!! CREATE DOMAIN oracle.date AS timestamp(0); CREATE OR REPLACE FUNCTION oracle.add_days_to_timestamp(oracle.date,integer) RETURNS timestamp AS $$ SELECT $1 + interval '1 day' * $2; $$ LANGUAGE SQL IMMUTABLE; CREATE OR REPLACE FUNCTION oracle.subtract (oracle.date, integer) RETURNS timestamp AS $$ SELECT $1 - interval '1 day' * $2; $$ LANGUAGE SQL IMMUTABLE; CREATE OR REPLACE FUNCTION oracle.add_days_to_timestamp(oracle.date,bigint) RETURNS timestamp AS $$ SELECT $1 + interval '1 day' * $2; $$ LANGUAGE SQL IMMUTABLE; CREATE OR REPLACE FUNCTION oracle.subtract (oracle.date, bigint) RETURNS timestamp AS $$ SELECT $1 - interval '1 day' * $2; $$ LANGUAGE SQL IMMUTABLE; CREATE OR REPLACE FUNCTION oracle.add_days_to_timestamp(oracle.date,smallint) RETURNS timestamp AS $$ SELECT $1 + interval '1 day' * $2; $$ LANGUAGE SQL IMMUTABLE; CREATE OR REPLACE FUNCTION oracle.subtract (oracle.date, smallint) RETURNS timestamp AS $$ SELECT $1 - interval '1 day' * $2; $$ LANGUAGE SQL IMMUTABLE; CREATE OR REPLACE FUNCTION oracle.add_days_to_timestamp(oracle.date,numeric) RETURNS timestamp AS $$ SELECT $1 + interval '1 day' * $2; $$ LANGUAGE SQL IMMUTABLE; CREATE OR REPLACE FUNCTION oracle.subtract (oracle.date, numeric) RETURNS timestamp AS $$ SELECT $1 - interval '1 day' * $2; $$ LANGUAGE SQL IMMUTABLE; CREATE OR REPLACE FUNCTION oracle.subtract(oracle.date,oracle.date) RETURNS double precision AS $$ SELECT date_part('epoch', ($1::timestamp - $2::timestamp)/3600/24); $$ LANGUAGE SQL IMMUTABLE; CREATE OPERATOR oracle.+ ( LEFTARG = oracle.date, RIGHTARG = INTEGER, PROCEDURE = oracle.add_days_to_timestamp ); CREATE OPERATOR oracle.- ( LEFTARG = oracle.date, RIGHTARG = INTEGER, PROCEDURE = oracle.subtract ); CREATE OPERATOR oracle.+ ( LEFTARG = oracle.date, RIGHTARG = bigint, PROCEDURE = oracle.add_days_to_timestamp ); CREATE OPERATOR oracle.- ( LEFTARG = oracle.date, RIGHTARG = bigint, PROCEDURE = oracle.subtract ); CREATE OPERATOR oracle.+ ( LEFTARG = oracle.date, RIGHTARG = smallint, PROCEDURE = oracle.add_days_to_timestamp ); CREATE OPERATOR oracle.- ( LEFTARG = oracle.date, RIGHTARG = smallint, PROCEDURE = oracle.subtract ); CREATE OPERATOR oracle.+ ( LEFTARG = oracle.date, RIGHTARG = numeric, PROCEDURE = oracle.add_days_to_timestamp ); CREATE OPERATOR oracle.- ( LEFTARG = oracle.date, RIGHTARG = numeric, PROCEDURE = oracle.subtract ); CREATE OPERATOR oracle.- ( LEFTARG = oracle.date, RIGHTARG = oracle.date, PROCEDURE = oracle.subtract ); CREATE FUNCTION oracle.add_months(TIMESTAMP WITH TIME ZONE,INTEGER) RETURNS TIMESTAMP AS $$ SELECT (pg_catalog.add_months($1::pg_catalog.date, $2) + $1::time)::oracle.date; $$ LANGUAGE SQL IMMUTABLE STRICT; CREATE OR REPLACE FUNCTION oracle.last_day(TIMESTAMPTZ) RETURNS TIMESTAMP AS $$ SELECT (date_trunc('MONTH', $1) + INTERVAL '1 MONTH - 1 day' + $1::time)::oracle.date; $$ LANGUAGE SQL IMMUTABLE STRICT; CREATE FUNCTION oracle.months_between(TIMESTAMP WITH TIME ZONE,TIMESTAMP WITH TIME ZONE) RETURNS NUMERIC AS $$ SELECT pg_catalog.months_between($1::pg_catalog.date,$2::pg_catalog.date); $$ LANGUAGE SQL IMMUTABLE STRICT; CREATE FUNCTION oracle.next_day(TIMESTAMP WITH TIME ZONE,INTEGER) RETURNS TIMESTAMP AS $$ SELECT (pg_catalog.next_day($1::pg_catalog.date,$2) + $1::time)::oracle.date; $$ LANGUAGE SQL IMMUTABLE STRICT; CREATE FUNCTION oracle.next_day(TIMESTAMP WITH TIME ZONE,TEXT) RETURNS TIMESTAMP AS $$ SELECT (pg_catalog.next_day($1::pg_catalog.date,$2) + $1::time)::oracle.date; $$ LANGUAGE SQL IMMUTABLE STRICT; CREATE FUNCTION oracle.to_date(TEXT) RETURNS oracle.date AS $$ SELECT pg_catalog.to_date($1)::oracle.date; $$ LANGUAGE SQL STABLE STRICT; CREATE OR REPLACE FUNCTION oracle.to_date(TEXT,TEXT) RETURNS oracle.date AS $$ SELECT TO_TIMESTAMP($1,$2)::oracle.date; $$ LANGUAGE SQL IMMUTABLE STRICT; CREATE FUNCTION oracle.to_char(timestamp) RETURNS TEXT AS 'MODULE_PATHNAME','orafce_to_char_timestamp' LANGUAGE C STABLE STRICT; COMMENT ON FUNCTION oracle.to_char(timestamp) IS 'Convert timestamp to string'; CREATE FUNCTION oracle.sysdate() RETURNS oracle.date AS 'MODULE_PATHNAME','orafce_sysdate' LANGUAGE C STABLE STRICT; COMMENT ON FUNCTION oracle.sysdate() IS 'Ruturns statement timestamp at server time zone'; CREATE FUNCTION oracle.sessiontimezone() RETURNS text AS 'MODULE_PATHNAME','orafce_sessiontimezone' LANGUAGE C STABLE STRICT; COMMENT ON FUNCTION oracle.sessiontimezone() IS 'Ruturns session time zone'; CREATE FUNCTION oracle.dbtimezone() RETURNS text AS 'MODULE_PATHNAME','orafce_dbtimezone' LANGUAGE C STABLE STRICT; COMMENT ON FUNCTION oracle.dbtimezone() IS 'Ruturns server time zone (orafce.timezone)'; -- emulation of dual table CREATE VIEW public.dual AS SELECT 'X'::varchar AS dummy; REVOKE ALL ON public.dual FROM PUBLIC; GRANT SELECT, REFERENCES ON public.dual TO PUBLIC; -- this packege is emulation of dbms_output Oracle packege -- CREATE SCHEMA dbms_output; CREATE FUNCTION dbms_output.enable(IN buffer_size int4) RETURNS void AS 'MODULE_PATHNAME','dbms_output_enable' LANGUAGE C VOLATILE; COMMENT ON FUNCTION dbms_output.enable(IN int4) IS 'Enable package functionality'; CREATE FUNCTION dbms_output.enable() RETURNS void AS 'MODULE_PATHNAME','dbms_output_enable_default' LANGUAGE C VOLATILE STRICT; COMMENT ON FUNCTION dbms_output.enable() IS 'Enable package functionality'; CREATE FUNCTION dbms_output.disable() RETURNS void AS 'MODULE_PATHNAME','dbms_output_disable' LANGUAGE C VOLATILE STRICT; COMMENT ON FUNCTION dbms_output.disable() IS 'Disable package functionality'; CREATE FUNCTION dbms_output.serveroutput(IN bool) RETURNS void AS 'MODULE_PATHNAME','dbms_output_serveroutput' LANGUAGE C VOLATILE STRICT; COMMENT ON FUNCTION dbms_output.serveroutput(IN bool) IS 'Set drowing output'; CREATE FUNCTION dbms_output.put(IN a text) RETURNS void AS 'MODULE_PATHNAME','dbms_output_put' LANGUAGE C VOLATILE STRICT; COMMENT ON FUNCTION dbms_output.put(IN text) IS 'Put some text to output'; CREATE FUNCTION dbms_output.put_line(IN a text) RETURNS void AS 'MODULE_PATHNAME','dbms_output_put_line' LANGUAGE C VOLATILE STRICT; COMMENT ON FUNCTION dbms_output.put_line(IN text) IS 'Put line to output'; CREATE FUNCTION dbms_output.new_line() RETURNS void AS 'MODULE_PATHNAME','dbms_output_new_line' LANGUAGE C VOLATILE STRICT; COMMENT ON FUNCTION dbms_output.new_line() IS 'Put new line char to output'; CREATE FUNCTION dbms_output.get_line(OUT line text, OUT status int4) AS 'MODULE_PATHNAME','dbms_output_get_line' LANGUAGE C VOLATILE STRICT; COMMENT ON FUNCTION dbms_output.get_line(OUT text, OUT int4) IS 'Get line from output buffer'; CREATE FUNCTION dbms_output.get_lines(OUT lines text[], INOUT numlines int4) AS 'MODULE_PATHNAME','dbms_output_get_lines' LANGUAGE C VOLATILE STRICT; COMMENT ON FUNCTION dbms_output.get_lines(OUT text[], INOUT int4) IS 'Get lines from output buffer'; -- others functions CREATE FUNCTION nvl(anyelement, anyelement) RETURNS anyelement AS 'MODULE_PATHNAME','ora_nvl' LANGUAGE C IMMUTABLE; CREATE FUNCTION nvl2(anyelement, anyelement, anyelement) RETURNS anyelement AS 'MODULE_PATHNAME','ora_nvl2' LANGUAGE C IMMUTABLE; COMMENT ON FUNCTION nvl2(anyelement, anyelement, anyelement) IS ''; CREATE FUNCTION public.decode(anyelement, anyelement, text) RETURNS text AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, text, text) RETURNS text AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, text, anyelement, text) RETURNS text AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, text, anyelement, text, text) RETURNS text AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, text, anyelement, text, anyelement, text) RETURNS text AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, text, anyelement, text, anyelement, text, text) RETURNS text AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, bpchar) RETURNS bpchar AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, bpchar, bpchar) RETURNS bpchar AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, bpchar, anyelement, bpchar) RETURNS bpchar AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, bpchar, anyelement, bpchar, bpchar) RETURNS bpchar AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, bpchar, anyelement, bpchar, anyelement, bpchar) RETURNS bpchar AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, bpchar, anyelement, bpchar, anyelement, bpchar, bpchar) RETURNS bpchar AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, integer) RETURNS integer AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, integer, integer) RETURNS integer AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, integer, anyelement, integer) RETURNS integer AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, integer, anyelement, integer, integer) RETURNS integer AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, integer, anyelement, integer, anyelement, integer) RETURNS integer AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, integer, anyelement, integer, anyelement, integer, integer) RETURNS integer AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, bigint) RETURNS bigint AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, bigint, bigint) RETURNS bigint AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, bigint, anyelement, bigint) RETURNS bigint AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, bigint, anyelement, bigint, bigint) RETURNS bigint AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, bigint, anyelement, bigint, anyelement, bigint) RETURNS bigint AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, bigint, anyelement, bigint, anyelement, bigint, bigint) RETURNS bigint AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, numeric) RETURNS numeric AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, numeric, numeric) RETURNS numeric AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, numeric, anyelement, numeric) RETURNS numeric AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, numeric, anyelement, numeric, numeric) RETURNS numeric AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, numeric, anyelement, numeric, anyelement, numeric) RETURNS numeric AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, numeric, anyelement, numeric, anyelement, numeric, numeric) RETURNS numeric AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, date) RETURNS date AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, date, date) RETURNS date AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, date, anyelement, date) RETURNS date AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, date, anyelement, date, date) RETURNS date AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, date, anyelement, date, anyelement, date) RETURNS date AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, date, anyelement, date, anyelement, date, date) RETURNS date AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, time) RETURNS time AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, time, time) RETURNS time AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, time, anyelement, time) RETURNS time AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, time, anyelement, time, time) RETURNS time AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, time, anyelement, time, anyelement, time) RETURNS time AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, time, anyelement, time, anyelement, time, time) RETURNS time AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, timestamp) RETURNS timestamp AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, timestamp, timestamp) RETURNS timestamp AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, timestamp, anyelement, timestamp) RETURNS timestamp AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, timestamp, anyelement, timestamp, timestamp) RETURNS timestamp AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, timestamp, anyelement, timestamp, anyelement, timestamp) RETURNS timestamp AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, timestamp, anyelement, timestamp, anyelement, timestamp, timestamp) RETURNS timestamp AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, timestamptz) RETURNS timestamptz AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, timestamptz, timestamptz) RETURNS timestamptz AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, timestamptz, anyelement, timestamptz) RETURNS timestamptz AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, timestamptz, anyelement, timestamptz, timestamptz) RETURNS timestamptz AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, timestamptz, anyelement, timestamptz, anyelement, timestamptz) RETURNS timestamptz AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.decode(anyelement, anyelement, timestamptz, anyelement, timestamptz, anyelement, timestamptz, timestamptz) RETURNS timestamptz AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE; CREATE SCHEMA dbms_pipe; CREATE FUNCTION dbms_pipe.pack_message(text) RETURNS void AS 'MODULE_PATHNAME','dbms_pipe_pack_message_text' LANGUAGE C VOLATILE STRICT; COMMENT ON FUNCTION dbms_pipe.pack_message(text) IS 'Add text field to message'; CREATE FUNCTION dbms_pipe.unpack_message_text() RETURNS text AS 'MODULE_PATHNAME','dbms_pipe_unpack_message_text' LANGUAGE C VOLATILE; COMMENT ON FUNCTION dbms_pipe.unpack_message_text() IS 'Get text fiedl from message'; CREATE FUNCTION dbms_pipe.receive_message(text, int) RETURNS int AS 'MODULE_PATHNAME','dbms_pipe_receive_message' LANGUAGE C VOLATILE; COMMENT ON FUNCTION dbms_pipe.receive_message(text, int) IS 'Receive message from pipe'; CREATE FUNCTION dbms_pipe.receive_message(text) RETURNS int AS $$SELECT dbms_pipe.receive_message($1,NULL::int);$$ LANGUAGE SQL VOLATILE; COMMENT ON FUNCTION dbms_pipe.receive_message(text) IS 'Receive message from pipe'; CREATE FUNCTION dbms_pipe.send_message(text, int, int) RETURNS int AS 'MODULE_PATHNAME','dbms_pipe_send_message' LANGUAGE C VOLATILE; COMMENT ON FUNCTION dbms_pipe.send_message(text, int, int) IS 'Send message to pipe'; CREATE FUNCTION dbms_pipe.send_message(text, int) RETURNS int AS $$SELECT dbms_pipe.send_message($1,$2,NULL);$$ LANGUAGE SQL VOLATILE; COMMENT ON FUNCTION dbms_pipe.send_message(text, int) IS 'Send message to pipe'; CREATE FUNCTION dbms_pipe.send_message(text) RETURNS int AS $$SELECT dbms_pipe.send_message($1,NULL,NULL);$$ LANGUAGE SQL VOLATILE; COMMENT ON FUNCTION dbms_pipe.send_message(text) IS 'Send message to pipe'; CREATE FUNCTION dbms_pipe.unique_session_name() RETURNS varchar AS 'MODULE_PATHNAME','dbms_pipe_unique_session_name' LANGUAGE C VOLATILE STRICT; COMMENT ON FUNCTION dbms_pipe.unique_session_name() IS 'Returns unique session name'; CREATE FUNCTION dbms_pipe.__list_pipes() RETURNS SETOF RECORD AS 'MODULE_PATHNAME','dbms_pipe_list_pipes' LANGUAGE C VOLATILE STRICT; COMMENT ON FUNCTION dbms_pipe.__list_pipes() IS ''; CREATE VIEW dbms_pipe.db_pipes AS SELECT * FROM dbms_pipe.__list_pipes() AS (Name varchar, Items int, Size int, "limit" int, "private" bool, "owner" varchar); CREATE FUNCTION dbms_pipe.next_item_type() RETURNS int AS 'MODULE_PATHNAME','dbms_pipe_next_item_type' LANGUAGE C VOLATILE STRICT; COMMENT ON FUNCTION dbms_pipe.next_item_type() IS 'Returns type of next field in message'; CREATE FUNCTION dbms_pipe.create_pipe(text, int, bool) RETURNS void AS 'MODULE_PATHNAME','dbms_pipe_create_pipe' LANGUAGE C VOLATILE; COMMENT ON FUNCTION dbms_pipe.create_pipe(text, int, bool) IS 'Create named pipe'; CREATE FUNCTION dbms_pipe.create_pipe(text, int) RETURNS void AS 'MODULE_PATHNAME','dbms_pipe_create_pipe_2' LANGUAGE C VOLATILE; COMMENT ON FUNCTION dbms_pipe.create_pipe(text, int) IS 'Create named pipe'; CREATE FUNCTION dbms_pipe.create_pipe(text) RETURNS void AS 'MODULE_PATHNAME','dbms_pipe_create_pipe_1' LANGUAGE C VOLATILE; COMMENT ON FUNCTION dbms_pipe.create_pipe(text) IS 'Create named pipe'; CREATE FUNCTION dbms_pipe.reset_buffer() RETURNS void AS 'MODULE_PATHNAME','dbms_pipe_reset_buffer' LANGUAGE C VOLATILE; COMMENT ON FUNCTION dbms_pipe.reset_buffer() IS 'Clean input buffer'; CREATE FUNCTION dbms_pipe.purge(text) RETURNS void AS 'MODULE_PATHNAME','dbms_pipe_purge' LANGUAGE C VOLATILE STRICT; COMMENT ON FUNCTION dbms_pipe.purge(text) IS 'Clean pipe'; CREATE FUNCTION dbms_pipe.remove_pipe(text) RETURNS void AS 'MODULE_PATHNAME','dbms_pipe_remove_pipe' LANGUAGE C VOLATILE STRICT; COMMENT ON FUNCTION dbms_pipe.remove_pipe(text) IS 'Destroy pipe'; CREATE FUNCTION dbms_pipe.pack_message(date) RETURNS void AS 'MODULE_PATHNAME','dbms_pipe_pack_message_date' LANGUAGE C VOLATILE STRICT; COMMENT ON FUNCTION dbms_pipe.pack_message(date) IS 'Add date field to message'; CREATE FUNCTION dbms_pipe.unpack_message_date() RETURNS date AS 'MODULE_PATHNAME','dbms_pipe_unpack_message_date' LANGUAGE C VOLATILE STRICT; COMMENT ON FUNCTION dbms_pipe.unpack_message_date() IS 'Get date field from message'; CREATE FUNCTION dbms_pipe.pack_message(timestamp with time zone) RETURNS void AS 'MODULE_PATHNAME','dbms_pipe_pack_message_timestamp' LANGUAGE C VOLATILE STRICT; COMMENT ON FUNCTION dbms_pipe.pack_message(timestamp with time zone) IS 'Add timestamp field to message'; CREATE FUNCTION dbms_pipe.unpack_message_timestamp() RETURNS timestamp with time zone AS 'MODULE_PATHNAME','dbms_pipe_unpack_message_timestamp' LANGUAGE C VOLATILE STRICT; COMMENT ON FUNCTION dbms_pipe.unpack_message_timestamp() IS 'Get timestamp field from message'; CREATE FUNCTION dbms_pipe.pack_message(numeric) RETURNS void AS 'MODULE_PATHNAME','dbms_pipe_pack_message_number' LANGUAGE C VOLATILE STRICT; COMMENT ON FUNCTION dbms_pipe.pack_message(numeric) IS 'Add numeric field to message'; CREATE FUNCTION dbms_pipe.unpack_message_number() RETURNS numeric AS 'MODULE_PATHNAME','dbms_pipe_unpack_message_number' LANGUAGE C VOLATILE STRICT; COMMENT ON FUNCTION dbms_pipe.unpack_message_number() IS 'Get numeric field from message'; CREATE FUNCTION dbms_pipe.pack_message(integer) RETURNS void AS 'MODULE_PATHNAME','dbms_pipe_pack_message_integer' LANGUAGE C VOLATILE STRICT; COMMENT ON FUNCTION dbms_pipe.pack_message(integer) IS 'Add numeric field to message'; CREATE FUNCTION dbms_pipe.pack_message(bigint) RETURNS void AS 'MODULE_PATHNAME','dbms_pipe_pack_message_bigint' LANGUAGE C VOLATILE STRICT; COMMENT ON FUNCTION dbms_pipe.pack_message(bigint) IS 'Add numeric field to message'; CREATE FUNCTION dbms_pipe.pack_message(bytea) RETURNS void AS 'MODULE_PATHNAME','dbms_pipe_pack_message_bytea' LANGUAGE C VOLATILE STRICT; COMMENT ON FUNCTION dbms_pipe.pack_message(bytea) IS 'Add bytea field to message'; CREATE FUNCTION dbms_pipe.unpack_message_bytea() RETURNS bytea AS 'MODULE_PATHNAME','dbms_pipe_unpack_message_bytea' LANGUAGE C VOLATILE STRICT; COMMENT ON FUNCTION dbms_pipe.unpack_message_bytea() IS 'Get bytea field from message'; CREATE FUNCTION dbms_pipe.pack_message(record) RETURNS void AS 'MODULE_PATHNAME','dbms_pipe_pack_message_record' LANGUAGE C VOLATILE STRICT; COMMENT ON FUNCTION dbms_pipe.pack_message(record) IS 'Add record field to message'; CREATE FUNCTION dbms_pipe.unpack_message_record() RETURNS record AS 'MODULE_PATHNAME','dbms_pipe_unpack_message_record' LANGUAGE C VOLATILE STRICT; COMMENT ON FUNCTION dbms_pipe.unpack_message_record() IS 'Get record field from message'; -- follow package PLVdate emulation CREATE SCHEMA plvdate; CREATE FUNCTION plvdate.add_bizdays(date, int) RETURNS date AS 'MODULE_PATHNAME','plvdate_add_bizdays' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION plvdate.add_bizdays(date, int) IS 'Get the date created by adding business days to a date'; CREATE FUNCTION plvdate.nearest_bizday(date) RETURNS date AS 'MODULE_PATHNAME','plvdate_nearest_bizday' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION plvdate.nearest_bizday(date) IS 'Get the nearest business date to a given date, user defined'; CREATE FUNCTION plvdate.next_bizday(date) RETURNS date AS 'MODULE_PATHNAME','plvdate_next_bizday' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION plvdate.next_bizday(date) IS 'Get the next business date from a given date, user defined'; CREATE FUNCTION plvdate.bizdays_between(date, date) RETURNS int AS 'MODULE_PATHNAME','plvdate_bizdays_between' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION plvdate.bizdays_between(date, date) IS 'Get the number of business days between two dates'; CREATE FUNCTION plvdate.prev_bizday(date) RETURNS date AS 'MODULE_PATHNAME','plvdate_prev_bizday' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION plvdate.prev_bizday(date) IS 'Get the previous business date from a given date'; CREATE FUNCTION plvdate.isbizday(date) RETURNS bool AS 'MODULE_PATHNAME','plvdate_isbizday' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION plvdate.isbizday(date) IS 'Call this function to determine if a date is a business day'; CREATE FUNCTION plvdate.set_nonbizday(text) RETURNS void AS 'MODULE_PATHNAME','plvdate_set_nonbizday_dow' LANGUAGE C VOLATILE STRICT; COMMENT ON FUNCTION plvdate.set_nonbizday(text) IS 'Set day of week as non bussines day'; CREATE FUNCTION plvdate.unset_nonbizday(text) RETURNS void AS 'MODULE_PATHNAME','plvdate_unset_nonbizday_dow' LANGUAGE C VOLATILE STRICT; COMMENT ON FUNCTION plvdate.unset_nonbizday(text) IS 'Unset day of week as non bussines day'; CREATE FUNCTION plvdate.set_nonbizday(date, bool) RETURNS void AS 'MODULE_PATHNAME','plvdate_set_nonbizday_day' LANGUAGE C VOLATILE STRICT; COMMENT ON FUNCTION plvdate.set_nonbizday(date, bool) IS 'Set day as non bussines day, if repeat is true, then day is nonbiz every year'; CREATE FUNCTION plvdate.unset_nonbizday(date, bool) RETURNS void AS 'MODULE_PATHNAME','plvdate_unset_nonbizday_day' LANGUAGE C VOLATILE STRICT; COMMENT ON FUNCTION plvdate.unset_nonbizday(date, bool) IS 'Unset day as non bussines day, if repeat is true, then day is nonbiz every year'; CREATE FUNCTION plvdate.set_nonbizday(date) RETURNS bool AS $$SELECT plvdate.set_nonbizday($1, false); SELECT NULL::boolean;$$ LANGUAGE SQL VOLATILE STRICT; COMMENT ON FUNCTION plvdate.set_nonbizday(date) IS 'Set day as non bussines day'; CREATE FUNCTION plvdate.unset_nonbizday(date) RETURNS bool AS $$SELECT plvdate.unset_nonbizday($1, false); SELECT NULL::boolean;$$ LANGUAGE SQL VOLATILE STRICT; COMMENT ON FUNCTION plvdate.unset_nonbizday(date) IS 'Unset day as non bussines day'; CREATE FUNCTION plvdate.use_easter(bool) RETURNS void AS 'MODULE_PATHNAME','plvdate_use_easter' LANGUAGE C VOLATILE STRICT; COMMENT ON FUNCTION plvdate.use_easter(bool) IS 'Easter Sunday and easter monday will be holiday'; CREATE FUNCTION plvdate.use_easter() RETURNS bool AS $$SELECT plvdate.use_easter(true); SELECT NULL::boolean;$$ LANGUAGE SQL VOLATILE STRICT; COMMENT ON FUNCTION plvdate.use_easter() IS 'Easter Sunday and easter monday will be holiday'; CREATE FUNCTION plvdate.unuse_easter() RETURNS bool AS $$SELECT plvdate.use_easter(false); SELECT NULL::boolean;$$ LANGUAGE SQL VOLATILE STRICT; COMMENT ON FUNCTION plvdate.unuse_easter() IS 'Easter Sunday and easter monday will not be holiday'; CREATE FUNCTION plvdate.using_easter() RETURNS bool AS 'MODULE_PATHNAME','plvdate_using_easter' LANGUAGE C VOLATILE STRICT; COMMENT ON FUNCTION plvdate.using_easter() IS 'Use easter?'; CREATE FUNCTION plvdate.use_great_friday(bool) RETURNS void AS 'MODULE_PATHNAME','plvdate_use_great_friday' LANGUAGE C VOLATILE STRICT; COMMENT ON FUNCTION plvdate.use_great_friday(bool) IS 'Great Friday will be holiday'; CREATE FUNCTION plvdate.use_great_friday() RETURNS bool AS $$SELECT plvdate.use_great_friday(true); SELECT NULL::boolean;$$ LANGUAGE SQL VOLATILE STRICT; COMMENT ON FUNCTION plvdate.use_great_friday() IS 'Great Friday will be holiday'; CREATE FUNCTION plvdate.unuse_great_friday() RETURNS bool AS $$SELECT plvdate.use_great_friday(false); SELECT NULL::boolean;$$ LANGUAGE SQL VOLATILE STRICT; COMMENT ON FUNCTION plvdate.unuse_great_friday() IS 'Great Friday will not be holiday'; CREATE FUNCTION plvdate.using_great_friday() RETURNS bool AS 'MODULE_PATHNAME','plvdate_using_great_friday' LANGUAGE C VOLATILE STRICT; COMMENT ON FUNCTION plvdate.using_great_friday() IS 'Use Great Friday?'; CREATE FUNCTION plvdate.include_start(bool) RETURNS void AS 'MODULE_PATHNAME','plvdate_include_start' LANGUAGE C VOLATILE STRICT; COMMENT ON FUNCTION plvdate.include_start(bool) IS 'Include starting date in bizdays_between calculation'; CREATE FUNCTION plvdate.include_start() RETURNS bool AS $$SELECT plvdate.include_start(true); SELECT NULL::boolean;$$ LANGUAGE SQL VOLATILE STRICT; COMMENT ON FUNCTION plvdate.include_start() IS ''; CREATE FUNCTION plvdate.noinclude_start() RETURNS bool AS $$SELECT plvdate.include_start(false); SELECT NULL::boolean;$$ LANGUAGE SQL VOLATILE STRICT; COMMENT ON FUNCTION plvdate.noinclude_start() IS ''; CREATE FUNCTION plvdate.including_start() RETURNS bool AS 'MODULE_PATHNAME','plvdate_including_start' LANGUAGE C VOLATILE STRICT; COMMENT ON FUNCTION plvdate.including_start() IS ''; CREATE FUNCTION plvdate.version() RETURNS cstring AS 'MODULE_PATHNAME','plvdate_version' LANGUAGE C VOLATILE STRICT; COMMENT ON FUNCTION plvdate.version() IS ''; CREATE FUNCTION plvdate.default_holidays(text) RETURNS void AS 'MODULE_PATHNAME','plvdate_default_holidays' LANGUAGE C VOLATILE STRICT; COMMENT ON FUNCTION plvdate.default_holidays(text) IS 'Load calendar for some nations'; CREATE FUNCTION plvdate.days_inmonth(date) RETURNS integer AS 'MODULE_PATHNAME','plvdate_days_inmonth' LANGUAGE C VOLATILE STRICT; COMMENT ON FUNCTION plvdate.days_inmonth(date) IS 'Returns number of days in month'; CREATE FUNCTION plvdate.isleapyear(date) RETURNS bool AS 'MODULE_PATHNAME','plvdate_isleapyear' LANGUAGE C VOLATILE STRICT; COMMENT ON FUNCTION plvdate.isleapyear(date) IS 'Is leap year'; -- PLVstr package CREATE FUNCTION plvstr.normalize(str text) RETURNS varchar AS 'MODULE_PATHNAME','plvstr_normalize' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION plvstr.normalize(text) IS 'Replace white chars by space, replace spaces by space'; CREATE FUNCTION plvstr.is_prefix(str text, prefix text, cs bool) RETURNS bool AS 'MODULE_PATHNAME','plvstr_is_prefix_text' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION plvstr.is_prefix(text, text, bool) IS 'Returns true, if prefix is prefix of str'; CREATE FUNCTION plvstr.is_prefix(str text, prefix text) RETURNS bool AS $$ SELECT plvstr.is_prefix($1,$2,true);$$ LANGUAGE SQL IMMUTABLE STRICT; COMMENT ON FUNCTION plvstr.is_prefix(text, text) IS 'Returns true, if prefix is prefix of str'; CREATE FUNCTION plvstr.is_prefix(str int, prefix int) RETURNS bool AS 'MODULE_PATHNAME','plvstr_is_prefix_int' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION plvstr.is_prefix(int, int) IS 'Returns true, if prefix is prefix of str'; CREATE FUNCTION plvstr.is_prefix(str bigint, prefix bigint) RETURNS bool AS 'MODULE_PATHNAME','plvstr_is_prefix_int64' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION plvstr.is_prefix(bigint, bigint) IS 'Returns true, if prefix is prefix of str'; CREATE FUNCTION plvstr.substr(str text, start int, len int) RETURNS varchar AS 'MODULE_PATHNAME','plvstr_substr3' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION plvstr.substr(text, int, int) IS 'Returns substring started on start_in to end'; CREATE FUNCTION plvstr.substr(str text, start int) RETURNS varchar AS 'MODULE_PATHNAME','plvstr_substr2' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION plvstr.substr(text, int) IS 'Returns substring started on start_in to end'; CREATE FUNCTION plvstr.instr(str text, patt text, start int, nth int) RETURNS int AS 'MODULE_PATHNAME','plvstr_instr4' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION plvstr.instr(text, text, int, int) IS 'Search pattern in string'; CREATE FUNCTION plvstr.instr(str text, patt text, start int) RETURNS int AS 'MODULE_PATHNAME','plvstr_instr3' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION plvstr.instr(text, text, int) IS 'Search pattern in string'; CREATE FUNCTION plvstr.instr(str text, patt text) RETURNS int AS 'MODULE_PATHNAME','plvstr_instr2' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION plvstr.instr(text, text) IS 'Search pattern in string'; CREATE FUNCTION plvstr.lpart(str text, div text, start int, nth int, all_if_notfound bool) RETURNS text AS 'MODULE_PATHNAME','plvstr_lpart' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION plvstr.lpart(text, text, int, int, bool) IS 'Call this function to return the left part of a string'; CREATE FUNCTION plvstr.lpart(str text, div text, start int, nth int) RETURNS text AS $$ SELECT plvstr.lpart($1,$2, $3, $4, false); $$ LANGUAGE SQL IMMUTABLE STRICT; COMMENT ON FUNCTION plvstr.lpart(text, text, int, int) IS 'Call this function to return the left part of a string'; CREATE FUNCTION plvstr.lpart(str text, div text, start int) RETURNS text AS $$ SELECT plvstr.lpart($1,$2, $3, 1, false); $$ LANGUAGE SQL IMMUTABLE STRICT; COMMENT ON FUNCTION plvstr.lpart(text, text, int) IS 'Call this function to return the left part of a string'; CREATE FUNCTION plvstr.lpart(str text, div text) RETURNS text AS $$ SELECT plvstr.lpart($1,$2, 1, 1, false); $$ LANGUAGE SQL IMMUTABLE STRICT; COMMENT ON FUNCTION plvstr.lpart(text, text) IS 'Call this function to return the left part of a string'; CREATE FUNCTION plvstr.rpart(str text, div text, start int, nth int, all_if_notfound bool) RETURNS text AS 'MODULE_PATHNAME','plvstr_rpart' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION plvstr.rpart(text, text, int, int, bool) IS 'Call this function to return the right part of a string'; CREATE FUNCTION plvstr.rpart(str text, div text, start int, nth int) RETURNS text AS $$ SELECT plvstr.rpart($1,$2, $3, $4, false); $$ LANGUAGE SQL IMMUTABLE STRICT; COMMENT ON FUNCTION plvstr.rpart(text, text, int, int) IS 'Call this function to return the right part of a string'; CREATE FUNCTION plvstr.rpart(str text, div text, start int) RETURNS text AS $$ SELECT plvstr.rpart($1,$2, $3, 1, false); $$ LANGUAGE SQL IMMUTABLE STRICT; COMMENT ON FUNCTION plvstr.rpart(text, text, int) IS 'Call this function to return the right part of a string'; CREATE FUNCTION plvstr.rpart(str text, div text) RETURNS text AS $$ SELECT plvstr.rpart($1,$2, 1, 1, false); $$ LANGUAGE SQL IMMUTABLE STRICT; COMMENT ON FUNCTION plvstr.rpart(text, text) IS 'Call this function to return the right part of a string'; CREATE FUNCTION plvstr.lstrip(str text, substr text, num int) RETURNS text AS 'MODULE_PATHNAME','plvstr_lstrip' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION plvstr.lstrip(text, text, int) IS 'Call this function to remove characters from the beginning '; CREATE FUNCTION plvstr.lstrip(str text, substr text) RETURNS text AS $$ SELECT plvstr.lstrip($1, $2, 1); $$ LANGUAGE SQL IMMUTABLE STRICT; COMMENT ON FUNCTION plvstr.lstrip(text, text) IS 'Call this function to remove characters from the beginning '; CREATE FUNCTION plvstr.rstrip(str text, substr text, num int) RETURNS text AS 'MODULE_PATHNAME','plvstr_rstrip' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION plvstr.rstrip(text, text, int) IS 'Call this function to remove characters from the end'; CREATE FUNCTION plvstr.rstrip(str text, substr text) RETURNS text AS $$ SELECT plvstr.rstrip($1, $2, 1); $$ LANGUAGE SQL IMMUTABLE STRICT; COMMENT ON FUNCTION plvstr.rstrip(text, text) IS 'Call this function to remove characters from the end'; CREATE FUNCTION plvstr.swap(str text, replace text, start int, length int) RETURNS text AS 'MODULE_PATHNAME','plvstr_swap' LANGUAGE C IMMUTABLE; COMMENT ON FUNCTION plvstr.swap(text,text, int, int) IS 'Replace a substring in a string with a specified string'; CREATE FUNCTION plvstr.swap(str text, replace text) RETURNS text AS $$ SELECT plvstr.swap($1,$2,1, NULL);$$ LANGUAGE SQL IMMUTABLE STRICT; COMMENT ON FUNCTION plvstr.swap(text,text) IS 'Replace a substring in a string with a specified string'; CREATE FUNCTION plvstr.betwn(str text, start int, _end int, inclusive bool) RETURNS text AS 'MODULE_PATHNAME','plvstr_betwn_i' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION plvstr.betwn(text, int, int, bool) IS 'Find the Substring Between Start and End Locations'; CREATE FUNCTION plvstr.betwn(str text, start int, _end int) RETURNS text AS $$ SELECT plvstr.betwn($1,$2,$3,true);$$ LANGUAGE SQL IMMUTABLE STRICT; COMMENT ON FUNCTION plvstr.betwn(text, int, int) IS 'Find the Substring Between Start and End Locations'; CREATE FUNCTION plvstr.betwn(str text, start text, _end text, startnth int, endnth int, inclusive bool, gotoend bool) RETURNS text AS 'MODULE_PATHNAME','plvstr_betwn_c' LANGUAGE C IMMUTABLE; COMMENT ON FUNCTION plvstr.betwn(text, text, text, int, int, bool, bool) IS 'Find the Substring Between Start and End Locations'; CREATE FUNCTION plvstr.betwn(str text, start text, _end text) RETURNS text AS $$ SELECT plvstr.betwn($1,$2,$3,1,1,true,false);$$ LANGUAGE SQL IMMUTABLE; COMMENT ON FUNCTION plvstr.betwn(text, text, text) IS 'Find the Substring Between Start and End Locations'; CREATE FUNCTION plvstr.betwn(str text, start text, _end text, startnth int, endnth int) RETURNS text AS $$ SELECT plvstr.betwn($1,$2,$3,$4,$5,true,false);$$ LANGUAGE SQL IMMUTABLE; COMMENT ON FUNCTION plvstr.betwn(text, text, text, int, int) IS 'Find the Substring Between Start and End Locations'; CREATE SCHEMA plvchr; CREATE FUNCTION plvchr.nth(str text, n int) RETURNS text AS 'MODULE_PATHNAME','plvchr_nth' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION plvchr.nth(text, int) IS 'Call this function to return the Nth character in a string'; CREATE FUNCTION plvchr.first(str text) RETURNS varchar AS 'MODULE_PATHNAME','plvchr_first' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION plvchr.first(text) IS 'Call this function to return the first character in a string'; CREATE FUNCTION plvchr.last(str text) RETURNS varchar AS 'MODULE_PATHNAME','plvchr_last' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION plvchr.last(text) IS 'Call this function to return the last character in a string'; CREATE FUNCTION plvchr._is_kind(str text, kind int) RETURNS bool AS 'MODULE_PATHNAME','plvchr_is_kind_a' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION plvchr._is_kind(text, int) IS ''; CREATE FUNCTION plvchr._is_kind(c int, kind int) RETURNS bool AS 'MODULE_PATHNAME','plvchr_is_kind_i' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION plvchr._is_kind(int, int) IS ''; CREATE FUNCTION plvchr.is_blank(c int) RETURNS BOOL AS $$ SELECT plvchr._is_kind($1, 1);$$ LANGUAGE SQL IMMUTABLE STRICT; COMMENT ON FUNCTION plvchr.is_blank(int) IS ''; CREATE FUNCTION plvchr.is_blank(c text) RETURNS BOOL AS $$ SELECT plvchr._is_kind($1, 1);$$ LANGUAGE SQL IMMUTABLE STRICT; COMMENT ON FUNCTION plvchr.is_blank(text) IS ''; CREATE FUNCTION plvchr.is_digit(c int) RETURNS BOOL AS $$ SELECT plvchr._is_kind($1, 2);$$ LANGUAGE SQL IMMUTABLE STRICT; COMMENT ON FUNCTION plvchr.is_digit(int) IS ''; CREATE FUNCTION plvchr.is_digit(c text) RETURNS BOOL AS $$ SELECT plvchr._is_kind($1, 2);$$ LANGUAGE SQL IMMUTABLE STRICT; COMMENT ON FUNCTION plvchr.is_digit(text) IS ''; CREATE FUNCTION plvchr.is_quote(c int) RETURNS BOOL AS $$ SELECT plvchr._is_kind($1, 3);$$ LANGUAGE SQL IMMUTABLE STRICT; COMMENT ON FUNCTION plvchr.is_quote(int) IS ''; CREATE FUNCTION plvchr.is_quote(c text) RETURNS BOOL AS $$ SELECT plvchr._is_kind($1, 3);$$ LANGUAGE SQL IMMUTABLE STRICT; COMMENT ON FUNCTION plvchr.is_quote(text) IS ''; CREATE FUNCTION plvchr.is_other(c int) RETURNS BOOL AS $$ SELECT plvchr._is_kind($1, 4);$$ LANGUAGE SQL IMMUTABLE STRICT; COMMENT ON FUNCTION plvchr.is_other(int) IS ''; CREATE FUNCTION plvchr.is_other(c text) RETURNS BOOL AS $$ SELECT plvchr._is_kind($1, 4);$$ LANGUAGE SQL IMMUTABLE STRICT; COMMENT ON FUNCTION plvchr.is_other(text) IS ''; CREATE FUNCTION plvchr.is_letter(c int) RETURNS BOOL AS $$ SELECT plvchr._is_kind($1, 5);$$ LANGUAGE SQL IMMUTABLE STRICT; COMMENT ON FUNCTION plvchr.is_letter(int) IS ''; CREATE FUNCTION plvchr.is_letter(c text) RETURNS BOOL AS $$ SELECT plvchr._is_kind($1, 5);$$ LANGUAGE SQL IMMUTABLE STRICT; COMMENT ON FUNCTION plvchr.is_letter(text) IS ''; CREATE FUNCTION plvchr.char_name(c text) RETURNS varchar AS 'MODULE_PATHNAME','plvchr_char_name' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION plvchr.char_name(text) IS ''; CREATE FUNCTION plvstr.left(str text, n int) RETURNS varchar AS 'MODULE_PATHNAME', 'plvstr_left' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION plvstr.left(text, int) IS 'Returns firs num_in charaters. You can use negative num_in'; CREATE FUNCTION plvstr.right(str text, n int) RETURNS varchar AS 'MODULE_PATHNAME','plvstr_right' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION plvstr.right(text, int) IS 'Returns last num_in charaters. You can use negative num_ni'; CREATE FUNCTION plvchr.quoted1(str text) RETURNS varchar AS $$SELECT ''''||$1||'''';$$ LANGUAGE SQL IMMUTABLE STRICT; COMMENT ON FUNCTION plvchr.quoted1(text) IS E'Quoted text between '''; CREATE FUNCTION plvchr.quoted2(str text) RETURNS varchar AS $$SELECT '"'||$1||'"';$$ LANGUAGE SQL IMMUTABLE STRICT; COMMENT ON FUNCTION plvchr.quoted2(text) IS 'Quoted text between "'; CREATE FUNCTION plvchr.stripped(str text, char_in text) RETURNS varchar AS $$ SELECT TRANSLATE($1, 'A'||$2, 'A'); $$ LANGUAGE SQL IMMUTABLE STRICT; COMMENT ON FUNCTION plvchr.stripped(text, text) IS 'Strips a string of all instances of the specified characters'; -- dbms_alert CREATE SCHEMA dbms_alert; CREATE FUNCTION dbms_alert.register(name text) RETURNS void AS 'MODULE_PATHNAME','dbms_alert_register' LANGUAGE C VOLATILE STRICT; COMMENT ON FUNCTION dbms_alert.register(text) IS 'Register session as recipient of alert name'; CREATE FUNCTION dbms_alert.remove(name text) RETURNS void AS 'MODULE_PATHNAME','dbms_alert_remove' LANGUAGE C VOLATILE STRICT; COMMENT ON FUNCTION dbms_alert.remove(text) IS 'Remove session as recipient of alert name'; CREATE FUNCTION dbms_alert.removeall() RETURNS void AS 'MODULE_PATHNAME','dbms_alert_removeall' LANGUAGE C VOLATILE; COMMENT ON FUNCTION dbms_alert.removeall() IS 'Remove registration for all alerts'; CREATE FUNCTION dbms_alert._signal(name text, message text) RETURNS void AS 'MODULE_PATHNAME','dbms_alert_signal' LANGUAGE C VOLATILE; COMMENT ON FUNCTION dbms_alert._signal(text, text) IS ''; CREATE FUNCTION dbms_alert.waitany(OUT name text, OUT message text, OUT status integer, timeout float8) RETURNS record AS 'MODULE_PATHNAME','dbms_alert_waitany' LANGUAGE C VOLATILE; COMMENT ON FUNCTION dbms_alert.waitany(OUT text, OUT text, OUT integer, float8) IS 'Wait for any signal'; CREATE FUNCTION dbms_alert.waitone(name text, OUT message text, OUT status integer, timeout float8) RETURNS record AS 'MODULE_PATHNAME','dbms_alert_waitone' LANGUAGE C VOLATILE; COMMENT ON FUNCTION dbms_alert.waitone(text, OUT text, OUT integer, float8) IS 'Wait for specific signal'; CREATE FUNCTION dbms_alert.set_defaults(sensitivity float8) RETURNS void AS 'MODULE_PATHNAME','dbms_alert_set_defaults' LANGUAGE C VOLATILE; COMMENT ON FUNCTION dbms_alert.set_defaults(float8) IS ''; CREATE FUNCTION dbms_alert.defered_signal() RETURNS trigger AS 'MODULE_PATHNAME','dbms_alert_defered_signal' LANGUAGE C SECURITY DEFINER; REVOKE ALL ON FUNCTION dbms_alert.defered_signal() FROM PUBLIC; CREATE FUNCTION dbms_alert.signal(_event text, _message text) RETURNS void AS 'MODULE_PATHNAME','dbms_alert_signal' LANGUAGE C SECURITY DEFINER; COMMENT ON FUNCTION dbms_alert.signal(text, text) IS 'Emit signal to all recipients'; CREATE SCHEMA plvsubst; CREATE FUNCTION plvsubst.string(template_in text, values_in text[], subst text) RETURNS text AS 'MODULE_PATHNAME','plvsubst_string_array' LANGUAGE C IMMUTABLE; COMMENT ON FUNCTION plvsubst.string(text, text[], text) IS 'Scans a string for all instances of the substitution keyword and replace it with the next value in the substitution values list'; CREATE FUNCTION plvsubst.string(template_in text, values_in text[]) RETURNS text AS $$SELECT plvsubst.string($1,$2, NULL);$$ LANGUAGE SQL STRICT VOLATILE; COMMENT ON FUNCTION plvsubst.string(text, text[]) IS 'Scans a string for all instances of the substitution keyword and replace it with the next value in the substitution values list'; CREATE FUNCTION plvsubst.string(template_in text, vals_in text, delim_in text, subst_in text) RETURNS text AS 'MODULE_PATHNAME','plvsubst_string_string' LANGUAGE C IMMUTABLE; COMMENT ON FUNCTION plvsubst.string(text, text, text, text) IS 'Scans a string for all instances of the substitution keyword and replace it with the next value in the substitution values list'; CREATE FUNCTION plvsubst.string(template_in text, vals_in text) RETURNS text AS 'MODULE_PATHNAME','plvsubst_string_string' LANGUAGE C IMMUTABLE; COMMENT ON FUNCTION plvsubst.string(text, text) IS 'Scans a string for all instances of the substitution keyword and replace it with the next value in the substitution values list'; CREATE FUNCTION plvsubst.string(template_in text, vals_in text, delim_in text) RETURNS text AS 'MODULE_PATHNAME','plvsubst_string_string' LANGUAGE C IMMUTABLE; COMMENT ON FUNCTION plvsubst.string(text, text, text) IS 'Scans a string for all instances of the substitution keyword and replace it with the next value in the substitution values list'; CREATE FUNCTION plvsubst.setsubst(str text) RETURNS void AS 'MODULE_PATHNAME','plvsubst_setsubst' LANGUAGE C STRICT VOLATILE; COMMENT ON FUNCTION plvsubst.setsubst(text) IS 'Change the substitution keyword'; CREATE FUNCTION plvsubst.setsubst() RETURNS void AS 'MODULE_PATHNAME','plvsubst_setsubst_default' LANGUAGE C STRICT VOLATILE; COMMENT ON FUNCTION plvsubst.setsubst() IS 'Change the substitution keyword to default %s'; CREATE FUNCTION plvsubst.subst() RETURNS text AS 'MODULE_PATHNAME','plvsubst_subst' LANGUAGE C STRICT VOLATILE; COMMENT ON FUNCTION plvsubst.subst() IS 'Retrieve the current substitution keyword'; CREATE SCHEMA dbms_utility; CREATE FUNCTION dbms_utility.format_call_stack(text) RETURNS text AS 'MODULE_PATHNAME','dbms_utility_format_call_stack1' LANGUAGE C STRICT VOLATILE; COMMENT ON FUNCTION dbms_utility.format_call_stack(text) IS 'Return formated call stack'; CREATE FUNCTION dbms_utility.format_call_stack() RETURNS text AS 'MODULE_PATHNAME','dbms_utility_format_call_stack0' LANGUAGE C VOLATILE; COMMENT ON FUNCTION dbms_utility.format_call_stack() IS 'Return formated call stack'; CREATE SCHEMA plvlex; CREATE FUNCTION plvlex.tokens(IN str text, IN skip_spaces bool, IN qualified_names bool, OUT pos int, OUT token text, OUT code int, OUT class text, OUT separator text, OUT mod text) RETURNS SETOF RECORD AS 'MODULE_PATHNAME','plvlex_tokens' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION plvlex.tokens(text,bool,bool) IS 'Parse SQL string'; CREATE SCHEMA utl_file; CREATE DOMAIN utl_file.file_type integer; CREATE FUNCTION utl_file.fopen(location text, filename text, open_mode text, max_linesize integer, encoding name) RETURNS utl_file.file_type AS 'MODULE_PATHNAME','utl_file_fopen' LANGUAGE C VOLATILE SECURITY DEFINER; COMMENT ON FUNCTION utl_file.fopen(text,text,text,integer,name) IS 'The FOPEN function open file and return file handle'; CREATE FUNCTION utl_file.fopen(location text, filename text, open_mode text, max_linesize integer) RETURNS utl_file.file_type AS 'MODULE_PATHNAME','utl_file_fopen' LANGUAGE C VOLATILE SECURITY DEFINER; COMMENT ON FUNCTION utl_file.fopen(text,text,text,integer) IS 'The FOPEN function open file and return file handle'; CREATE FUNCTION utl_file.fopen(location text, filename text, open_mode text) RETURNS utl_file.file_type AS $$SELECT utl_file.fopen($1, $2, $3, 1024); $$ LANGUAGE SQL VOLATILE; COMMENT ON FUNCTION utl_file.fopen(text,text,text,integer) IS 'The FOPEN function open file and return file handle'; CREATE FUNCTION utl_file.is_open(file utl_file.file_type) RETURNS bool AS 'MODULE_PATHNAME','utl_file_is_open' LANGUAGE C VOLATILE; COMMENT ON FUNCTION utl_file.is_open(utl_file.file_type) IS 'Functions returns true if handle points to file that is open'; CREATE FUNCTION utl_file.get_line(file utl_file.file_type, OUT buffer text) AS 'MODULE_PATHNAME','utl_file_get_line' LANGUAGE C VOLATILE; COMMENT ON FUNCTION utl_file.get_line(utl_file.file_type) IS 'Returns one line from file'; CREATE FUNCTION utl_file.get_line(file utl_file.file_type, OUT buffer text, len integer) AS 'MODULE_PATHNAME','utl_file_get_line' LANGUAGE C VOLATILE; COMMENT ON FUNCTION utl_file.get_line(utl_file.file_type, len integer) IS 'Returns one line from file'; CREATE FUNCTION utl_file.get_nextline(file utl_file.file_type, OUT buffer text) AS 'MODULE_PATHNAME','utl_file_get_nextline' LANGUAGE C VOLATILE; COMMENT ON FUNCTION utl_file.get_nextline(utl_file.file_type) IS 'Returns one line from file or returns NULL'; CREATE FUNCTION utl_file.put(file utl_file.file_type, buffer text) RETURNS bool AS 'MODULE_PATHNAME','utl_file_put' LANGUAGE C VOLATILE; COMMENT ON FUNCTION utl_file.put(utl_file.file_type, text) IS 'Puts data to specified file'; CREATE FUNCTION utl_file.put(file utl_file.file_type, buffer anyelement) RETURNS bool AS $$SELECT utl_file.put($1, $2::text); $$ LANGUAGE SQL VOLATILE; COMMENT ON FUNCTION utl_file.put(utl_file.file_type, anyelement) IS 'Puts data to specified file'; CREATE FUNCTION utl_file.new_line(file utl_file.file_type) RETURNS bool AS 'MODULE_PATHNAME','utl_file_new_line' LANGUAGE C VOLATILE; COMMENT ON FUNCTION utl_file.new_line(file utl_file.file_type) IS 'Function inserts one ore more newline characters in specified file'; CREATE FUNCTION utl_file.new_line(file utl_file.file_type, lines int) RETURNS bool AS 'MODULE_PATHNAME','utl_file_new_line' LANGUAGE C VOLATILE; COMMENT ON FUNCTION utl_file.new_line(file utl_file.file_type) IS 'Function inserts one ore more newline characters in specified file'; CREATE FUNCTION utl_file.put_line(file utl_file.file_type, buffer text) RETURNS bool AS 'MODULE_PATHNAME','utl_file_put_line' LANGUAGE C VOLATILE; COMMENT ON FUNCTION utl_file.put_line(utl_file.file_type, text) IS 'Puts data to specified file and append newline character'; CREATE FUNCTION utl_file.put_line(file utl_file.file_type, buffer text, autoflush bool) RETURNS bool AS 'MODULE_PATHNAME','utl_file_put_line' LANGUAGE C VOLATILE; COMMENT ON FUNCTION utl_file.put_line(utl_file.file_type, text, bool) IS 'Puts data to specified file and append newline character'; CREATE FUNCTION utl_file.putf(file utl_file.file_type, format text, arg1 text, arg2 text, arg3 text, arg4 text, arg5 text) RETURNS bool AS 'MODULE_PATHNAME','utl_file_putf' LANGUAGE C VOLATILE; COMMENT ON FUNCTION utl_file.putf(utl_file.file_type, text, text, text, text, text, text) IS 'Puts formatted data to specified file'; CREATE FUNCTION utl_file.putf(file utl_file.file_type, format text, arg1 text, arg2 text, arg3 text, arg4 text) RETURNS bool AS $$SELECT utl_file.putf($1, $2, $3, $4, $5, $6, NULL); $$ LANGUAGE SQL VOLATILE; COMMENT ON FUNCTION utl_file.putf(utl_file.file_type, text, text, text, text, text) IS 'Puts formatted data to specified file'; CREATE FUNCTION utl_file.putf(file utl_file.file_type, format text, arg1 text, arg2 text, arg3 text) RETURNS bool AS $$SELECT utl_file.putf($1, $2, $3, $4, $5, NULL, NULL); $$ LANGUAGE SQL VOLATILE; COMMENT ON FUNCTION utl_file.putf(utl_file.file_type, text, text, text, text) IS 'Puts formatted data to specified file'; CREATE FUNCTION utl_file.putf(file utl_file.file_type, format text, arg1 text, arg2 text) RETURNS bool AS $$SELECT utl_file.putf($1, $2, $3, $4, NULL, NULL, NULL); $$ LANGUAGE SQL VOLATILE; COMMENT ON FUNCTION utl_file.putf(utl_file.file_type, text, text, text, text) IS 'Puts formatted data to specified file'; CREATE FUNCTION utl_file.putf(file utl_file.file_type, format text, arg1 text) RETURNS bool AS $$SELECT utl_file.putf($1, $2, $3, NULL, NULL, NULL, NULL); $$ LANGUAGE SQL VOLATILE; COMMENT ON FUNCTION utl_file.putf(utl_file.file_type, text, text) IS 'Puts formatted data to specified file'; CREATE FUNCTION utl_file.putf(file utl_file.file_type, format text) RETURNS bool AS $$SELECT utl_file.putf($1, $2, NULL, NULL, NULL, NULL, NULL); $$ LANGUAGE SQL VOLATILE; COMMENT ON FUNCTION utl_file.putf(utl_file.file_type, text) IS 'Puts formatted data to specified file'; CREATE FUNCTION utl_file.fflush(file utl_file.file_type) RETURNS void AS 'MODULE_PATHNAME','utl_file_fflush' LANGUAGE C VOLATILE; COMMENT ON FUNCTION utl_file.fflush(file utl_file.file_type) IS 'This procedure makes sure that all pending data for specified file is written physically out to a file'; CREATE FUNCTION utl_file.fclose(file utl_file.file_type) RETURNS utl_file.file_type AS 'MODULE_PATHNAME','utl_file_fclose' LANGUAGE C VOLATILE; COMMENT ON FUNCTION utl_file.fclose(utl_file.file_type) IS 'Close file'; CREATE FUNCTION utl_file.fclose_all() RETURNS void AS 'MODULE_PATHNAME','utl_file_fclose_all' LANGUAGE C VOLATILE; COMMENT ON FUNCTION utl_file.fclose_all() IS 'Close all open files.'; CREATE FUNCTION utl_file.fremove(location text, filename text) RETURNS void AS 'MODULE_PATHNAME','utl_file_fremove' LANGUAGE C VOLATILE; COMMENT ON FUNCTION utl_file.fremove(text, text) IS 'Remove file.'; CREATE FUNCTION utl_file.frename(location text, filename text, dest_dir text, dest_file text, overwrite boolean) RETURNS void AS 'MODULE_PATHNAME','utl_file_frename' LANGUAGE C VOLATILE; COMMENT ON FUNCTION utl_file.frename(text, text, text, text, boolean) IS 'Rename file.'; CREATE FUNCTION utl_file.frename(location text, filename text, dest_dir text, dest_file text) RETURNS void AS $$SELECT utl_file.frename($1, $2, $3, $4, false);$$ LANGUAGE SQL VOLATILE; COMMENT ON FUNCTION utl_file.frename(text, text, text, text) IS 'Rename file.'; CREATE FUNCTION utl_file.fcopy(src_location text, src_filename text, dest_location text, dest_filename text) RETURNS void AS 'MODULE_PATHNAME','utl_file_fcopy' LANGUAGE C VOLATILE; COMMENT ON FUNCTION utl_file.fcopy(text, text, text, text) IS 'Copy a text file.'; CREATE FUNCTION utl_file.fcopy(src_location text, src_filename text, dest_location text, dest_filename text, start_line integer) RETURNS void AS 'MODULE_PATHNAME','utl_file_fcopy' LANGUAGE C VOLATILE; COMMENT ON FUNCTION utl_file.fcopy(text, text, text, text, integer) IS 'Copy a text file.'; CREATE FUNCTION utl_file.fcopy(src_location text, src_filename text, dest_location text, dest_filename text, start_line integer, end_line integer) RETURNS void AS 'MODULE_PATHNAME','utl_file_fcopy' LANGUAGE C VOLATILE; COMMENT ON FUNCTION utl_file.fcopy(text, text, text, text, integer, integer) IS 'Copy a text file.'; CREATE FUNCTION utl_file.fgetattr(location text, filename text, OUT fexists boolean, OUT file_length bigint, OUT blocksize integer) AS 'MODULE_PATHNAME','utl_file_fgetattr' LANGUAGE C VOLATILE; COMMENT ON FUNCTION utl_file.fgetattr(text, text) IS 'Get file attributes.'; CREATE FUNCTION utl_file.tmpdir() RETURNS text AS 'MODULE_PATHNAME','utl_file_tmpdir' LANGUAGE C VOLATILE; COMMENT ON FUNCTION utl_file.tmpdir() IS 'Get temp directory path.'; /* carry all safe directories */ CREATE TABLE utl_file.utl_file_dir(dir text); REVOKE ALL ON utl_file.utl_file_dir FROM PUBLIC; REVOKE ALL ON FUNCTION utl_file.tmpdir() FROM PUBLIC; -- dbms_assert CREATE SCHEMA dbms_assert; CREATE FUNCTION dbms_assert.enquote_literal(str varchar) RETURNS varchar AS 'MODULE_PATHNAME','dbms_assert_enquote_literal' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION dbms_assert.enquote_literal(varchar) IS 'Add leading and trailing quotes, verify that all single quotes are paired with adjacent single quotes'; CREATE FUNCTION dbms_assert.enquote_name(str varchar, loweralize boolean) RETURNS varchar AS 'MODULE_PATHNAME','dbms_assert_enquote_name' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION dbms_assert.enquote_name(varchar, boolean) IS 'Enclose name in double quotes'; CREATE FUNCTION dbms_assert.enquote_name(str varchar) RETURNS varchar AS 'SELECT dbms_assert.enquote_name($1, true)' LANGUAGE SQL IMMUTABLE STRICT; COMMENT ON FUNCTION dbms_assert.enquote_name(varchar) IS 'Enclose name in double quotes'; CREATE FUNCTION dbms_assert.noop(str varchar) RETURNS varchar AS 'MODULE_PATHNAME','dbms_assert_noop' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION dbms_assert.noop(varchar) IS 'Returns value without any checking.'; CREATE FUNCTION dbms_assert.schema_name(str varchar) RETURNS varchar AS 'MODULE_PATHNAME','dbms_assert_schema_name' LANGUAGE C IMMUTABLE; COMMENT ON FUNCTION dbms_assert.schema_name(varchar) IS 'Verify input string is an existing schema name.'; CREATE FUNCTION dbms_assert.object_name(str varchar) RETURNS varchar AS 'MODULE_PATHNAME','dbms_assert_object_name' LANGUAGE C IMMUTABLE; COMMENT ON FUNCTION dbms_assert.object_name(varchar) IS 'Verify input string is an existing object name.'; CREATE FUNCTION dbms_assert.simple_sql_name(str varchar) RETURNS varchar AS 'MODULE_PATHNAME','dbms_assert_simple_sql_name' LANGUAGE C IMMUTABLE; COMMENT ON FUNCTION dbms_assert.object_name(varchar) IS 'Verify input string is an sql name.'; CREATE FUNCTION dbms_assert.qualified_sql_name(str varchar) RETURNS varchar AS 'MODULE_PATHNAME','dbms_assert_qualified_sql_name' LANGUAGE C IMMUTABLE; COMMENT ON FUNCTION dbms_assert.object_name(varchar) IS 'Verify input string is an qualified sql name.'; CREATE SCHEMA plunit; CREATE FUNCTION plunit.assert_true(condition boolean) RETURNS void AS 'MODULE_PATHNAME','plunit_assert_true' LANGUAGE C IMMUTABLE; COMMENT ON FUNCTION plunit.assert_true(condition boolean) IS 'Asserts that the condition is true'; CREATE FUNCTION plunit.assert_true(condition boolean, message varchar) RETURNS void AS 'MODULE_PATHNAME','plunit_assert_true_message' LANGUAGE C IMMUTABLE; COMMENT ON FUNCTION plunit.assert_true(condition boolean, message varchar) IS 'Asserts that the condition is true'; CREATE FUNCTION plunit.assert_false(condition boolean) RETURNS void AS 'MODULE_PATHNAME','plunit_assert_false' LANGUAGE C IMMUTABLE; COMMENT ON FUNCTION plunit.assert_false(condition boolean) IS 'Asserts that the condition is false'; CREATE FUNCTION plunit.assert_false(condition boolean, message varchar) RETURNS void AS 'MODULE_PATHNAME','plunit_assert_false_message' LANGUAGE C IMMUTABLE; COMMENT ON FUNCTION plunit.assert_false(condition boolean, message varchar) IS 'Asserts that the condition is false'; CREATE FUNCTION plunit.assert_null(actual anyelement) RETURNS void AS 'MODULE_PATHNAME','plunit_assert_null' LANGUAGE C IMMUTABLE; COMMENT ON FUNCTION plunit.assert_null(actual anyelement) IS 'Asserts that the actual is null'; CREATE FUNCTION plunit.assert_null(actual anyelement, message varchar) RETURNS void AS 'MODULE_PATHNAME','plunit_assert_null_message' LANGUAGE C IMMUTABLE; COMMENT ON FUNCTION plunit.assert_null(actual anyelement, message varchar) IS 'Asserts that the condition is null'; CREATE FUNCTION plunit.assert_not_null(actual anyelement) RETURNS void AS 'MODULE_PATHNAME','plunit_assert_not_null' LANGUAGE C IMMUTABLE; COMMENT ON FUNCTION plunit.assert_not_null(actual anyelement) IS 'Asserts that the actual is not null'; CREATE FUNCTION plunit.assert_not_null(actual anyelement, message varchar) RETURNS void AS 'MODULE_PATHNAME','plunit_assert_not_null_message' LANGUAGE C IMMUTABLE; COMMENT ON FUNCTION plunit.assert_not_null(actual anyelement, message varchar) IS 'Asserts that the condition is not null'; CREATE FUNCTION plunit.assert_equals(expected anyelement, actual anyelement) RETURNS void AS 'MODULE_PATHNAME','plunit_assert_equals' LANGUAGE C IMMUTABLE; COMMENT ON FUNCTION plunit.assert_equals(expected anyelement, actual anyelement) IS 'Asserts that expected and actual are equal'; CREATE FUNCTION plunit.assert_equals(expected anyelement, actual anyelement, message varchar) RETURNS void AS 'MODULE_PATHNAME','plunit_assert_equals_message' LANGUAGE C IMMUTABLE; COMMENT ON FUNCTION plunit.assert_equals(expected anyelement, actual anyelement, message varchar) IS 'Asserts that expected and actual are equal'; CREATE FUNCTION plunit.assert_equals(expected double precision, actual double precision, "range" double precision) RETURNS void AS 'MODULE_PATHNAME','plunit_assert_equals_range' LANGUAGE C IMMUTABLE; COMMENT ON FUNCTION plunit.assert_equals(expected double precision, actual double precision, "range" double precision) IS 'Asserts that expected and actual are equal'; CREATE FUNCTION plunit.assert_equals(expected double precision, actual double precision, "range" double precision, message varchar) RETURNS void AS 'MODULE_PATHNAME','plunit_assert_equals_range_message' LANGUAGE C IMMUTABLE; COMMENT ON FUNCTION plunit.assert_equals(expected double precision, actual double precision, "range" double precision, message varchar) IS 'Asserts that expected and actual are equal'; CREATE FUNCTION plunit.assert_not_equals(expected anyelement, actual anyelement) RETURNS void AS 'MODULE_PATHNAME','plunit_assert_not_equals' LANGUAGE C IMMUTABLE; COMMENT ON FUNCTION plunit.assert_not_equals(expected anyelement, actual anyelement) IS 'Asserts that expected and actual are equal'; CREATE FUNCTION plunit.assert_not_equals(expected anyelement, actual anyelement, message varchar) RETURNS void AS 'MODULE_PATHNAME','plunit_assert_not_equals_message' LANGUAGE C IMMUTABLE; COMMENT ON FUNCTION plunit.assert_not_equals(expected anyelement, actual anyelement, message varchar) IS 'Asserts that expected and actual are equal'; CREATE FUNCTION plunit.assert_not_equals(expected double precision, actual double precision, "range" double precision) RETURNS void AS 'MODULE_PATHNAME','plunit_assert_not_equals_range' LANGUAGE C IMMUTABLE; COMMENT ON FUNCTION plunit.assert_equals(expected double precision, actual double precision, "range" double precision) IS 'Asserts that expected and actual are equal'; CREATE FUNCTION plunit.assert_not_equals(expected double precision, actual double precision, "range" double precision, message varchar) RETURNS void AS 'MODULE_PATHNAME','plunit_assert_not_equals_range_message' LANGUAGE C IMMUTABLE; COMMENT ON FUNCTION plunit.assert_not_equals(expected double precision, actual double precision, "range" double precision, message varchar) IS 'Asserts that expected and actual are equal'; CREATE FUNCTION plunit.fail() RETURNS void AS 'MODULE_PATHNAME','plunit_fail' LANGUAGE C IMMUTABLE; COMMENT ON FUNCTION plunit.fail() IS 'Immediately fail.'; CREATE FUNCTION plunit.fail(message varchar) RETURNS void AS 'MODULE_PATHNAME','plunit_fail_message' LANGUAGE C IMMUTABLE; COMMENT ON FUNCTION plunit.fail(message varchar) IS 'Immediately fail.'; -- dbms_random CREATE SCHEMA dbms_random; CREATE FUNCTION dbms_random.initialize(int) RETURNS void AS 'MODULE_PATHNAME','dbms_random_initialize' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION dbms_random.initialize(int) IS 'Initialize package with a seed value'; CREATE FUNCTION dbms_random.normal() RETURNS double precision AS 'MODULE_PATHNAME','dbms_random_normal' LANGUAGE C VOLATILE; COMMENT ON FUNCTION dbms_random.normal() IS 'Returns random numbers in a standard normal distribution'; CREATE FUNCTION dbms_random.random() RETURNS integer AS 'MODULE_PATHNAME','dbms_random_random' LANGUAGE C VOLATILE; COMMENT ON FUNCTION dbms_random.random() IS 'Generate Random Numeric Values'; CREATE FUNCTION dbms_random.seed(integer) RETURNS void AS 'MODULE_PATHNAME','dbms_random_seed_int' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION dbms_random.seed(int) IS 'Reset the seed value'; CREATE FUNCTION dbms_random.seed(text) RETURNS void AS 'MODULE_PATHNAME','dbms_random_seed_varchar' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION dbms_random.seed(text) IS 'Reset the seed value'; CREATE FUNCTION dbms_random.string(opt text, len int) RETURNS text AS 'MODULE_PATHNAME','dbms_random_string' LANGUAGE C IMMUTABLE; COMMENT ON FUNCTION dbms_random.string(text,int) IS 'Create Random Strings'; CREATE FUNCTION dbms_random.terminate() RETURNS void AS 'MODULE_PATHNAME','dbms_random_terminate' LANGUAGE C IMMUTABLE; COMMENT ON FUNCTION dbms_random.terminate() IS 'Terminate use of the Package'; CREATE FUNCTION dbms_random.value(low double precision, high double precision) RETURNS double precision AS 'MODULE_PATHNAME','dbms_random_value_range' LANGUAGE C STRICT VOLATILE; COMMENT ON FUNCTION dbms_random.value(double precision, double precision) IS 'Generate Random number x, where x is greater or equal to low and less then high'; CREATE FUNCTION dbms_random.value() RETURNS double precision AS 'MODULE_PATHNAME','dbms_random_value' LANGUAGE C VOLATILE; COMMENT ON FUNCTION dbms_random.value() IS 'Generate Random number x, where x is greater or equal to 0 and less then 1'; CREATE FUNCTION dump(text) RETURNS varchar AS 'MODULE_PATHNAME', 'orafce_dump' LANGUAGE C; CREATE FUNCTION dump(text, integer) RETURNS varchar AS 'MODULE_PATHNAME', 'orafce_dump' LANGUAGE C; CREATE FUNCTION utl_file.put_line(file utl_file.file_type, buffer anyelement) RETURNS bool AS $$SELECT utl_file.put_line($1, $2::text); $$ LANGUAGE SQL VOLATILE; COMMENT ON FUNCTION utl_file.put_line(utl_file.file_type, anyelement) IS 'Puts data to specified file and append newline character'; CREATE FUNCTION utl_file.put_line(file utl_file.file_type, buffer anyelement, autoflush bool) RETURNS bool AS $$SELECT utl_file.put_line($1, $2::text, true); $$ LANGUAGE SQL VOLATILE; COMMENT ON FUNCTION utl_file.put_line(utl_file.file_type, anyelement, bool) IS 'Puts data to specified file and append newline character'; CREATE FUNCTION pg_catalog.listagg1_transfn(internal, text) RETURNS internal AS 'MODULE_PATHNAME','orafce_listagg1_transfn' LANGUAGE C IMMUTABLE; CREATE FUNCTION pg_catalog.wm_concat_transfn(internal, text) RETURNS internal AS 'MODULE_PATHNAME','orafce_wm_concat_transfn' LANGUAGE C IMMUTABLE; CREATE FUNCTION pg_catalog.listagg2_transfn(internal, text, text) RETURNS internal AS 'MODULE_PATHNAME','orafce_listagg2_transfn' LANGUAGE C IMMUTABLE; CREATE FUNCTION pg_catalog.listagg_finalfn(internal) RETURNS text AS 'MODULE_PATHNAME','orafce_listagg_finalfn' LANGUAGE C IMMUTABLE; CREATE AGGREGATE pg_catalog.listagg(text) ( SFUNC=pg_catalog.listagg1_transfn, STYPE=internal, FINALFUNC=pg_catalog.listagg_finalfn ); /* * Undocumented function wm_concat - removed from * Oracle 12c. */ CREATE AGGREGATE pg_catalog.wm_concat(text) ( SFUNC=pg_catalog.wm_concat_transfn, STYPE=internal, FINALFUNC=pg_catalog.listagg_finalfn ); CREATE AGGREGATE pg_catalog.listagg(text, text) ( SFUNC=pg_catalog.listagg2_transfn, STYPE=internal, FINALFUNC=pg_catalog.listagg_finalfn ); CREATE FUNCTION pg_catalog.median4_transfn(internal, real) RETURNS internal AS 'MODULE_PATHNAME','orafce_median4_transfn' LANGUAGE C IMMUTABLE; CREATE FUNCTION pg_catalog.median4_finalfn(internal) RETURNS real AS 'MODULE_PATHNAME','orafce_median4_finalfn' LANGUAGE C IMMUTABLE; CREATE FUNCTION pg_catalog.median8_transfn(internal, double precision) RETURNS internal AS 'MODULE_PATHNAME','orafce_median8_transfn' LANGUAGE C IMMUTABLE; CREATE FUNCTION pg_catalog.median8_finalfn(internal) RETURNS double precision AS 'MODULE_PATHNAME','orafce_median8_finalfn' LANGUAGE C IMMUTABLE; CREATE AGGREGATE pg_catalog.median(real) ( SFUNC=pg_catalog.median4_transfn, STYPE=internal, FINALFUNC=pg_catalog.median4_finalfn ); CREATE AGGREGATE pg_catalog.median(double precision) ( SFUNC=pg_catalog.median8_transfn, STYPE=internal, FINALFUNC=pg_catalog.median8_finalfn ); -- oracle.varchar2 type support CREATE FUNCTION varchar2in(cstring,oid,integer) RETURNS varchar2 AS 'MODULE_PATHNAME','varchar2in' LANGUAGE C STRICT IMMUTABLE; CREATE FUNCTION varchar2out(varchar2) RETURNS CSTRING AS 'MODULE_PATHNAME','varchar2out' LANGUAGE C STRICT IMMUTABLE; CREATE FUNCTION varchar2_transform(internal) RETURNS internal AS 'MODULE_PATHNAME','orafce_varchar_transform' LANGUAGE C STRICT IMMUTABLE; CREATE FUNCTION varchar2recv(internal,oid,integer) RETURNS varchar2 AS 'MODULE_PATHNAME','varchar2recv' LANGUAGE C STRICT STABLE; CREATE FUNCTION varchar2send(varchar2) RETURNS bytea AS 'varcharsend' LANGUAGE internal STRICT STABLE; CREATE FUNCTION varchar2typmodin(cstring[]) RETURNS integer AS 'varchartypmodin' LANGUAGE internal STRICT IMMUTABLE; CREATE FUNCTION varchar2typmodout(integer) RETURNS CSTRING AS 'varchartypmodout' LANGUAGE internal STRICT IMMUTABLE; CREATE FUNCTION varchar2(varchar2,integer,boolean) RETURNS varchar2 AS 'MODULE_PATHNAME','varchar2' LANGUAGE C STRICT IMMUTABLE; /* CREATE TYPE */ CREATE TYPE varchar2 ( internallength = VARIABLE, input = varchar2in, output = varchar2out, receive = varchar2recv, send = varchar2send, category = 'S', typmod_in = varchar2typmodin, typmod_out = varchar2typmodout, collatable = true ); CREATE FUNCTION oracle.orafce_concat2(varchar2, varchar2) RETURNS varchar2 AS 'MODULE_PATHNAME','orafce_concat2' LANGUAGE C STABLE; /* CREATE CAST */ CREATE CAST (varchar2 AS text) WITHOUT FUNCTION AS IMPLICIT; CREATE CAST (text AS varchar2) WITHOUT FUNCTION AS IMPLICIT; CREATE CAST (varchar2 AS char) WITHOUT FUNCTION AS IMPLICIT; CREATE CAST (char AS varchar2) WITHOUT FUNCTION AS IMPLICIT; CREATE CAST (varchar2 AS varchar) WITHOUT FUNCTION AS IMPLICIT; CREATE CAST (varchar AS varchar2) WITHOUT FUNCTION AS IMPLICIT; CREATE CAST (varchar2 AS varchar2) WITH FUNCTION varchar2(varchar2,integer,boolean) AS IMPLICIT; CREATE CAST (varchar2 AS real) WITH INOUT AS IMPLICIT; CREATE CAST (real AS varchar2) WITH INOUT AS IMPLICIT; CREATE CAST (varchar2 AS double precision) WITH INOUT AS IMPLICIT; CREATE CAST (double precision AS varchar2) WITH INOUT AS IMPLICIT; CREATE CAST (varchar2 AS integer) WITH INOUT AS IMPLICIT; CREATE CAST (integer AS varchar2) WITH INOUT AS IMPLICIT; CREATE CAST (varchar2 AS smallint) WITH INOUT AS IMPLICIT; CREATE CAST (smallint AS varchar2) WITH INOUT AS IMPLICIT; CREATE CAST (varchar2 AS bigint) WITH INOUT AS IMPLICIT; CREATE CAST (bigint AS varchar2) WITH INOUT AS IMPLICIT; CREATE CAST (varchar2 AS numeric) WITH INOUT AS IMPLICIT; CREATE CAST (numeric AS varchar2) WITH INOUT AS IMPLICIT; CREATE CAST (varchar2 AS date) WITH INOUT AS IMPLICIT; CREATE CAST (date AS varchar2) WITH INOUT AS IMPLICIT; CREATE CAST (varchar2 AS timestamp) WITH INOUT AS IMPLICIT; CREATE CAST (timestamp AS varchar2) WITH INOUT AS IMPLICIT; CREATE CAST (varchar2 AS interval) WITH INOUT AS IMPLICIT; CREATE CAST (interval AS varchar2) WITH INOUT AS IMPLICIT; do $$ BEGIN IF EXISTS(SELECT * FROM pg_settings WHERE name = 'server_version_num' AND setting::int >= 120000) THEN UPDATE pg_proc SET prosupport= 'varchar2_transform'::regproc::oid WHERE proname='varchar2'; ELSE UPDATE pg_proc SET protransform= 'varchar2_transform'::regproc::oid WHERE proname='varchar2'; END IF; END $$; -- string functions for varchar2 type -- these are 'byte' versions of corresponsing text/varchar functions CREATE OR REPLACE FUNCTION pg_catalog.substrb(varchar2, integer, integer) RETURNS varchar2 AS 'bytea_substr' LANGUAGE internal STRICT IMMUTABLE; COMMENT ON FUNCTION pg_catalog.substrb(varchar2, integer, integer) IS 'extracts specified number of bytes from the input varchar2 string starting at the specified byte position (1-based) and returns as a varchar2 string'; CREATE OR REPLACE FUNCTION pg_catalog.substrb(varchar2, integer) RETURNS varchar2 AS 'bytea_substr_no_len' LANGUAGE internal STRICT IMMUTABLE; COMMENT ON FUNCTION pg_catalog.substrb(varchar2, integer) IS 'extracts specified number of bytes from the input varchar2 string starting at the specified byte position (1-based) and returns as a varchar2 string'; CREATE OR REPLACE FUNCTION pg_catalog.lengthb(varchar2) RETURNS integer AS 'byteaoctetlen' LANGUAGE internal STRICT IMMUTABLE; COMMENT ON FUNCTION pg_catalog.lengthb(varchar2) IS 'returns byte length of the input varchar2 string'; CREATE OR REPLACE FUNCTION pg_catalog.strposb(varchar2, varchar2) RETURNS integer AS 'byteapos' LANGUAGE internal STRICT IMMUTABLE; COMMENT ON FUNCTION pg_catalog.strposb(varchar2, varchar2) IS 'returns the byte position of a specified string in the input varchar2 string'; -- oracle.nvarchar2 type support CREATE FUNCTION nvarchar2in(cstring,oid,integer) RETURNS nvarchar2 AS 'MODULE_PATHNAME','nvarchar2in' LANGUAGE C STRICT IMMUTABLE; CREATE FUNCTION nvarchar2out(nvarchar2) RETURNS CSTRING AS 'MODULE_PATHNAME','nvarchar2out' LANGUAGE C STRICT IMMUTABLE; CREATE FUNCTION nvarchar2_transform(internal) RETURNS internal AS 'MODULE_PATHNAME','orafce_varchar_transform' LANGUAGE C STRICT IMMUTABLE; CREATE FUNCTION nvarchar2recv(internal,oid,integer) RETURNS nvarchar2 AS 'MODULE_PATHNAME','nvarchar2recv' LANGUAGE C STRICT STABLE; CREATE FUNCTION nvarchar2send(nvarchar2) RETURNS bytea AS 'varcharsend' LANGUAGE internal STRICT STABLE; CREATE FUNCTION nvarchar2typmodin(cstring[]) RETURNS integer AS 'varchartypmodin' LANGUAGE internal STRICT IMMUTABLE; CREATE FUNCTION nvarchar2typmodout(integer) RETURNS CSTRING AS 'varchartypmodout' LANGUAGE internal STRICT IMMUTABLE; CREATE FUNCTION nvarchar2(nvarchar2,integer,boolean) RETURNS nvarchar2 AS 'MODULE_PATHNAME','nvarchar2' LANGUAGE C STRICT IMMUTABLE; /* CREATE TYPE */ CREATE TYPE nvarchar2 ( internallength = VARIABLE, input = nvarchar2in, output = nvarchar2out, receive = nvarchar2recv, send = nvarchar2send, category = 'S', typmod_in = nvarchar2typmodin, typmod_out = nvarchar2typmodout, collatable = true ); CREATE FUNCTION oracle.orafce_concat2(nvarchar2, nvarchar2) RETURNS nvarchar2 AS 'MODULE_PATHNAME','orafce_concat2' LANGUAGE C IMMUTABLE; /* CREATE CAST */ CREATE CAST (nvarchar2 AS text) WITHOUT FUNCTION AS IMPLICIT; CREATE CAST (text AS nvarchar2) WITHOUT FUNCTION AS IMPLICIT; CREATE CAST (nvarchar2 AS char) WITHOUT FUNCTION AS IMPLICIT; CREATE CAST (char AS nvarchar2) WITHOUT FUNCTION AS IMPLICIT; CREATE CAST (nvarchar2 AS varchar) WITHOUT FUNCTION AS IMPLICIT; CREATE CAST (varchar AS nvarchar2) WITHOUT FUNCTION AS IMPLICIT; CREATE CAST (nvarchar2 AS nvarchar2) WITH FUNCTION nvarchar2(nvarchar2, integer, boolean) AS IMPLICIT; CREATE CAST (nvarchar2 AS real) WITH INOUT AS IMPLICIT; CREATE CAST (real AS nvarchar2) WITH INOUT AS IMPLICIT; CREATE CAST (nvarchar2 AS double precision) WITH INOUT AS IMPLICIT; CREATE CAST (double precision AS nvarchar2) WITH INOUT AS IMPLICIT; CREATE CAST (nvarchar2 AS integer) WITH INOUT AS IMPLICIT; CREATE CAST (integer AS nvarchar2) WITH INOUT AS IMPLICIT; CREATE CAST (nvarchar2 AS smallint) WITH INOUT AS IMPLICIT; CREATE CAST (smallint AS nvarchar2) WITH INOUT AS IMPLICIT; CREATE CAST (nvarchar2 AS bigint) WITH INOUT AS IMPLICIT; CREATE CAST (bigint AS nvarchar2) WITH INOUT AS IMPLICIT; CREATE CAST (nvarchar2 AS numeric) WITH INOUT AS IMPLICIT; CREATE CAST (numeric AS nvarchar2) WITH INOUT AS IMPLICIT; CREATE CAST (nvarchar2 AS date) WITH INOUT AS IMPLICIT; CREATE CAST (date AS nvarchar2) WITH INOUT AS IMPLICIT; CREATE CAST (nvarchar2 AS timestamp) WITH INOUT AS IMPLICIT; CREATE CAST (timestamp AS nvarchar2) WITH INOUT AS IMPLICIT; CREATE CAST (nvarchar2 AS interval) WITH INOUT AS IMPLICIT; CREATE CAST (interval AS nvarchar2) WITH INOUT AS IMPLICIT; do $$ BEGIN IF EXISTS(SELECT * FROM pg_settings WHERE name = 'server_version_num' AND setting::int >= 120000) THEN UPDATE pg_proc SET prosupport='nvarchar2_transform'::regproc::oid WHERE proname='nvarchar2'; ELSE UPDATE pg_proc SET protransform='nvarchar2_transform'::regproc::oid WHERE proname='nvarchar2'; END IF; END $$; /* * Note - a procedure keyword is depraceted from PostgreSQL 11, but it used * because older release doesn't know function. * */ CREATE OPERATOR || (procedure = oracle.orafce_concat2, leftarg = varchar2, rightarg = varchar2); CREATE OPERATOR || (procedure = oracle.orafce_concat2, leftarg = nvarchar2, rightarg = nvarchar2); /* PAD */ /* LPAD family */ /* Incompatibility #1: * pg_catalog.lpad removes trailing blanks of CHAR arguments * because of implicit cast to text * * Incompatibility #2: * pg_catalog.lpad considers character length, NOT display length * so, add functions to use custom C implementation of lpad as defined * in charpad.c */ CREATE FUNCTION oracle.lpad(char, integer, char) RETURNS text AS 'MODULE_PATHNAME','orafce_lpad' LANGUAGE 'c' STRICT IMMUTABLE ; CREATE FUNCTION oracle.lpad(char, integer, text) RETURNS text AS 'MODULE_PATHNAME','orafce_lpad' LANGUAGE 'c' STRICT IMMUTABLE ; CREATE FUNCTION oracle.lpad(char, integer, varchar2) RETURNS text AS 'MODULE_PATHNAME','orafce_lpad' LANGUAGE 'c' STRICT IMMUTABLE ; CREATE FUNCTION oracle.lpad(char, integer, nvarchar2) RETURNS text AS 'MODULE_PATHNAME','orafce_lpad' LANGUAGE 'c' STRICT IMMUTABLE ; CREATE FUNCTION oracle.lpad(char, integer) RETURNS text AS $$ SELECT oracle.lpad($1, $2, ' '::text); $$ LANGUAGE SQL STRICT IMMUTABLE ; CREATE FUNCTION oracle.lpad(text, integer, char) RETURNS text AS 'MODULE_PATHNAME','orafce_lpad' LANGUAGE 'c' STRICT IMMUTABLE ; CREATE FUNCTION oracle.lpad(varchar2, integer, char) RETURNS text AS 'MODULE_PATHNAME','orafce_lpad' LANGUAGE 'c' STRICT IMMUTABLE ; CREATE FUNCTION oracle.lpad(nvarchar2, integer, char) RETURNS text AS 'MODULE_PATHNAME','orafce_lpad' LANGUAGE 'c' STRICT IMMUTABLE ; CREATE FUNCTION oracle.lpad(text, integer, text) RETURNS text AS 'MODULE_PATHNAME','orafce_lpad' LANGUAGE 'c' STRICT IMMUTABLE ; CREATE FUNCTION oracle.lpad(text, integer, varchar2) RETURNS text AS 'MODULE_PATHNAME','orafce_lpad' LANGUAGE 'c' STRICT IMMUTABLE ; CREATE FUNCTION oracle.lpad(text, integer, nvarchar2) RETURNS text AS 'MODULE_PATHNAME','orafce_lpad' LANGUAGE 'c' STRICT IMMUTABLE ; CREATE FUNCTION oracle.lpad(text, integer) RETURNS text AS $$ SELECT oracle.lpad($1, $2, ' '::text); $$ LANGUAGE SQL STRICT IMMUTABLE ; CREATE FUNCTION oracle.lpad(varchar2, integer, text) RETURNS text AS 'MODULE_PATHNAME','orafce_lpad' LANGUAGE 'c' STRICT IMMUTABLE ; CREATE FUNCTION oracle.lpad(varchar2, integer, varchar2) RETURNS text AS 'MODULE_PATHNAME','orafce_lpad' LANGUAGE 'c' STRICT IMMUTABLE ; CREATE FUNCTION oracle.lpad(varchar2, integer, nvarchar2) RETURNS text AS 'MODULE_PATHNAME','orafce_lpad' LANGUAGE 'c' STRICT IMMUTABLE ; CREATE FUNCTION oracle.lpad(varchar2, integer) RETURNS text AS $$ SELECT oracle.lpad($1, $2, ' '::text); $$ LANGUAGE SQL STRICT IMMUTABLE ; CREATE FUNCTION oracle.lpad(nvarchar2, integer, text) RETURNS text AS 'MODULE_PATHNAME','orafce_lpad' LANGUAGE 'c' STRICT IMMUTABLE ; CREATE FUNCTION oracle.lpad(nvarchar2, integer, varchar2) RETURNS text AS 'MODULE_PATHNAME','orafce_lpad' LANGUAGE 'c' STRICT IMMUTABLE ; CREATE FUNCTION oracle.lpad(nvarchar2, integer, nvarchar2) RETURNS text AS 'MODULE_PATHNAME','orafce_lpad' LANGUAGE 'c' STRICT IMMUTABLE ; CREATE FUNCTION oracle.lpad(nvarchar2, integer) RETURNS text AS $$ SELECT oracle.lpad($1, $2, ' '::text); $$ LANGUAGE SQL STRICT IMMUTABLE ; /* RPAD family */ /* Incompatibility #1: * pg_catalog.rpad removes trailing blanks of CHAR arguments * because of implicit cast to text * * Incompatibility #2: * pg_catalog.rpad considers character length, NOT display length * so, add functions to use custom C implementation of rpad as defined * in charpad.c */ CREATE FUNCTION oracle.rpad(char, integer, char) RETURNS text AS 'MODULE_PATHNAME','orafce_rpad' LANGUAGE 'c' STRICT IMMUTABLE ; CREATE FUNCTION oracle.rpad(char, integer, text) RETURNS text AS 'MODULE_PATHNAME','orafce_rpad' LANGUAGE 'c' STRICT IMMUTABLE ; CREATE FUNCTION oracle.rpad(char, integer, varchar2) RETURNS text AS 'MODULE_PATHNAME','orafce_rpad' LANGUAGE 'c' STRICT IMMUTABLE ; CREATE FUNCTION oracle.rpad(char, integer, nvarchar2) RETURNS text AS 'MODULE_PATHNAME','orafce_rpad' LANGUAGE 'c' STRICT IMMUTABLE ; CREATE FUNCTION oracle.rpad(char, integer) RETURNS text AS $$ SELECT oracle.rpad($1, $2, ' '::text); $$ LANGUAGE SQL STRICT IMMUTABLE ; CREATE FUNCTION oracle.rpad(text, integer, char) RETURNS text AS 'MODULE_PATHNAME','orafce_rpad' LANGUAGE 'c' STRICT IMMUTABLE ; CREATE FUNCTION oracle.rpad(varchar2, integer, char) RETURNS text AS 'MODULE_PATHNAME','orafce_rpad' LANGUAGE 'c' STRICT IMMUTABLE ; CREATE FUNCTION oracle.rpad(nvarchar2, integer, char) RETURNS text AS 'MODULE_PATHNAME','orafce_rpad' LANGUAGE 'c' STRICT IMMUTABLE ; CREATE FUNCTION oracle.rpad(text, integer, text) RETURNS text AS 'MODULE_PATHNAME','orafce_rpad' LANGUAGE 'c' STRICT IMMUTABLE ; CREATE FUNCTION oracle.rpad(text, integer, varchar2) RETURNS text AS 'MODULE_PATHNAME','orafce_rpad' LANGUAGE 'c' STRICT IMMUTABLE ; CREATE FUNCTION oracle.rpad(text, integer, nvarchar2) RETURNS text AS 'MODULE_PATHNAME','orafce_rpad' LANGUAGE 'c' STRICT IMMUTABLE ; CREATE FUNCTION oracle.rpad(text, integer) RETURNS text AS $$ SELECT oracle.rpad($1, $2, ' '::text); $$ LANGUAGE SQL STRICT IMMUTABLE ; CREATE FUNCTION oracle.rpad(varchar2, integer, text) RETURNS text AS 'MODULE_PATHNAME','orafce_rpad' LANGUAGE 'c' STRICT IMMUTABLE ; CREATE FUNCTION oracle.rpad(varchar2, integer, varchar2) RETURNS text AS 'MODULE_PATHNAME','orafce_rpad' LANGUAGE 'c' STRICT IMMUTABLE ; CREATE FUNCTION oracle.rpad(varchar2, integer, nvarchar2) RETURNS text AS 'MODULE_PATHNAME','orafce_rpad' LANGUAGE 'c' STRICT IMMUTABLE ; CREATE FUNCTION oracle.rpad(varchar2, integer) RETURNS text AS $$ SELECT oracle.rpad($1, $2, ' '::text); $$ LANGUAGE SQL STRICT IMMUTABLE ; CREATE FUNCTION oracle.rpad(nvarchar2, integer, text) RETURNS text AS 'MODULE_PATHNAME','orafce_rpad' LANGUAGE 'c' STRICT IMMUTABLE ; CREATE FUNCTION oracle.rpad(nvarchar2, integer, varchar2) RETURNS text AS 'MODULE_PATHNAME','orafce_rpad' LANGUAGE 'c' STRICT IMMUTABLE ; CREATE FUNCTION oracle.rpad(nvarchar2, integer, nvarchar2) RETURNS text AS 'MODULE_PATHNAME','orafce_rpad' LANGUAGE 'c' STRICT IMMUTABLE ; CREATE FUNCTION oracle.rpad(nvarchar2, integer) RETURNS text AS $$ SELECT oracle.rpad($1, $2, ' '::text); $$ LANGUAGE SQL STRICT IMMUTABLE ; /* TRIM */ /* Incompatibility #1: * pg_catalog.ltrim, pg_catalog.rtrim and pg_catalog.btrim remove * trailing blanks of CHAR arguments because of implicit cast to * text * * Following re-definitions address this incompatbility so that * trailing blanks of CHAR arguments are preserved and considered * significant for the trimming process. */ /* LTRIM family */ CREATE FUNCTION oracle.ltrim(char, char) RETURNS text AS 'ltrim' LANGUAGE internal STRICT IMMUTABLE ; CREATE FUNCTION oracle.ltrim(char, text) RETURNS text AS 'ltrim' LANGUAGE internal STRICT IMMUTABLE ; CREATE FUNCTION oracle.ltrim(char, varchar2) RETURNS text AS 'ltrim' LANGUAGE internal STRICT IMMUTABLE ; CREATE FUNCTION oracle.ltrim(char, nvarchar2) RETURNS text AS 'ltrim' LANGUAGE internal STRICT IMMUTABLE ; CREATE FUNCTION oracle.ltrim(char) RETURNS text AS $$ SELECT oracle.ltrim($1, ' '::text) $$ LANGUAGE SQL STRICT IMMUTABLE ; CREATE FUNCTION oracle.ltrim(text, char) RETURNS text AS 'ltrim' LANGUAGE internal STRICT IMMUTABLE ; CREATE FUNCTION oracle.ltrim(text, text) RETURNS text AS 'ltrim' LANGUAGE internal STRICT IMMUTABLE ; CREATE FUNCTION oracle.ltrim(text, varchar2) RETURNS text AS 'ltrim' LANGUAGE internal STRICT IMMUTABLE ; CREATE FUNCTION oracle.ltrim(text, nvarchar2) RETURNS text AS 'ltrim' LANGUAGE internal STRICT IMMUTABLE ; CREATE FUNCTION oracle.ltrim(text) RETURNS text AS $$ SELECT oracle.ltrim($1, ' '::text) $$ LANGUAGE SQL STRICT IMMUTABLE ; CREATE FUNCTION oracle.ltrim(varchar2, char) RETURNS text AS 'ltrim' LANGUAGE internal STRICT IMMUTABLE ; CREATE FUNCTION oracle.ltrim(varchar2, text) RETURNS text AS 'ltrim' LANGUAGE internal STRICT IMMUTABLE ; CREATE FUNCTION oracle.ltrim(varchar2, varchar2) RETURNS text AS 'ltrim' LANGUAGE internal STRICT IMMUTABLE ; CREATE FUNCTION oracle.ltrim(varchar2, nvarchar2) RETURNS text AS 'ltrim' LANGUAGE internal STRICT IMMUTABLE ; CREATE FUNCTION oracle.ltrim(varchar2) RETURNS text AS $$ SELECT oracle.ltrim($1, ' '::text) $$ LANGUAGE SQL STRICT IMMUTABLE ; CREATE FUNCTION oracle.ltrim(nvarchar2, char) RETURNS text AS 'ltrim' LANGUAGE internal STRICT IMMUTABLE ; CREATE FUNCTION oracle.ltrim(nvarchar2, text) RETURNS text AS 'ltrim' LANGUAGE internal STRICT IMMUTABLE ; CREATE FUNCTION oracle.ltrim(nvarchar2, varchar2) RETURNS text AS 'ltrim' LANGUAGE internal STRICT IMMUTABLE ; CREATE FUNCTION oracle.ltrim(nvarchar2, nvarchar2) RETURNS text AS 'ltrim' LANGUAGE internal STRICT IMMUTABLE ; CREATE FUNCTION oracle.ltrim(nvarchar2) RETURNS text AS $$ SELECT oracle.ltrim($1, ' '::text) $$ LANGUAGE SQL STRICT IMMUTABLE ; /* RTRIM family */ CREATE FUNCTION oracle.rtrim(char, char) RETURNS text AS 'rtrim' LANGUAGE internal STRICT IMMUTABLE ; CREATE FUNCTION oracle.rtrim(char, text) RETURNS text AS 'rtrim' LANGUAGE internal STRICT IMMUTABLE ; CREATE FUNCTION oracle.rtrim(char, varchar2) RETURNS text AS 'rtrim' LANGUAGE internal STRICT IMMUTABLE ; CREATE FUNCTION oracle.rtrim(char, nvarchar2) RETURNS text AS 'rtrim' LANGUAGE internal STRICT IMMUTABLE ; CREATE FUNCTION oracle.rtrim(char) RETURNS text AS $$ SELECT oracle.rtrim($1, ' '::text) $$ LANGUAGE SQL STRICT IMMUTABLE ; CREATE FUNCTION oracle.rtrim(text, char) RETURNS text AS 'rtrim' LANGUAGE internal STRICT IMMUTABLE ; CREATE FUNCTION oracle.rtrim(text, text) RETURNS text AS 'rtrim' LANGUAGE internal STRICT IMMUTABLE ; CREATE FUNCTION oracle.rtrim(text, varchar2) RETURNS text AS 'rtrim' LANGUAGE internal STRICT IMMUTABLE ; CREATE FUNCTION oracle.rtrim(text, nvarchar2) RETURNS text AS 'rtrim' LANGUAGE internal STRICT IMMUTABLE ; CREATE FUNCTION oracle.rtrim(text) RETURNS text AS $$ SELECT oracle.rtrim($1, ' '::text) $$ LANGUAGE SQL STRICT IMMUTABLE ; CREATE FUNCTION oracle.rtrim(varchar2, char) RETURNS text AS 'rtrim' LANGUAGE internal STRICT IMMUTABLE ; CREATE FUNCTION oracle.rtrim(varchar2, text) RETURNS text AS 'rtrim' LANGUAGE internal STRICT IMMUTABLE ; CREATE FUNCTION oracle.rtrim(varchar2, varchar2) RETURNS text AS 'rtrim' LANGUAGE internal STRICT IMMUTABLE ; CREATE FUNCTION oracle.rtrim(varchar2, nvarchar2) RETURNS text AS 'rtrim' LANGUAGE internal STRICT IMMUTABLE ; CREATE FUNCTION oracle.rtrim(varchar2) RETURNS text AS $$ SELECT oracle.rtrim($1, ' '::text) $$ LANGUAGE SQL STRICT IMMUTABLE ; CREATE FUNCTION oracle.rtrim(nvarchar2, char) RETURNS text AS 'rtrim' LANGUAGE internal STRICT IMMUTABLE ; CREATE FUNCTION oracle.rtrim(nvarchar2, text) RETURNS text AS 'rtrim' LANGUAGE internal STRICT IMMUTABLE ; CREATE FUNCTION oracle.rtrim(nvarchar2, varchar2) RETURNS text AS 'rtrim' LANGUAGE internal STRICT IMMUTABLE ; CREATE FUNCTION oracle.rtrim(nvarchar2, nvarchar2) RETURNS text AS 'rtrim' LANGUAGE internal STRICT IMMUTABLE ; CREATE FUNCTION oracle.rtrim(nvarchar2) RETURNS text AS $$ SELECT oracle.rtrim($1, ' '::text) $$ LANGUAGE SQL STRICT IMMUTABLE ; /* BTRIM family */ CREATE FUNCTION oracle.btrim(char, char) RETURNS text AS 'btrim' LANGUAGE internal STRICT IMMUTABLE ; CREATE FUNCTION oracle.btrim(char, text) RETURNS text AS 'btrim' LANGUAGE internal STRICT IMMUTABLE ; CREATE FUNCTION oracle.btrim(char, varchar2) RETURNS text AS 'btrim' LANGUAGE internal STRICT IMMUTABLE ; CREATE FUNCTION oracle.btrim(char, nvarchar2) RETURNS text AS 'btrim' LANGUAGE internal STRICT IMMUTABLE ; CREATE FUNCTION oracle.btrim(char) RETURNS text AS $$ SELECT oracle.btrim($1, ' '::text) $$ LANGUAGE SQL STRICT IMMUTABLE ; CREATE FUNCTION oracle.btrim(text, char) RETURNS text AS 'btrim' LANGUAGE internal STRICT IMMUTABLE ; CREATE FUNCTION oracle.btrim(text, text) RETURNS text AS 'btrim' LANGUAGE internal STRICT IMMUTABLE ; CREATE FUNCTION oracle.btrim(text, varchar2) RETURNS text AS 'btrim' LANGUAGE internal STRICT IMMUTABLE ; CREATE FUNCTION oracle.btrim(text, nvarchar2) RETURNS text AS 'btrim' LANGUAGE internal STRICT IMMUTABLE ; CREATE FUNCTION oracle.btrim(text) RETURNS text AS $$ SELECT oracle.btrim($1, ' '::text) $$ LANGUAGE SQL STRICT IMMUTABLE ; CREATE FUNCTION oracle.btrim(varchar2, char) RETURNS text AS 'btrim' LANGUAGE internal STRICT IMMUTABLE ; CREATE FUNCTION oracle.btrim(varchar2, text) RETURNS text AS 'btrim' LANGUAGE internal STRICT IMMUTABLE ; CREATE FUNCTION oracle.btrim(varchar2, varchar2) RETURNS text AS 'btrim' LANGUAGE internal STRICT IMMUTABLE ; CREATE FUNCTION oracle.btrim(varchar2, nvarchar2) RETURNS text AS 'btrim' LANGUAGE internal STRICT IMMUTABLE ; CREATE FUNCTION oracle.btrim(varchar2) RETURNS text AS $$ SELECT oracle.btrim($1, ' '::text) $$ LANGUAGE SQL STRICT IMMUTABLE ; CREATE FUNCTION oracle.btrim(nvarchar2, char) RETURNS text AS 'btrim' LANGUAGE internal STRICT IMMUTABLE ; CREATE FUNCTION oracle.btrim(nvarchar2, text) RETURNS text AS 'btrim' LANGUAGE internal STRICT IMMUTABLE ; CREATE FUNCTION oracle.btrim(nvarchar2, varchar2) RETURNS text AS 'btrim' LANGUAGE internal STRICT IMMUTABLE ; CREATE FUNCTION oracle.btrim(nvarchar2, nvarchar2) RETURNS text AS 'btrim' LANGUAGE internal STRICT IMMUTABLE ; CREATE FUNCTION oracle.btrim(nvarchar2) RETURNS text AS $$ SELECT oracle.btrim($1, ' '::text) $$ LANGUAGE SQL STRICT IMMUTABLE ; /* LENGTH */ CREATE FUNCTION oracle.length(char) RETURNS integer AS 'MODULE_PATHNAME','orafce_bpcharlen' LANGUAGE 'c' STRICT IMMUTABLE ; GRANT USAGE ON SCHEMA dbms_pipe TO PUBLIC; GRANT USAGE ON SCHEMA dbms_alert TO PUBLIC; GRANT USAGE ON SCHEMA plvdate TO PUBLIC; GRANT USAGE ON SCHEMA plvstr TO PUBLIC; GRANT USAGE ON SCHEMA plvchr TO PUBLIC; GRANT USAGE ON SCHEMA dbms_output TO PUBLIC; GRANT USAGE ON SCHEMA plvsubst TO PUBLIC; GRANT SELECT ON dbms_pipe.db_pipes to PUBLIC; GRANT USAGE ON SCHEMA dbms_utility TO PUBLIC; GRANT USAGE ON SCHEMA plvlex TO PUBLIC; GRANT USAGE ON SCHEMA utl_file TO PUBLIC; GRANT USAGE ON SCHEMA dbms_assert TO PUBLIC; GRANT USAGE ON SCHEMA dbms_random TO PUBLIC; GRANT USAGE ON SCHEMA oracle TO PUBLIC; GRANT USAGE ON SCHEMA plunit TO PUBLIC; /* orafce 3.3. related changes */ ALTER FUNCTION dbms_assert.enquote_name ( character varying ) STRICT; ALTER FUNCTION dbms_assert.enquote_name ( character varying, boolean ) STRICT; ALTER FUNCTION dbms_assert.noop ( character varying ) STRICT; CREATE FUNCTION pg_catalog.trunc(value timestamp without time zone, fmt text) RETURNS timestamp without time zone AS 'MODULE_PATHNAME', 'ora_timestamp_trunc' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION pg_catalog.trunc(timestamp without time zone, text) IS 'truncate date according to the specified format'; CREATE FUNCTION pg_catalog.round(value timestamp without time zone, fmt text) RETURNS timestamp without time zone AS 'MODULE_PATHNAME','ora_timestamp_round' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION pg_catalog.round(timestamp with time zone, text) IS 'round dates according to the specified format'; CREATE FUNCTION pg_catalog.round(value timestamp without time zone) RETURNS timestamp without time zone AS $$ SELECT pg_catalog.round($1, 'DDD'); $$ LANGUAGE SQL IMMUTABLE STRICT; COMMENT ON FUNCTION pg_catalog.round(timestamp without time zone) IS 'will round dates according to the specified format'; CREATE FUNCTION pg_catalog.trunc(value timestamp without time zone) RETURNS timestamp without time zone AS $$ SELECT pg_catalog.trunc($1, 'DDD'); $$ LANGUAGE SQL IMMUTABLE STRICT; COMMENT ON FUNCTION pg_catalog.trunc(timestamp without time zone) IS 'truncate date according to the specified format'; CREATE OR REPLACE FUNCTION oracle.round(double precision, int) RETURNS numeric AS $$SELECT pg_catalog.round($1::numeric, $2)$$ LANGUAGE sql IMMUTABLE STRICT; CREATE OR REPLACE FUNCTION oracle.trunc(double precision, int) RETURNS numeric AS $$SELECT pg_catalog.trunc($1::numeric, $2)$$ LANGUAGE sql IMMUTABLE STRICT; CREATE OR REPLACE FUNCTION oracle.round(float4, int) RETURNS numeric AS $$SELECT pg_catalog.round($1::numeric, $2)$$ LANGUAGE sql IMMUTABLE STRICT; CREATE OR REPLACE FUNCTION oracle.trunc(float4, int) RETURNS numeric AS $$SELECT pg_catalog.trunc($1::numeric, $2)$$ LANGUAGE sql IMMUTABLE STRICT; CREATE FUNCTION oracle.get_major_version() RETURNS text AS 'MODULE_PATHNAME','ora_get_major_version' LANGUAGE 'c' STRICT IMMUTABLE; CREATE FUNCTION oracle.get_major_version_num() RETURNS text AS 'MODULE_PATHNAME','ora_get_major_version_num' LANGUAGE 'c' STRICT IMMUTABLE; CREATE FUNCTION oracle.get_full_version_num() RETURNS text AS 'MODULE_PATHNAME','ora_get_full_version_num' LANGUAGE 'c' STRICT IMMUTABLE; CREATE FUNCTION oracle.get_platform() RETURNS text AS 'MODULE_PATHNAME','ora_get_platform' LANGUAGE 'c' STRICT IMMUTABLE; CREATE FUNCTION oracle.get_status() RETURNS text AS 'MODULE_PATHNAME','ora_get_status' LANGUAGE 'c' STRICT IMMUTABLE; -- Oracle system views create view oracle.user_tab_columns as select table_name, column_name, data_type, coalesce(character_maximum_length, numeric_precision) AS data_length, numeric_precision AS data_precision, numeric_scale AS data_scale, is_nullable AS nullable, ordinal_position AS column_id, is_updatable AS data_upgraded, table_schema from information_schema.columns; create view oracle.user_tables as select table_name from information_schema.tables where table_type = 'BASE TABLE'; create view oracle.user_cons_columns as select constraint_name, column_name, table_name from information_schema.constraint_column_usage ; create view oracle.user_constraints as select conname as constraint_name, conindid::regclass as index_name, case contype when 'p' then 'P' when 'f' then 'R' end as constraint_type, conrelid::regclass as table_name, case contype when 'f' then (select conname from pg_constraint c2 where contype = 'p' and c2.conindid = c1.conindid) end as r_constraint_name from pg_constraint c1, pg_class where conrelid = pg_class.oid; create view oracle.product_component_version as select oracle.get_major_version() as product, oracle.get_full_version_num() as version, oracle.get_platform() || ' ' || oracle.get_status() as status union all select extname, case when extname = 'plpgsql' then oracle.get_full_version_num() else extversion end, oracle.get_platform() || ' ' || oracle.get_status() from pg_extension; create view oracle.user_objects as select relname as object_name, null::text as subject_name, c.oid as object_id, case relkind when 'r' then 'TABLE' when 'i' then 'INDEX' when 'S' then 'SEQUENCE' when 'v' then 'VIEW' when 'm' then 'VIEW' when 'f' then 'FOREIGN TABLE' end as object_type, null::timestamp(0) as created, null::timestamp(0) as last_ddl_time, case when relkind = 'i' then (select case when indisvalid then 'VALID' else 'INVALID' end from pg_index where indexrelid = c.oid) else case when relispopulated then 'VALID' else 'INVALID' end end as status, relnamespace as namespace from pg_class c join pg_namespace n on c.relnamespace = n.oid where relkind not in ('t','c') and nspname not in ('pg_toast','pg_catalog','information_schema') union all select tgname, null, t.oid, 'TRIGGER',null, null,'VALID', relnamespace from pg_trigger t join pg_class c on t.tgrelid = c.oid where not tgisinternal union all select proname, null, p.oid, 'FUNCTION', null, null, 'VALID', pronamespace from pg_proc p join pg_namespace n on p.pronamespace = n.oid where nspname not in ('pg_toast','pg_catalog','information_schema') order by 1; create view oracle.user_procedures as select proname as object_name from pg_proc p join pg_namespace n on p.pronamespace = n.oid and nspname <> 'pg_catalog'; create view oracle.user_source as select row_number() over (partition by oid) as line, * from ( select oid, unnest(string_to_array(prosrc, e'\n')) as text, proname as name, 'FUNCTION'::text as type from pg_proc) s; create view oracle.user_views as select c.relname as view_name, pg_catalog.pg_get_userbyid(c.relowner) as owner from pg_catalog.pg_class c left join pg_catalog.pg_namespace n on n.oid = c.relnamespace where c.relkind in ('v','') and n.nspname <> 'pg_catalog' and n.nspname <> 'information_schema' and n.nspname !~ '^pg_toast' and pg_catalog.pg_table_is_visible(c.oid); create view oracle.user_ind_columns as select attname as column_name, c1.relname as index_name, c2.relname as table_name from (select unnest(indkey) attno, indexrelid, indrelid from pg_index) s join pg_attribute on attno = attnum and attrelid = indrelid join pg_class c1 on indexrelid = c1.oid join pg_class c2 on indrelid = c2.oid join pg_namespace n on c2.relnamespace = n.oid where attno > 0 and nspname not in ('pg_catalog','information_schema'); CREATE VIEW oracle.dba_segments AS SELECT pg_namespace.nspname AS owner, pg_class.relname AS segment_name, CASE WHEN pg_class.relkind = 'r' THEN CAST( 'TABLE' AS VARCHAR( 18 ) ) WHEN pg_class.relkind = 'i' THEN CAST( 'INDEX' AS VARCHAR( 18 ) ) WHEN pg_class.relkind = 'f' THEN CAST( 'FOREIGN TABLE' AS VARCHAR( 18 ) ) WHEN pg_class.relkind = 'S' THEN CAST( 'SEQUENCE' AS VARCHAR( 18 ) ) WHEN pg_class.relkind = 's' THEN CAST( 'SPECIAL' AS VARCHAR( 18 ) ) WHEN pg_class.relkind = 't' THEN CAST( 'TOAST TABLE' AS VARCHAR( 18 ) ) WHEN pg_class.relkind = 'v' THEN CAST( 'VIEW' AS VARCHAR( 18 ) ) ELSE CAST( pg_class.relkind AS VARCHAR( 18 ) ) END AS segment_type, spcname AS tablespace_name, relfilenode AS header_file, NULL::oid AS header_block, pg_relation_size( pg_class.oid ) AS bytes, relpages AS blocks FROM pg_class INNER JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid LEFT OUTER JOIN pg_tablespace ON pg_class.reltablespace = pg_tablespace.oid WHERE pg_class.relkind not in ('f','S','v'); -- Oracle dirty functions CREATE OR REPLACE FUNCTION oracle.lpad(int, int, int) RETURNS text AS $$ SELECT pg_catalog.lpad($1::text,$2,$3::text) $$ LANGUAGE sql IMMUTABLE STRICT; CREATE OR REPLACE FUNCTION oracle.lpad(bigint, int, int) RETURNS text AS $$ SELECT pg_catalog.lpad($1::text,$2,$3::text) $$ LANGUAGE sql IMMUTABLE STRICT; CREATE OR REPLACE FUNCTION oracle.lpad(smallint, int, int) RETURNS text AS $$ SELECT pg_catalog.lpad($1::text,$2,$3::text) $$ LANGUAGE sql IMMUTABLE STRICT; CREATE OR REPLACE FUNCTION oracle.lpad(numeric, int, int) RETURNS text AS $$ SELECT pg_catalog.lpad($1::text,$2,$3::text) $$ LANGUAGE sql IMMUTABLE STRICT; CREATE OR REPLACE FUNCTION oracle.nvl(bigint, int) RETURNS bigint AS $$ SELECT coalesce($1, $2) $$ LANGUAGE sql IMMUTABLE; CREATE OR REPLACE FUNCTION oracle.nvl(numeric, int) RETURNS numeric AS $$ SELECT coalesce($1, $2) $$ LANGUAGE sql IMMUTABLE; CREATE OR REPLACE FUNCTION oracle.nvl(int, int) RETURNS int AS $$ SELECT coalesce($1, $2) $$ LANGUAGE sql IMMUTABLE; CREATE OR REPLACE FUNCTION oracle.numtodsinterval(double precision, text) RETURNS interval AS $$ SELECT $1 * ('1' || $2)::interval $$ LANGUAGE sql IMMUTABLE STRICT; orafce-VERSION_3_9_0/orafce.c000066400000000000000000000022731362147214200157420ustar00rootroot00000000000000#include "postgres.h" #include "storage/lwlock.h" #include "storage/shmem.h" #include "utils/guc.h" #include "commands/variable.h" #include "orafce.h" #include "builtins.h" #include "pipe.h" /* default value */ char *nls_date_format = NULL; char *orafce_timezone = NULL; void _PG_init(void) { #if PG_VERSION_NUM < 90600 RequestAddinLWLocks(1); #endif RequestAddinShmemSpace(SHMEMMSGSZ); /* Define custom GUC variables. */ DefineCustomStringVariable("orafce.nls_date_format", "Emulate oracle's date output behaviour.", NULL, &nls_date_format, NULL, PGC_USERSET, 0, NULL, NULL, NULL); DefineCustomStringVariable("orafce.timezone", "Specify timezone used for sysdate function.", NULL, &orafce_timezone, "GMT", PGC_USERSET, 0, check_timezone, NULL, show_timezone); DefineCustomBoolVariable("orafce.varchar2_null_safe_concat", "Specify timezone used for sysdate function.", NULL, &orafce_varchar2_null_safe_concat, false, PGC_USERSET, 0, NULL, NULL, NULL); EmitWarningsOnPlaceholders("orafce"); } orafce-VERSION_3_9_0/orafce.control000066400000000000000000000003141362147214200171720ustar00rootroot00000000000000# orafce extension comment = 'Functions and operators that emulate a subset of functions and packages from the Oracle RDBMS' default_version = '3.9' module_pathname = '$libdir/orafce' relocatable = false orafce-VERSION_3_9_0/orafce.h000066400000000000000000000023631362147214200157470ustar00rootroot00000000000000#ifndef __ORAFCE__ #define __ORAFCE__ #include "postgres.h" #include "catalog/catversion.h" #include "nodes/pg_list.h" #include #include "utils/datetime.h" #include "utils/datum.h" #define TextPCopy(t) \ DatumGetTextP(datumCopy(PointerGetDatum(t), false, -1)) #define PG_GETARG_IF_EXISTS(n, type, defval) \ ((PG_NARGS() > (n) && !PG_ARGISNULL(n)) ? PG_GETARG_##type(n) : (defval)) /* alignment of this struct must fit for all types */ typedef union vardata { char c; short s; int i; long l; float f; double d; void *p; } vardata; extern int ora_instr(text *txt, text *pattern, int start, int nth); extern int ora_mb_strlen(text *str, char **sizes, int **positions); extern int ora_mb_strlen1(text *str); extern char *nls_date_format; extern char *orafce_timezone; extern char *nls_date_format; extern char *orafce_timezone; extern bool orafce_varchar2_null_safe_concat; /* * Version compatibility */ extern Oid equality_oper_funcid(Oid argtype); /* * Date utils */ #if PG_VERSION_NUM >= 90400 #define STRING_PTR_FIELD_TYPE const char *const #else #define STRING_PTR_FIELD_TYPE char * #endif extern STRING_PTR_FIELD_TYPE ora_days[]; extern int ora_seq_search(const char *name, STRING_PTR_FIELD_TYPE array[], int max); #endif orafce-VERSION_3_9_0/others.c000066400000000000000000000257061362147214200160150ustar00rootroot00000000000000#include "postgres.h" #include #include #include "catalog/pg_operator.h" #include "catalog/pg_type.h" #include "fmgr.h" #include "lib/stringinfo.h" #include "nodes/nodeFuncs.h" #include "nodes/pg_list.h" #include "nodes/primnodes.h" #include "parser/parse_expr.h" #include "parser/parse_oper.h" #include "utils/builtins.h" #include "utils/datum.h" #include "utils/lsyscache.h" #include "utils/memutils.h" #include "utils/syscache.h" #include "orafce.h" #include "builtins.h" /* * Source code for nlssort is taken from postgresql-nls-string * package by Jan Pazdziora */ static char *lc_collate_cache = NULL; static size_t multiplication = 1; text *def_locale = NULL; PG_FUNCTION_INFO_V1(ora_lnnvl); Datum ora_lnnvl(PG_FUNCTION_ARGS) { if (PG_ARGISNULL(0)) PG_RETURN_BOOL(true); PG_RETURN_BOOL(!PG_GETARG_BOOL(0)); } PG_FUNCTION_INFO_V1(ora_concat); Datum ora_concat(PG_FUNCTION_ARGS) { text *t1; text *t2; int l1; int l2; text *result; if (PG_ARGISNULL(0) && PG_ARGISNULL(1)) PG_RETURN_NULL(); if (PG_ARGISNULL(0)) PG_RETURN_DATUM(PG_GETARG_DATUM(1)); if (PG_ARGISNULL(1)) PG_RETURN_DATUM(PG_GETARG_DATUM(0)); t1 = PG_GETARG_TEXT_PP(0); t2 = PG_GETARG_TEXT_PP(1); l1 = VARSIZE_ANY_EXHDR(t1); l2 = VARSIZE_ANY_EXHDR(t2); result = palloc(l1+l2+VARHDRSZ); memcpy(VARDATA(result), VARDATA_ANY(t1), l1); memcpy(VARDATA(result) + l1, VARDATA_ANY(t2), l2); SET_VARSIZE(result, l1 + l2 + VARHDRSZ); PG_RETURN_TEXT_P(result); } PG_FUNCTION_INFO_V1(ora_nvl); Datum ora_nvl(PG_FUNCTION_ARGS) { if (!PG_ARGISNULL(0)) PG_RETURN_DATUM(PG_GETARG_DATUM(0)); if (!PG_ARGISNULL(1)) PG_RETURN_DATUM(PG_GETARG_DATUM(1)); PG_RETURN_NULL(); } PG_FUNCTION_INFO_V1(ora_nvl2); Datum ora_nvl2(PG_FUNCTION_ARGS) { if (!PG_ARGISNULL(0)) { if (!PG_ARGISNULL(1)) PG_RETURN_DATUM(PG_GETARG_DATUM(1)); } else { if (!PG_ARGISNULL(2)) PG_RETURN_DATUM(PG_GETARG_DATUM(2)); } PG_RETURN_NULL(); } PG_FUNCTION_INFO_V1(ora_set_nls_sort); Datum ora_set_nls_sort(PG_FUNCTION_ARGS) { text *arg = PG_GETARG_TEXT_P(0); if (def_locale != NULL) { pfree(def_locale); def_locale = NULL; } def_locale = (text*) MemoryContextAlloc(TopMemoryContext, VARSIZE(arg)); memcpy(def_locale, arg, VARSIZE(arg)); PG_RETURN_VOID(); } static text* _nls_run_strxfrm(text *string, text *locale) { char *string_str; int string_len; char *locale_str = NULL; int locale_len = 0; text *result; char *tmp = NULL; size_t size = 0; size_t rest = 0; int changed_locale = 0; /* * Save the default, server-wide locale setting. * It should not change during the life-span of the server so it * is safe to save it only once, during the first invocation. */ if (!lc_collate_cache) { if ((lc_collate_cache = setlocale(LC_COLLATE, NULL))) /* Make a copy of the locale name string. */ #ifdef _MSC_VER lc_collate_cache = _strdup(lc_collate_cache); #else lc_collate_cache = strdup(lc_collate_cache); #endif if (!lc_collate_cache) elog(ERROR, "failed to retrieve the default LC_COLLATE value"); } /* * To run strxfrm, we need a zero-terminated strings. */ string_len = VARSIZE_ANY_EXHDR(string); if (string_len < 0) return NULL; string_str = palloc(string_len + 1); memcpy(string_str, VARDATA_ANY(string), string_len); *(string_str + string_len) = '\0'; if (locale) { locale_len = VARSIZE_ANY_EXHDR(locale); } /* * If different than default locale is requested, call setlocale. */ if (locale_len > 0 && (strncmp(lc_collate_cache, VARDATA_ANY(locale), locale_len) || *(lc_collate_cache + locale_len) != '\0')) { locale_str = palloc(locale_len + 1); memcpy(locale_str, VARDATA_ANY(locale), locale_len); *(locale_str + locale_len) = '\0'; /* * Try to set correct locales. * If setlocale failed, we know the default stayed the same, * co we can safely elog. */ if (!setlocale(LC_COLLATE, locale_str)) elog(ERROR, "failed to set the requested LC_COLLATE value [%s]", locale_str); changed_locale = 1; } /* * We do TRY / CATCH / END_TRY to catch ereport / elog that might * happen during palloc. Ereport during palloc would not be * nice since it would leave the server with changed locales * setting, resulting in bad things. */ PG_TRY(); { /* * Text transformation. * Increase the buffer until the strxfrm is able to fit. */ size = string_len * multiplication + 1; tmp = palloc(size + VARHDRSZ); rest = strxfrm(tmp + VARHDRSZ, string_str, size); while (rest >= size) { pfree(tmp); size = rest + 1; tmp = palloc(size + VARHDRSZ); rest = strxfrm(tmp + VARHDRSZ, string_str, size); /* * Cache the multiplication factor so that the next * time we start with better value. */ if (string_len) multiplication = (rest / string_len) + 2; } } PG_CATCH (); { if (changed_locale) { /* * Set original locale */ if (!setlocale(LC_COLLATE, lc_collate_cache)) elog(FATAL, "failed to set back the default LC_COLLATE value [%s]", lc_collate_cache); } } PG_END_TRY (); if (changed_locale) { /* * Set original locale */ if (!setlocale(LC_COLLATE, lc_collate_cache)) elog(FATAL, "failed to set back the default LC_COLLATE value [%s]", lc_collate_cache); pfree(locale_str); } pfree(string_str); /* * If the multiplication factor went down, reset it. */ if (string_len && rest < string_len * multiplication / 4) multiplication = (rest / string_len) + 1; result = (text *) tmp; SET_VARSIZE(result, rest + VARHDRSZ); return result; } PG_FUNCTION_INFO_V1(ora_nlssort); Datum ora_nlssort(PG_FUNCTION_ARGS) { text *locale; text *result; if (PG_ARGISNULL(0)) PG_RETURN_NULL(); if (PG_ARGISNULL(1)) { if (def_locale != NULL) locale = def_locale; else { locale = palloc(VARHDRSZ); SET_VARSIZE(locale, VARHDRSZ); } } else { locale = PG_GETARG_TEXT_PP(1); } result = _nls_run_strxfrm(PG_GETARG_TEXT_PP(0), locale); if (! result) PG_RETURN_NULL(); PG_RETURN_BYTEA_P(result); } PG_FUNCTION_INFO_V1(ora_decode); /* * decode(lhs, [rhs, ret], ..., [default]) */ Datum ora_decode(PG_FUNCTION_ARGS) { int nargs; int i; int retarg; /* default value is last arg or NULL. */ nargs = PG_NARGS(); if (nargs % 2 == 0) { retarg = nargs - 1; nargs -= 1; /* ignore the last argument */ } else retarg = -1; /* NULL */ if (PG_ARGISNULL(0)) { for (i = 1; i < nargs; i += 2) { if (PG_ARGISNULL(i)) { retarg = i + 1; break; } } } else { FmgrInfo *eq; Oid collation = PG_GET_COLLATION(); /* * On first call, get the input type's operator '=' and save at * fn_extra. */ if (fcinfo->flinfo->fn_extra == NULL) { MemoryContext oldctx; Oid typid = get_fn_expr_argtype(fcinfo->flinfo, 0); Oid eqoid = equality_oper_funcid(typid); oldctx = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt); eq = palloc(sizeof(FmgrInfo)); fmgr_info(eqoid, eq); MemoryContextSwitchTo(oldctx); fcinfo->flinfo->fn_extra = eq; } else eq = fcinfo->flinfo->fn_extra; for (i = 1; i < nargs; i += 2) { Datum result; if (PG_ARGISNULL(i)) continue; result = FunctionCall2Coll(eq, collation, PG_GETARG_DATUM(0), PG_GETARG_DATUM(i)); if (DatumGetBool(result)) { retarg = i + 1; break; } } } if (retarg < 0 || PG_ARGISNULL(retarg)) PG_RETURN_NULL(); else PG_RETURN_DATUM(PG_GETARG_DATUM(retarg)); } Oid equality_oper_funcid(Oid argtype) { Oid eq; get_sort_group_operators(argtype, false, true, false, NULL, &eq, NULL, NULL); return get_opcode(eq); } /* * dump(anyexpr [,format]) * * the dump function returns a varchar2 value that includes the datatype code, * the length in bytes, and the internal representation of the expression. */ PG_FUNCTION_INFO_V1(orafce_dump); static void appendDatum(StringInfo str, const void *ptr, size_t length, int format) { if (!PointerIsValid(ptr)) appendStringInfoChar(str, ':'); else { const unsigned char *s = (const unsigned char *) ptr; const char *formatstr; size_t i; switch (format) { case 8: formatstr = "%ho"; break; case 10: formatstr = "%hu"; break; case 16: formatstr = "%hx"; break; case 17: formatstr = "%hc"; break; default: elog(ERROR, "unknown format"); formatstr = NULL; /* quite compiler */ } /* append a byte array with the specified format */ for (i = 0; i < length; i++) { if (i > 0) appendStringInfoChar(str, ','); /* print only ANSI visible chars */ if (format == 17 && (iscntrl(s[i]) || !isascii(s[i]))) appendStringInfoChar(str, '?'); else appendStringInfo(str, formatstr, s[i]); } } } Datum orafce_dump(PG_FUNCTION_ARGS) { Oid valtype = get_fn_expr_argtype(fcinfo->flinfo, 0); List *args; int16 typlen; bool typbyval; Size length; Datum value; int format; StringInfoData str; if (!fcinfo->flinfo || !fcinfo->flinfo->fn_expr) elog(ERROR, "function is called from invalid context"); if (PG_ARGISNULL(0)) elog(ERROR, "argument is NULL"); value = PG_GETARG_DATUM(0); format = PG_GETARG_IF_EXISTS(1, INT32, 10); args = ((FuncExpr *) fcinfo->flinfo->fn_expr)->args; valtype = exprType((Node *) list_nth(args, 0)); get_typlenbyval(valtype, &typlen, &typbyval); length = datumGetSize(value, typbyval, typlen); initStringInfo(&str); appendStringInfo(&str, "Typ=%d Len=%d: ", valtype, (int) length); if (!typbyval) { appendDatum(&str, DatumGetPointer(value), length, format); } else if (length <= 1) { char v = DatumGetChar(value); appendDatum(&str, &v, sizeof(char), format); } else if (length <= 2) { int16 v = DatumGetInt16(value); appendDatum(&str, &v, sizeof(int16), format); } else if (length <= 4) { int32 v = DatumGetInt32(value); appendDatum(&str, &v, sizeof(int32), format); } else { int64 v = DatumGetInt64(value); appendDatum(&str, &v, sizeof(int64), format); } PG_RETURN_TEXT_P(cstring_to_text(str.data)); } PG_FUNCTION_INFO_V1(ora_get_major_version); /* * Returns current version etc, PostgreSQL 9.6, PostgreSQL 10, .. */ Datum ora_get_major_version(PG_FUNCTION_ARGS) { PG_RETURN_TEXT_P(cstring_to_text(PACKAGE_STRING)); } PG_FUNCTION_INFO_V1(ora_get_major_version_num); /* * Returns major version number 9.5, 9.6, 10, 11, .. */ Datum ora_get_major_version_num(PG_FUNCTION_ARGS) { PG_RETURN_TEXT_P(cstring_to_text(PG_MAJORVERSION)); } PG_FUNCTION_INFO_V1(ora_get_full_version_num); /* * Returns version number string - 9.5.1, 10.2, .. */ Datum ora_get_full_version_num(PG_FUNCTION_ARGS) { PG_RETURN_TEXT_P(cstring_to_text(PG_VERSION)); } PG_FUNCTION_INFO_V1(ora_get_platform); /* * 32bit, 64bit */ Datum ora_get_platform(PG_FUNCTION_ARGS) { #ifdef USE_FLOAT8_BYVAL PG_RETURN_TEXT_P(cstring_to_text("64bit")); #else PG_RETURN_TEXT_P(cstring_to_text("32bit")); #endif } PG_FUNCTION_INFO_V1(ora_get_status); /* * Production | Debug */ Datum ora_get_status(PG_FUNCTION_ARGS) { #ifdef USE_ASSERT_CHECKING PG_RETURN_TEXT_P(cstring_to_text("Debug")); #else PG_RETURN_TEXT_P(cstring_to_text("Production")); #endif } orafce-VERSION_3_9_0/parallel_schedule000066400000000000000000000001761362147214200177320ustar00rootroot00000000000000test: init test: dbms_pipe_session_A dbms_pipe_session_B test: dbms_alert_session_A dbms_alert_session_B dbms_alert_session_C orafce-VERSION_3_9_0/parse_keyword.c000066400000000000000000000015611362147214200173600ustar00rootroot00000000000000#include "postgres.h" #include "parse_keyword.h" #include "parser/gramparse.h" #if PG_VERSION_NUM >= 90600 #include "common/keywords.h" #else #include "parser/keywords.h" #endif #if PG_VERSION_NUM >= 120000 #define PG_KEYWORD(kwname, value, category) value, const uint16 ScanKeywordTokens[] = { #include "parser/kwlist.h" }; #undef PG_KEYWORD const char * orafce_scan_keyword(const char *text, int *keycode) { int kwnum; kwnum = ScanKeywordLookup(text, &ScanKeywords); if (kwnum >= 0) { *keycode = ScanKeywordTokens[kwnum]; return GetScanKeyword(kwnum, &ScanKeywords); } return NULL; } #else const char * orafce_scan_keyword(const char *text, int *keycode) { const ScanKeyword *keyword; keyword = ScanKeywordLookup(text, ScanKeywords, NumScanKeywords); if (keyword) { *keycode = keyword->value; return keyword->name; } return NULL; } #endif orafce-VERSION_3_9_0/parse_keyword.h000066400000000000000000000001111362147214200173530ustar00rootroot00000000000000 extern const char *orafce_scan_keyword(const char *text, int *keycode); orafce-VERSION_3_9_0/pipe.c000066400000000000000000000662131362147214200154440ustar00rootroot00000000000000#include "postgres.h" #include "funcapi.h" #include "fmgr.h" #include "access/htup_details.h" #include "storage/shmem.h" #include "utils/memutils.h" #include "utils/timestamp.h" #include "storage/lwlock.h" #include "miscadmin.h" #include "string.h" #include "lib/stringinfo.h" #include "catalog/pg_type.h" #include "utils/builtins.h" #include "utils/date.h" #include "utils/numeric.h" #include "shmmc.h" #include "pipe.h" #include "orafce.h" #include "builtins.h" /* * @ Pavel Stehule 2006-2018 */ #ifndef _GetCurrentTimestamp #define _GetCurrentTimestamp() GetCurrentTimestamp() #endif #ifndef GetNowFloat #ifdef HAVE_INT64_TIMESTAMP #define GetNowFloat() ((float8) _GetCurrentTimestamp() / 1000000.0) #else #define GetNowFloat() _GetCurrentTimestamp() #endif #endif #define RESULT_DATA 0 #define RESULT_WAIT 1 #define ONE_YEAR (60*60*24*365) PG_FUNCTION_INFO_V1(dbms_pipe_pack_message_text); PG_FUNCTION_INFO_V1(dbms_pipe_unpack_message_text); PG_FUNCTION_INFO_V1(dbms_pipe_send_message); PG_FUNCTION_INFO_V1(dbms_pipe_receive_message); PG_FUNCTION_INFO_V1(dbms_pipe_unique_session_name); PG_FUNCTION_INFO_V1(dbms_pipe_list_pipes); PG_FUNCTION_INFO_V1(dbms_pipe_next_item_type); PG_FUNCTION_INFO_V1(dbms_pipe_create_pipe); PG_FUNCTION_INFO_V1(dbms_pipe_create_pipe_2); PG_FUNCTION_INFO_V1(dbms_pipe_create_pipe_1); PG_FUNCTION_INFO_V1(dbms_pipe_reset_buffer); PG_FUNCTION_INFO_V1(dbms_pipe_purge); PG_FUNCTION_INFO_V1(dbms_pipe_remove_pipe); PG_FUNCTION_INFO_V1(dbms_pipe_pack_message_date); PG_FUNCTION_INFO_V1(dbms_pipe_unpack_message_date); PG_FUNCTION_INFO_V1(dbms_pipe_pack_message_timestamp); PG_FUNCTION_INFO_V1(dbms_pipe_unpack_message_timestamp); PG_FUNCTION_INFO_V1(dbms_pipe_pack_message_number); PG_FUNCTION_INFO_V1(dbms_pipe_unpack_message_number); PG_FUNCTION_INFO_V1(dbms_pipe_pack_message_bytea); PG_FUNCTION_INFO_V1(dbms_pipe_unpack_message_bytea); PG_FUNCTION_INFO_V1(dbms_pipe_pack_message_record); PG_FUNCTION_INFO_V1(dbms_pipe_unpack_message_record); PG_FUNCTION_INFO_V1(dbms_pipe_pack_message_integer); PG_FUNCTION_INFO_V1(dbms_pipe_pack_message_bigint); typedef enum { IT_NO_MORE_ITEMS = 0, IT_NUMBER = 9, IT_VARCHAR = 11, IT_DATE = 12, IT_TIMESTAMPTZ = 13, IT_BYTEA = 23, IT_RECORD = 24 } message_data_type; typedef struct _queue_item { void *ptr; struct _queue_item *next_item; } queue_item; typedef struct { bool is_valid; bool registered; char *pipe_name; char *creator; Oid uid; struct _queue_item *items; int16 count; int16 limit; int size; } pipe; typedef struct { int32 size; message_data_type type; Oid tupType; } message_data_item; typedef struct { int32 size; int32 items_count; message_data_item *next; } message_buffer; #define message_buffer_size (MAXALIGN(sizeof(message_buffer))) #define message_buffer_get_content(buf) ((message_data_item *) (((char*)buf)+message_buffer_size)) #define message_data_item_size (MAXALIGN(sizeof(message_data_item))) #define message_data_get_content(msg) (((char *)msg) + message_data_item_size) #define message_data_item_next(msg) \ ((message_data_item *) (message_data_get_content(msg) + MAXALIGN(msg->size))) typedef struct PipesFctx { int pipe_nth; } PipesFctx; typedef struct { #if PG_VERSION_NUM >= 90600 int tranche_id; LWLock shmem_lock; #else LWLockId shmem_lockid; #endif pipe *pipes; alert_event *events; alert_lock *locks; size_t size; unsigned int sid; vardata data[1]; /* flexible array member */ } sh_memory; #define sh_memory_size (offsetof(sh_memory, data)) message_buffer *output_buffer = NULL; message_buffer *input_buffer = NULL; pipe* pipes = NULL; #define NOT_INITIALIZED NULL LWLockId shmem_lockid = NOT_INITIALIZED;; unsigned int sid; /* session id */ extern alert_event *events; extern alert_lock *locks; /* * write on writer size bytes from ptr */ static void pack_field(message_buffer *buffer, message_data_type type, int32 size, void *ptr, Oid tupType) { int len; message_data_item *message; len = MAXALIGN(size) + message_data_item_size; if (MAXALIGN(buffer->size) + len > LOCALMSGSZ - message_buffer_size) ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"), errdetail("Packed message is bigger than local buffer."), errhint("Increase LOCALMSGSZ in 'pipe.h' and recompile library."))); if (buffer->next == NULL) buffer->next = message_buffer_get_content(buffer); message = buffer->next; message->size = size; message->type = type; message->tupType = tupType; /* padding bytes have to be zeroed - buffer creator is responsible to clear memory */ memcpy(message_data_get_content(message), ptr, size); buffer->size += len; buffer->items_count++; buffer->next = message_data_item_next(message); } static void* unpack_field(message_buffer *buffer, message_data_type *type, int32 *size, Oid *tupType) { void *ptr; message_data_item *message; Assert(buffer != NULL); Assert(buffer->items_count > 0); Assert(buffer->next != NULL); message = buffer->next; *size = message->size; *type = message->type; *tupType = message->tupType; ptr = message_data_get_content(message); buffer->next = --buffer->items_count > 0 ? message_data_item_next(message) : NULL; return ptr; } /* * Add ptr to queue. If pipe doesn't exist, register new pipe */ bool ora_lock_shmem(size_t size, int max_pipes, int max_events, int max_locks, bool reset) { int i; bool found; sh_memory *sh_mem; if (pipes == NULL) { sh_mem = ShmemInitStruct("dbms_pipe", size, &found); if (sh_mem == NULL) ereport(FATAL, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"), errdetail("Failed while allocation block %lu bytes in shared memory.", (unsigned long) size))); if (!found) { #if PG_VERSION_NUM >= 90600 sh_mem->tranche_id = LWLockNewTrancheId(); LWLockInitialize(&sh_mem->shmem_lock, sh_mem->tranche_id); { #if PG_VERSION_NUM >= 100000 LWLockRegisterTranche(sh_mem->tranche_id, "orafce"); #else static LWLockTranche tranche; tranche.name = "orafce"; tranche.array_base = &sh_mem->shmem_lock; tranche.array_stride = sizeof(LWLock); LWLockRegisterTranche(sh_mem->tranche_id, &tranche); #endif shmem_lockid = &sh_mem->shmem_lock; } #else shmem_lockid = sh_mem->shmem_lockid = LWLockAssign(); #endif LWLockAcquire(shmem_lockid, LW_EXCLUSIVE); sh_mem->size = size - sh_memory_size; ora_sinit(sh_mem->data, size, true); pipes = sh_mem->pipes = ora_salloc(max_pipes*sizeof(pipe)); sid = sh_mem->sid = 1; for (i = 0; i < max_pipes; i++) pipes[i].is_valid = false; events = sh_mem->events = ora_salloc(max_events*sizeof(alert_event)); locks = sh_mem->locks = ora_salloc(max_locks*sizeof(alert_lock)); for (i = 0; i < max_events; i++) { events[i].event_name = NULL; events[i].max_receivers = 0; events[i].receivers = NULL; events[i].messages = NULL; } for (i = 0; i < max_locks; i++) { locks[i].sid = -1; locks[i].echo = NULL; } } else if (pipes == NULL) { #if PG_VERSION_NUM >= 90600 #if PG_VERSION_NUM >= 100000 LWLockRegisterTranche(sh_mem->tranche_id, "orafce"); #else static LWLockTranche tranche; tranche.name = "orafce"; tranche.array_base = &sh_mem->shmem_lock; tranche.array_stride = sizeof(LWLock); LWLockRegisterTranche(sh_mem->tranche_id, &tranche); #endif shmem_lockid = &sh_mem->shmem_lock; #else shmem_lockid = sh_mem->shmem_lockid; #endif pipes = sh_mem->pipes; LWLockAcquire(shmem_lockid, LW_EXCLUSIVE); ora_sinit(sh_mem->data, sh_mem->size, reset); sid = ++(sh_mem->sid); events = sh_mem->events; locks = sh_mem->locks; } } else { LWLockAcquire(shmem_lockid, LW_EXCLUSIVE); } return pipes != NULL; } /* * can be enhanced access/hash.h */ static pipe* find_pipe(text* pipe_name, bool* created, bool only_check) { int i; pipe *result = NULL; *created = false; for (i = 0; i < MAX_PIPES; i++) { if (pipes[i].is_valid && strncmp((char*)VARDATA(pipe_name), pipes[i].pipe_name, VARSIZE(pipe_name) - VARHDRSZ) == 0 && (strlen(pipes[i].pipe_name) == (VARSIZE(pipe_name) - VARHDRSZ))) { /* check owner if non public pipe */ if (pipes[i].creator != NULL && pipes[i].uid != GetUserId()) { LWLockRelease(shmem_lockid); ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("insufficient privilege"), errdetail("Insufficient privilege to access pipe"))); } return &pipes[i]; } } if (only_check) return result; for (i = 0; i < MAX_PIPES; i++) if (!pipes[i].is_valid) { if (NULL != (pipes[i].pipe_name = ora_scstring(pipe_name))) { pipes[i].is_valid = true; pipes[i].registered = false; pipes[i].creator = NULL; pipes[i].uid = -1; pipes[i].count = 0; pipes[i].limit = -1; *created = true; result = &pipes[i]; } break; } return result; } static bool new_last(pipe *p, void *ptr) { queue_item *q, *aux_q; if (p->count >= p->limit && p->limit != -1) return false; if (p->items == NULL) { if (NULL == (p->items = ora_salloc(sizeof(queue_item)))) return false; p->items->next_item = NULL; p->items->ptr = ptr; p->count = 1; return true; } q = p->items; while (q->next_item != NULL) q = q->next_item; if (NULL == (aux_q = ora_salloc(sizeof(queue_item)))) return false; q->next_item = aux_q; aux_q->next_item = NULL; aux_q->ptr = ptr; p->count += 1; return true; } static void* remove_first(pipe *p, bool *found) { struct _queue_item *q; void *ptr = NULL; *found = false; if (NULL != (q = p->items)) { p->count -= 1; ptr = q->ptr; p->items = q->next_item; *found = true; ora_sfree(q); if (p->items == NULL && !p->registered) { ora_sfree(p->pipe_name); p->is_valid = false; } } return ptr; } /* copy message to local memory, if exists */ static message_buffer* get_from_pipe(text *pipe_name, bool *found) { pipe *p; bool created; message_buffer *shm_msg; message_buffer *result = NULL; if (!ora_lock_shmem(SHMEMMSGSZ, MAX_PIPES, MAX_EVENTS, MAX_LOCKS, false)) return NULL; if (NULL != (p = find_pipe(pipe_name, &created,false))) { if (!created) { if (NULL != (shm_msg = remove_first(p, found))) { p->size -= shm_msg->size; result = (message_buffer*) MemoryContextAlloc(TopMemoryContext, shm_msg->size); memcpy(result, shm_msg, shm_msg->size); ora_sfree(shm_msg); } } } LWLockRelease(shmem_lockid); return result; } /* * if ptr is null, then only register pipe */ static bool add_to_pipe(text *pipe_name, message_buffer *ptr, int limit, bool limit_is_valid) { pipe *p; bool created; bool result = false; message_buffer *sh_ptr; if (!ora_lock_shmem(SHMEMMSGSZ, MAX_PIPES, MAX_EVENTS, MAX_LOCKS,false)) return false; for (;;) { if (NULL != (p = find_pipe(pipe_name, &created, false))) { if (created) p->registered = ptr == NULL; if (limit_is_valid && (created || (p->limit < limit))) p->limit = limit; if (ptr != NULL) { if (NULL != (sh_ptr = ora_salloc(ptr->size))) { memcpy(sh_ptr,ptr,ptr->size); if (new_last(p, sh_ptr)) { p->size += ptr->size; result = true; break; } ora_sfree(sh_ptr); } if (created) { /* I created new pipe, but haven't memory for new value */ ora_sfree(p->pipe_name); p->is_valid = false; result = false; } } else result = true; } break; } LWLockRelease(shmem_lockid); return result; } static void remove_pipe(text *pipe_name, bool purge) { pipe *p; bool created; if (NULL != (p = find_pipe(pipe_name, &created, true))) { queue_item *q = p->items; while (q != NULL) { queue_item *aux_q; aux_q = q->next_item; if (q->ptr) ora_sfree(q->ptr); ora_sfree(q); q = aux_q; } p->items = NULL; p->size = 0; p->count = 0; if (!(purge && p->registered)) { ora_sfree(p->pipe_name); p->is_valid = false; } } } Datum dbms_pipe_next_item_type (PG_FUNCTION_ARGS) { PG_RETURN_INT32(input_buffer != NULL ? input_buffer->next->type : IT_NO_MORE_ITEMS); } static void init_buffer(message_buffer *buffer, int32 size) { memset(buffer, 0, size); buffer->size = message_buffer_size; buffer->items_count = 0; buffer->next = message_buffer_get_content(buffer); } static message_buffer* check_buffer(message_buffer *buffer, int32 size) { if (buffer == NULL) { buffer = (message_buffer*) MemoryContextAlloc(TopMemoryContext, size); if (buffer == NULL) ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"), errdetail("Failed while allocation block %d bytes in memory.", size))); init_buffer(buffer, size); } return buffer; } Datum dbms_pipe_pack_message_text(PG_FUNCTION_ARGS) { text *str = PG_GETARG_TEXT_PP(0); output_buffer = check_buffer(output_buffer, LOCALMSGSZ); pack_field(output_buffer, IT_VARCHAR, VARSIZE_ANY_EXHDR(str), VARDATA_ANY(str), InvalidOid); PG_RETURN_VOID(); } Datum dbms_pipe_pack_message_date(PG_FUNCTION_ARGS) { DateADT dt = PG_GETARG_DATEADT(0); output_buffer = check_buffer(output_buffer, LOCALMSGSZ); pack_field(output_buffer, IT_DATE, sizeof(dt), &dt, InvalidOid); PG_RETURN_VOID(); } Datum dbms_pipe_pack_message_timestamp(PG_FUNCTION_ARGS) { TimestampTz dt = PG_GETARG_TIMESTAMPTZ(0); output_buffer = check_buffer(output_buffer, LOCALMSGSZ); pack_field(output_buffer, IT_TIMESTAMPTZ, sizeof(dt), &dt, InvalidOid); PG_RETURN_VOID(); } Datum dbms_pipe_pack_message_number(PG_FUNCTION_ARGS) { Numeric num = PG_GETARG_NUMERIC(0); output_buffer = check_buffer(output_buffer, LOCALMSGSZ); pack_field(output_buffer, IT_NUMBER, VARSIZE(num) - VARHDRSZ, VARDATA(num), InvalidOid); PG_RETURN_VOID(); } Datum dbms_pipe_pack_message_bytea(PG_FUNCTION_ARGS) { bytea *data = PG_GETARG_BYTEA_P(0); output_buffer = check_buffer(output_buffer, LOCALMSGSZ); pack_field(output_buffer, IT_BYTEA, VARSIZE_ANY_EXHDR(data), VARDATA_ANY(data), InvalidOid); PG_RETURN_VOID(); } static void init_args_3(FunctionCallInfo info, Datum arg0, Datum arg1, Datum arg2) { #if PG_VERSION_NUM >= 120000 info->args[0].value = arg0; info->args[1].value = arg1; info->args[2].value = arg2; info->args[0].isnull = false; info->args[1].isnull = false; info->args[2].isnull = false; #else info->arg[0] = arg0; info->arg[1] = arg1; info->arg[2] = arg2; info->argnull[0] = false; info->argnull[1] = false; info->argnull[2] = false; #endif } /* * We can serialize only typed record */ Datum dbms_pipe_pack_message_record(PG_FUNCTION_ARGS) { HeapTupleHeader rec = PG_GETARG_HEAPTUPLEHEADER(0); Oid tupType; bytea *data; #if PG_VERSION_NUM >= 120000 LOCAL_FCINFO(info, 3); #else FunctionCallInfoData info_data; FunctionCallInfo info = &info_data; #endif tupType = HeapTupleHeaderGetTypeId(rec); /* * Normally one would call record_send() using DirectFunctionCall3, * but that does not work since record_send wants to cache some data * using fcinfo->flinfo->fn_extra. So we need to pass it our own * flinfo parameter. */ InitFunctionCallInfoData(*info, fcinfo->flinfo, 3, InvalidOid, NULL, NULL); init_args_3(info, PointerGetDatum(rec), ObjectIdGetDatum(tupType), Int32GetDatum(-1)); data = (bytea*) DatumGetPointer(record_send(info)); output_buffer = check_buffer(output_buffer, LOCALMSGSZ); pack_field(output_buffer, IT_RECORD, VARSIZE(data), VARDATA(data), tupType); PG_RETURN_VOID(); } static Datum dbms_pipe_unpack_message(PG_FUNCTION_ARGS, message_data_type dtype) { Oid tupType; void *ptr; message_data_type type; int32 size; Datum result; message_data_type next_type; if (input_buffer == NULL || input_buffer->items_count <= 0 || input_buffer->next == NULL || input_buffer->next->type == IT_NO_MORE_ITEMS) PG_RETURN_NULL(); next_type = input_buffer->next->type; if (next_type != dtype) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("datatype mismatch"), errdetail("unpack unexpected type: %d", next_type))); ptr = unpack_field(input_buffer, &type, &size, &tupType); Assert(ptr != NULL); switch (type) { case IT_TIMESTAMPTZ: result = TimestampTzGetDatum(*(TimestampTz*)ptr); break; case IT_DATE: result = DateADTGetDatum(*(DateADT*)ptr); break; case IT_VARCHAR: case IT_NUMBER: case IT_BYTEA: result = PointerGetDatum(cstring_to_text_with_len(ptr, size)); break; case IT_RECORD: { #if PG_VERSION_NUM >= 120000 LOCAL_FCINFO(info, 3); #else FunctionCallInfoData info_data; FunctionCallInfo info = &info_data; #endif StringInfoData buf; text *data = cstring_to_text_with_len(ptr, size); buf.data = VARDATA(data); buf.len = VARSIZE(data) - VARHDRSZ; buf.maxlen = buf.len; buf.cursor = 0; /* * Normally one would call record_recv() using DirectFunctionCall3, * but that does not work since record_recv wants to cache some data * using fcinfo->flinfo->fn_extra. So we need to pass it our own * flinfo parameter. */ InitFunctionCallInfoData(*info, fcinfo->flinfo, 3, InvalidOid, NULL, NULL); init_args_3(info, PointerGetDatum(&buf), ObjectIdGetDatum(tupType), Int32GetDatum(-1)); result = record_recv(info); break; } default: elog(ERROR, "unexpected type: %d", type); result = (Datum) 0; /* keep compiler quiet */ } if (input_buffer->items_count == 0) { pfree(input_buffer); input_buffer = NULL; } PG_RETURN_DATUM(result); } Datum dbms_pipe_unpack_message_text(PG_FUNCTION_ARGS) { return dbms_pipe_unpack_message(fcinfo, IT_VARCHAR); } Datum dbms_pipe_unpack_message_date(PG_FUNCTION_ARGS) { return dbms_pipe_unpack_message(fcinfo, IT_DATE); } Datum dbms_pipe_unpack_message_timestamp(PG_FUNCTION_ARGS) { return dbms_pipe_unpack_message(fcinfo, IT_TIMESTAMPTZ); } Datum dbms_pipe_unpack_message_number(PG_FUNCTION_ARGS) { return dbms_pipe_unpack_message(fcinfo, IT_NUMBER); } Datum dbms_pipe_unpack_message_bytea(PG_FUNCTION_ARGS) { return dbms_pipe_unpack_message(fcinfo, IT_BYTEA); } Datum dbms_pipe_unpack_message_record(PG_FUNCTION_ARGS) { return dbms_pipe_unpack_message(fcinfo, IT_RECORD); } #define WATCH_PRE(t, et, c) \ et = GetNowFloat() + (float8)t; c = 0; \ do \ { \ #define WATCH_POST(t,et,c) \ if (GetNowFloat() >= et) \ PG_RETURN_INT32(RESULT_WAIT); \ if (cycle++ % 100 == 0) \ CHECK_FOR_INTERRUPTS(); \ pg_usleep(10000L); \ } while(true && t != 0); Datum dbms_pipe_receive_message(PG_FUNCTION_ARGS) { text *pipe_name = NULL; int timeout = ONE_YEAR; int cycle = 0; float8 endtime; bool found = false; if (PG_ARGISNULL(0)) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("pipe name is NULL"), errdetail("Pipename may not be NULL."))); else pipe_name = PG_GETARG_TEXT_P(0); if (!PG_ARGISNULL(1)) timeout = PG_GETARG_INT32(1); if (input_buffer != NULL) { pfree(input_buffer); input_buffer = NULL; } WATCH_PRE(timeout, endtime, cycle); if (NULL != (input_buffer = get_from_pipe(pipe_name, &found))) { input_buffer->next = message_buffer_get_content(input_buffer); break; } /* found empty message */ if (found) break; WATCH_POST(timeout, endtime, cycle); PG_RETURN_INT32(RESULT_DATA); } Datum dbms_pipe_send_message(PG_FUNCTION_ARGS) { text *pipe_name = NULL; int timeout = ONE_YEAR; int limit = 0; bool valid_limit; int cycle = 0; float8 endtime; if (PG_ARGISNULL(0)) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("pipe name is NULL"), errdetail("Pipename may not be NULL."))); else pipe_name = PG_GETARG_TEXT_P(0); output_buffer = check_buffer(output_buffer, LOCALMSGSZ); if (!PG_ARGISNULL(1)) timeout = PG_GETARG_INT32(1); if (PG_ARGISNULL(2)) valid_limit = false; else { limit = PG_GETARG_INT32(2); valid_limit = true; } if (input_buffer != NULL) /* XXX Strange? */ { pfree(input_buffer); input_buffer = NULL; } WATCH_PRE(timeout, endtime, cycle); if (add_to_pipe(pipe_name, output_buffer, limit, valid_limit)) break; WATCH_POST(timeout, endtime, cycle); init_buffer(output_buffer, LOCALMSGSZ); PG_RETURN_INT32(RESULT_DATA); } Datum dbms_pipe_unique_session_name (PG_FUNCTION_ARGS) { StringInfoData strbuf; text *result; float8 endtime; int cycle = 0; int timeout = 10; WATCH_PRE(timeout, endtime, cycle); if (ora_lock_shmem(SHMEMMSGSZ, MAX_PIPES,MAX_EVENTS,MAX_LOCKS,false)) { initStringInfo(&strbuf); appendStringInfo(&strbuf,"PG$PIPE$%d$%d",sid, MyProcPid); result = cstring_to_text_with_len(strbuf.data, strbuf.len); pfree(strbuf.data); LWLockRelease(shmem_lockid); PG_RETURN_TEXT_P(result); } WATCH_POST(timeout, endtime, cycle); LOCK_ERROR(); PG_RETURN_NULL(); } #define DB_PIPES_COLS 6 Datum dbms_pipe_list_pipes(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; TupleDesc tupdesc; AttInMetadata *attinmeta; PipesFctx *fctx; float8 endtime; int cycle = 0; int timeout = 10; if (SRF_IS_FIRSTCALL()) { int i; MemoryContext oldcontext; bool has_lock = false; WATCH_PRE(timeout, endtime, cycle); if (ora_lock_shmem(SHMEMMSGSZ, MAX_PIPES, MAX_EVENTS, MAX_LOCKS, false)) { has_lock = true; break; } WATCH_POST(timeout, endtime, cycle); if (!has_lock) LOCK_ERROR(); funcctx = SRF_FIRSTCALL_INIT(); oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); fctx = palloc(sizeof(PipesFctx)); funcctx->user_fctx = fctx; fctx->pipe_nth = 0; #if PG_VERSION_NUM >= 120000 tupdesc = CreateTemplateTupleDesc(DB_PIPES_COLS); #else tupdesc = CreateTemplateTupleDesc(DB_PIPES_COLS, false); #endif i = 0; TupleDescInitEntry(tupdesc, ++i, "name", VARCHAROID, -1, 0); TupleDescInitEntry(tupdesc, ++i, "items", INT4OID, -1, 0); TupleDescInitEntry(tupdesc, ++i, "size", INT4OID, -1, 0); TupleDescInitEntry(tupdesc, ++i, "limit", INT4OID, -1, 0); TupleDescInitEntry(tupdesc, ++i, "private", BOOLOID, -1, 0); TupleDescInitEntry(tupdesc, ++i, "owner", VARCHAROID, -1, 0); Assert(i == DB_PIPES_COLS); attinmeta = TupleDescGetAttInMetadata(tupdesc); funcctx->attinmeta = attinmeta; MemoryContextSwitchTo(oldcontext); } funcctx = SRF_PERCALL_SETUP(); fctx = (PipesFctx *) funcctx->user_fctx; while (fctx->pipe_nth < MAX_PIPES) { if (pipes[fctx->pipe_nth].is_valid) { Datum result; HeapTuple tuple; char *values[DB_PIPES_COLS]; char items[16]; char size[16]; char limit[16]; /* name */ values[0] = pipes[fctx->pipe_nth].pipe_name; /* items */ snprintf(items, lengthof(items), "%d", pipes[fctx->pipe_nth].count); values[1] = items; /* items */ snprintf(size, lengthof(size), "%d", pipes[fctx->pipe_nth].size); values[2] = size; /* limit */ if (pipes[fctx->pipe_nth].limit != -1) { snprintf(limit, lengthof(limit), "%d", pipes[fctx->pipe_nth].limit); values[3] = limit; } else values[3] = NULL; /* private */ values[4] = (pipes[fctx->pipe_nth].creator ? "true" : "false"); /* owner */ values[5] = pipes[fctx->pipe_nth].creator; tuple = BuildTupleFromCStrings(funcctx->attinmeta, values); result = HeapTupleGetDatum(tuple); fctx->pipe_nth += 1; SRF_RETURN_NEXT(funcctx, result); } fctx->pipe_nth += 1; } LWLockRelease(shmem_lockid); SRF_RETURN_DONE(funcctx); } /* * secondary functions */ /* * Registration explicit pipes * dbms_pipe.create_pipe(pipe_name varchar, limit := -1 int, private := false bool); */ Datum dbms_pipe_create_pipe (PG_FUNCTION_ARGS) { text *pipe_name = NULL; int limit = 0; bool is_private; bool limit_is_valid = false; bool created; float8 endtime; int cycle = 0; int timeout = 10; if (PG_ARGISNULL(0)) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("pipe name is NULL"), errdetail("Pipename may not be NULL."))); else pipe_name = PG_GETARG_TEXT_P(0); if (!PG_ARGISNULL(1)) { limit = PG_GETARG_INT32(1); limit_is_valid = true; } is_private = PG_ARGISNULL(2) ? false : PG_GETARG_BOOL(2); WATCH_PRE(timeout, endtime, cycle); if (ora_lock_shmem(SHMEMMSGSZ, MAX_PIPES,MAX_EVENTS,MAX_LOCKS,false)) { pipe *p; if (NULL != (p = find_pipe(pipe_name, &created, false))) { if (!created) { LWLockRelease(shmem_lockid); ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("pipe creation error"), errdetail("Pipe is registered."))); } if (is_private) { char *user; p->uid = GetUserId(); #if PG_VERSION_NUM >= 90500 user = (char*)DirectFunctionCall1(namein, CStringGetDatum(GetUserNameFromId(p->uid, false))); #else user = (char*)DirectFunctionCall1(namein, CStringGetDatum(GetUserNameFromId(p->uid))); #endif p->creator = ora_sstrcpy(user); pfree(user); } p->limit = limit_is_valid ? limit : -1; p->registered = true; LWLockRelease(shmem_lockid); PG_RETURN_VOID(); } } WATCH_POST(timeout, endtime, cycle); LOCK_ERROR(); PG_RETURN_VOID(); } /* * Clean local input, output buffers */ Datum dbms_pipe_reset_buffer(PG_FUNCTION_ARGS) { if (output_buffer != NULL) { pfree(output_buffer); output_buffer = NULL; } if (input_buffer != NULL) { pfree(input_buffer); input_buffer = NULL; } PG_RETURN_VOID(); } /* * Remove all stored messages in pipe. Remove implicit created * pipe. */ Datum dbms_pipe_purge (PG_FUNCTION_ARGS) { text *pipe_name = PG_GETARG_TEXT_P(0); float8 endtime; int cycle = 0; int timeout = 10; WATCH_PRE(timeout, endtime, cycle); if (ora_lock_shmem(SHMEMMSGSZ, MAX_PIPES,MAX_EVENTS,MAX_LOCKS,false)) { remove_pipe(pipe_name, true); LWLockRelease(shmem_lockid); PG_RETURN_VOID(); } WATCH_POST(timeout, endtime, cycle); LOCK_ERROR(); PG_RETURN_VOID(); } /* * Remove pipe if exists */ Datum dbms_pipe_remove_pipe (PG_FUNCTION_ARGS) { text *pipe_name = PG_GETARG_TEXT_P(0); float8 endtime; int cycle = 0; int timeout = 10; WATCH_PRE(timeout, endtime, cycle); if (ora_lock_shmem(SHMEMMSGSZ, MAX_PIPES,MAX_EVENTS,MAX_LOCKS,false)) { remove_pipe(pipe_name, false); LWLockRelease(shmem_lockid); PG_RETURN_VOID(); } WATCH_POST(timeout, endtime, cycle); LOCK_ERROR(); PG_RETURN_VOID(); } /* * Some void udf which I can't wrap in sql */ Datum dbms_pipe_create_pipe_2 (PG_FUNCTION_ARGS) { Datum arg1; int limit = -1; if (PG_ARGISNULL(0)) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("pipe name is NULL"), errdetail("Pipename may not be NULL."))); arg1 = PG_GETARG_DATUM(0); if (!PG_ARGISNULL(1)) limit = PG_GETARG_INT32(1); DirectFunctionCall3(dbms_pipe_create_pipe, arg1, Int32GetDatum(limit), BoolGetDatum(false)); PG_RETURN_VOID(); } Datum dbms_pipe_create_pipe_1 (PG_FUNCTION_ARGS) { Datum arg1; if (PG_ARGISNULL(0)) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("pipe name is NULL"), errdetail("Pipename may not be NULL."))); arg1 = PG_GETARG_DATUM(0); DirectFunctionCall3(dbms_pipe_create_pipe, arg1, (Datum) -1, BoolGetDatum(false)); PG_RETURN_VOID(); } Datum dbms_pipe_pack_message_integer(PG_FUNCTION_ARGS) { /* Casting from int4 to numeric */ DirectFunctionCall1(dbms_pipe_pack_message_number, DirectFunctionCall1(int4_numeric, PG_GETARG_DATUM(0))); PG_RETURN_VOID(); } Datum dbms_pipe_pack_message_bigint(PG_FUNCTION_ARGS) { /* Casting from int8 to numeric */ DirectFunctionCall1(dbms_pipe_pack_message_number, DirectFunctionCall1(int8_numeric, PG_GETARG_DATUM(0))); PG_RETURN_VOID(); } orafce-VERSION_3_9_0/pipe.h000066400000000000000000000023321362147214200154410ustar00rootroot00000000000000#ifndef __PIPE__ #define __PIPE__ #define LOCALMSGSZ (8*1024) #define SHMEMMSGSZ (30*1024) #define MAX_PIPES 30 #define MAX_EVENTS 30 #define MAX_LOCKS 256 typedef struct _message_item { char *message; float8 timestamp; struct _message_item *next_message; struct _message_item *prev_message; unsigned char message_id; int *receivers; /* copy of array all registered receivers */ int receivers_number; } message_item; typedef struct _message_echo { struct _message_item *message; unsigned char message_id; struct _message_echo *next_echo; } message_echo; typedef struct { char *event_name; unsigned char max_receivers; int *receivers; int receivers_number; struct _message_item *messages; } alert_event; typedef struct { unsigned int sid; message_echo *echo; } alert_lock; bool ora_lock_shmem(size_t size, int max_pipes, int max_events, int max_locks, bool reset); #define ERRCODE_ORA_PACKAGES_LOCK_REQUEST_ERROR MAKE_SQLSTATE('3','0', '0','0','1') #define LOCK_ERROR() \ ereport(ERROR, \ (errcode(ERRCODE_ORA_PACKAGES_LOCK_REQUEST_ERROR), \ errmsg("lock request error"), \ errdetail("Failed exclusive locking of shared memory."), \ errhint("Restart PostgreSQL server."))); #endif orafce-VERSION_3_9_0/plunit.c000066400000000000000000000277061362147214200160260ustar00rootroot00000000000000/* * This API is subset plunit lib with http://www.apollo-pro.com/help/pl_unit_assertions.htm * */ #include "postgres.h" #include #include "funcapi.h" #include "catalog/pg_collation.h" #include "parser/parse_oper.h" #include "utils/builtins.h" #include "orafce.h" #include "builtins.h" PG_FUNCTION_INFO_V1(plunit_assert_true); PG_FUNCTION_INFO_V1(plunit_assert_true_message); PG_FUNCTION_INFO_V1(plunit_assert_false); PG_FUNCTION_INFO_V1(plunit_assert_false_message); PG_FUNCTION_INFO_V1(plunit_assert_null); PG_FUNCTION_INFO_V1(plunit_assert_null_message); PG_FUNCTION_INFO_V1(plunit_assert_not_null); PG_FUNCTION_INFO_V1(plunit_assert_not_null_message); PG_FUNCTION_INFO_V1(plunit_assert_equals); PG_FUNCTION_INFO_V1(plunit_assert_equals_message); PG_FUNCTION_INFO_V1(plunit_assert_equals_range); PG_FUNCTION_INFO_V1(plunit_assert_equals_range_message); PG_FUNCTION_INFO_V1(plunit_assert_not_equals); PG_FUNCTION_INFO_V1(plunit_assert_not_equals_message); PG_FUNCTION_INFO_V1(plunit_assert_not_equals_range); PG_FUNCTION_INFO_V1(plunit_assert_not_equals_range_message); PG_FUNCTION_INFO_V1(plunit_fail); PG_FUNCTION_INFO_V1(plunit_fail_message); static bool assert_equals_base(FunctionCallInfo fcinfo); static bool assert_equals_range_base(FunctionCallInfo fcinfo); static char *assert_get_message(FunctionCallInfo fcinfo, int nargs, char *default_message); /**************************************************************** * plunit.assert_true * plunit.assert_true_message * * Syntax: * PROCEDURE assert_true(condition boolean, message varchar default ''); * * Purpouse: * Asserts that the condition is true. The optional message will be * displayed if the assertion fails. If not supplied, a default message * is displayed. * ****************************************************************/ Datum plunit_assert_true(PG_FUNCTION_ARGS) { return plunit_assert_true_message(fcinfo); } Datum plunit_assert_true_message(PG_FUNCTION_ARGS) { char *message = assert_get_message(fcinfo, 2, "plunit.assert_true exception"); bool condition = PG_GETARG_BOOL(0); if (PG_ARGISNULL(0) || !condition) ereport(ERROR, (errcode(ERRCODE_CHECK_VIOLATION), errmsg("%s", message), errdetail("Plunit.assertation fails (assert_true)."))); PG_RETURN_VOID(); } /**************************************************************** * plunit.assert_false * plunit.assert_false_message * * Syntax: * PROCEDURE assert_false(condition boolean, message varchar default ''); * * Purpouse: * Asserts that the condition is false. The optional message will be * displayed if the assertion fails. If not supplied, a default message * is displayed. * ****************************************************************/ Datum plunit_assert_false(PG_FUNCTION_ARGS) { return plunit_assert_false_message(fcinfo); } Datum plunit_assert_false_message(PG_FUNCTION_ARGS) { char *message = assert_get_message(fcinfo, 2, "plunit.assert_false exception"); bool condition = PG_GETARG_BOOL(0); if (PG_ARGISNULL(0) || condition) ereport(ERROR, (errcode(ERRCODE_CHECK_VIOLATION), errmsg("%s", message), errdetail("Plunit.assertation fails (assert_false)."))); PG_RETURN_VOID(); } /**************************************************************** * plunit.assert_null * plunit.assert_null_message * * Syntax: * PROCEDURE assert_null(actual anyelement, message varchar default ''); * * Purpouse: * Asserts that the actual is null. The optional message will be * displayed if the assertion fails. If not supplied, a default message * is displayed. * ****************************************************************/ Datum plunit_assert_null(PG_FUNCTION_ARGS) { return plunit_assert_null_message(fcinfo); } Datum plunit_assert_null_message(PG_FUNCTION_ARGS) { char *message = assert_get_message(fcinfo, 2, "plunit.assert_null exception"); if (!PG_ARGISNULL(0)) ereport(ERROR, (errcode(ERRCODE_CHECK_VIOLATION), errmsg("%s", message), errdetail("Plunit.assertation fails (assert_null)."))); PG_RETURN_VOID(); } /**************************************************************** * plunit.assert_not_null * plunit.assert_not_null_message * * Syntax: * PROCEDURE assert_not_null(actual anyelement, message varchar default ''); * * Purpouse: * Asserts that the actual isn't null. The optional message will be * displayed if the assertion fails. If not supplied, a default message * is displayed. * ****************************************************************/ Datum plunit_assert_not_null(PG_FUNCTION_ARGS) { return plunit_assert_not_null_message(fcinfo); } Datum plunit_assert_not_null_message(PG_FUNCTION_ARGS) { char *message = assert_get_message(fcinfo, 2, "plunit.assert_not_null exception"); if (PG_ARGISNULL(0)) ereport(ERROR, (errcode(ERRCODE_CHECK_VIOLATION), errmsg("%s", message), errdetail("Plunit.assertation fails (assert_not_null)."))); PG_RETURN_VOID(); } /**************************************************************** * plunit.assert_equals * plunit.assert_equals_message * plunit.assert_equals_range * plunit.assert_equals_range_message * * Syntax: * PROCEDURE assert_equals(expected anyelement,actual anyelement, * message varchar default ''); * PROCEDURE assert_equals(expected double precision, actual double precision, * range double precision, message varchar default ''); * * Purpouse: * Asserts that expected and actual are equal. The optional message will be * displayed if the assertion fails. If not supplied, a default * message is displayed. * Asserts that expected and actual are within the specified range. * The optional message will be displayed if the assertion fails. * If not supplied, a default message is displayed. * ****************************************************************/ static char * assert_get_message(FunctionCallInfo fcinfo, int nargs, char *message) { char *result; if (PG_NARGS() == nargs) { text *msg; if (PG_ARGISNULL(nargs - 1)) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("message is NULL"), errdetail("Message may not be NULL."))); msg = PG_GETARG_TEXT_P(nargs - 1); result = text_to_cstring(msg); } else result = message; return result; } static bool assert_equals_base(FunctionCallInfo fcinfo) { Datum value1 = PG_GETARG_DATUM(0); Datum value2 = PG_GETARG_DATUM(1); Oid *ptr; ptr = (Oid *) fcinfo->flinfo->fn_extra; if (ptr == NULL) { Oid valtype = get_fn_expr_argtype(fcinfo->flinfo, 0); Oid eqopfcid; if (!OidIsValid(valtype)) elog(ERROR, "could not determine data type of input"); eqopfcid = equality_oper_funcid(valtype); if (!OidIsValid(eqopfcid)) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("unknown equal operand for datatype"))); /* First time calling for current query: allocate storage */ fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt, sizeof(Oid)); ptr = (Oid *) fcinfo->flinfo->fn_extra; *ptr = eqopfcid; } return DatumGetBool(OidFunctionCall2Coll(*ptr, DEFAULT_COLLATION_OID, value1, value2)); } Datum plunit_assert_equals(PG_FUNCTION_ARGS) { return plunit_assert_equals_message(fcinfo); } Datum plunit_assert_equals_message(PG_FUNCTION_ARGS) { char *message = assert_get_message(fcinfo, 3, "plunit.assert_equal exception"); /* skip all tests for NULL value */ if (PG_ARGISNULL(0) || PG_ARGISNULL(1)) ereport(ERROR, (errcode(ERRCODE_CHECK_VIOLATION), errmsg("%s", message), errdetail("Plunit.assertation fails (assert_equals)."))); if (!assert_equals_base(fcinfo)) ereport(ERROR, (errcode(ERRCODE_CHECK_VIOLATION), errmsg("%s", message), errdetail("Plunit.assertation fails (assert_equals)."))); PG_RETURN_VOID(); } Datum plunit_assert_equals_range(PG_FUNCTION_ARGS) { return plunit_assert_equals_range_message(fcinfo); } static bool assert_equals_range_base(FunctionCallInfo fcinfo) { float8 expected_value; float8 actual_value; float8 range_value; range_value = PG_GETARG_FLOAT8(2); if (range_value < 0) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("cannot set range to negative number"))); expected_value = PG_GETARG_FLOAT8(0); actual_value = PG_GETARG_FLOAT8(1); return fabs(expected_value - actual_value) < range_value; } Datum plunit_assert_equals_range_message(PG_FUNCTION_ARGS) { char *message = assert_get_message(fcinfo, 4, "plunit.assert_equal exception"); /* skip all tests for NULL value */ if (PG_ARGISNULL(0) || PG_ARGISNULL(1) || PG_ARGISNULL(2)) ereport(ERROR, (errcode(ERRCODE_CHECK_VIOLATION), errmsg("%s", message), errdetail("Plunit.assertation fails (assert_equals)."))); if (!assert_equals_range_base(fcinfo)) ereport(ERROR, (errcode(ERRCODE_CHECK_VIOLATION), errmsg("%s", message), errdetail("Plunit.assertation fails (assert_equals)."))); PG_RETURN_VOID(); } /**************************************************************** * plunit.assert_not_equals * plunit.assert_not_equals_message * plunit.assert_not_equals_range * plunit.assert_not_equals_range_message * * Syntax: * PROCEDURE assert_not_equals(expected anyelement,actual anyelement, * message varchar default ''); * PROCEDURE assert_not_equals(expected double precision, expected double precision, * range double precision, message varchar default ''); * * Purpouse: * Asserts that expected and actual are equal. The optional message will be * displayed if the assertion fails. If not supplied, a default * message is displayed. * Asserts that expected and actual are within the specified range. * The optional message will be displayed if the assertion fails. * If not supplied, a default message is displayed. * ****************************************************************/ Datum plunit_assert_not_equals(PG_FUNCTION_ARGS) { return plunit_assert_not_equals_message(fcinfo); } Datum plunit_assert_not_equals_message(PG_FUNCTION_ARGS) { char *message = assert_get_message(fcinfo, 3, "plunit.assert_not_equal exception"); /* skip all tests for NULL value */ if (PG_ARGISNULL(0) || PG_ARGISNULL(1)) ereport(ERROR, (errcode(ERRCODE_CHECK_VIOLATION), errmsg("%s", message), errdetail("Plunit.assertation fails (assert_not_equals)."))); if (assert_equals_base(fcinfo)) ereport(ERROR, (errcode(ERRCODE_CHECK_VIOLATION), errmsg("%s", message), errdetail("Plunit.assertation fails (assert_not_equals)."))); PG_RETURN_VOID(); } Datum plunit_assert_not_equals_range(PG_FUNCTION_ARGS) { return plunit_assert_not_equals_range_message(fcinfo); } Datum plunit_assert_not_equals_range_message(PG_FUNCTION_ARGS) { char *message = assert_get_message(fcinfo, 4, "plunit.assert_not_equal exception"); /* skip all tests for NULL value */ if (PG_ARGISNULL(0) || PG_ARGISNULL(1) || PG_ARGISNULL(2)) ereport(ERROR, (errcode(ERRCODE_CHECK_VIOLATION), errmsg("%s", message), errdetail("Plunit.assertation fails (assert_not_equals)."))); if (assert_equals_range_base(fcinfo)) ereport(ERROR, (errcode(ERRCODE_CHECK_VIOLATION), errmsg("%s", message), errdetail("Plunit.assertation fails (assert_not_equals)."))); PG_RETURN_VOID(); } /**************************************************************** * plunit.fail * plunit.fail_message * * Syntax: * PROCEDURE fail(message varchar default ''); * * Purpouse: * Fail can be used to cause a test procedure to fail * immediately using the supplied message. * ****************************************************************/ Datum plunit_fail(PG_FUNCTION_ARGS) { return plunit_fail_message(fcinfo); } Datum plunit_fail_message(PG_FUNCTION_ARGS) { char *message = assert_get_message(fcinfo, 1, "plunit.assert_fail exception"); ereport(ERROR, (errcode(ERRCODE_CHECK_VIOLATION), errmsg("%s", message), errdetail("Plunit.assertation (assert_fail)."))); PG_RETURN_VOID(); } orafce-VERSION_3_9_0/plvdate.c000066400000000000000000000515661362147214200161530ustar00rootroot00000000000000/* This code implements one part of functonality of free available library PL/Vision. Please look www.quest.com This library isn't optimalized for big numbers, for working with n days (n > 10000), can be slow (on my P4 31ms). Original author: Steven Feuerstein, 1996 - 2002 PostgreSQL implementation author: Pavel Stehule, 2006-2018 This module is under BSD Licence */ #define PLVDATE_VERSION "PostgreSQL PLVdate, version 3.7, October 2018" #include "postgres.h" #include "utils/date.h" #include "utils/builtins.h" #include #include #include "orafce.h" #include "builtins.h" PG_FUNCTION_INFO_V1(plvdate_add_bizdays); PG_FUNCTION_INFO_V1(plvdate_nearest_bizday); PG_FUNCTION_INFO_V1(plvdate_next_bizday); PG_FUNCTION_INFO_V1(plvdate_bizdays_between); PG_FUNCTION_INFO_V1(plvdate_prev_bizday); PG_FUNCTION_INFO_V1(plvdate_isbizday); PG_FUNCTION_INFO_V1(plvdate_set_nonbizday_dow); PG_FUNCTION_INFO_V1(plvdate_unset_nonbizday_dow); PG_FUNCTION_INFO_V1(plvdate_set_nonbizday_day); PG_FUNCTION_INFO_V1(plvdate_unset_nonbizday_day); PG_FUNCTION_INFO_V1(plvdate_use_easter); PG_FUNCTION_INFO_V1(plvdate_using_easter); PG_FUNCTION_INFO_V1(plvdate_use_great_friday); PG_FUNCTION_INFO_V1(plvdate_using_great_friday); PG_FUNCTION_INFO_V1(plvdate_include_start); PG_FUNCTION_INFO_V1(plvdate_including_start); PG_FUNCTION_INFO_V1(plvdate_default_holidays); PG_FUNCTION_INFO_V1(plvdate_version); PG_FUNCTION_INFO_V1(plvdate_days_inmonth); PG_FUNCTION_INFO_V1(plvdate_isleapyear); #define CHECK_SEQ_SEARCH(_l, _s) \ do { \ if ((_l) < 0) { \ ereport(ERROR, \ (errcode(ERRCODE_INVALID_DATETIME_FORMAT), \ errmsg("invalid value for %s", (_s)))); \ } \ } while (0) #define SUNDAY (1 << 0) #define SATURDAY (1 << 6) static unsigned char nonbizdays = SUNDAY | SATURDAY; static bool use_easter = true; static bool use_great_friday = true; static bool include_start = true; static int country_id = -1; /* unknown */ #define MAX_holidays 30 #define MAX_EXCEPTIONS 50 typedef struct { char day; char month; } holiday_desc; typedef struct { unsigned char nonbizdays; bool use_easter; bool use_great_friday; holiday_desc *holidays; int holidays_c; } cultural_info; static holiday_desc holidays[MAX_holidays]; /* sorted array */ static DateADT exceptions[MAX_EXCEPTIONS]; /* sorted array */ static int holidays_c = 0; static int exceptions_c = 0; static holiday_desc czech_holidays[] = { {1,1}, // Novy rok {1,5}, // Svatek prace {8,5}, // Den osvobozeni {5,7}, // Den slovanskych verozvestu {6,7}, // Den upaleni mistra Jana Husa {28,9}, // Den ceske statnosti {28,10}, // Den vzniku samostatneho ceskoslovenskeho statu {17,11}, // Den boje za svobodu a demokracii {24,12}, // Stedry den {25,12}, // 1. svatek vanocni {26,12} // 2. svatek vanocni }; static holiday_desc germany_holidays[] = { {1,1},{1,5},{25,5},{4,6},{5,6}, {15,8},{3,10},{25,12},{26,12} }; static holiday_desc poland_holidays[] = { {1,1},{1,5},{3,5},{15,6},{15,8}, {1,11},{11,11},{25,12},{26,12} }; static holiday_desc austria_holidays[] = { {1,1},{6,1},{1,5},{25,5},{4,6}, {5,6},{15,6},{15,8},{26,10},{1,11}, {8,12},{25,12},{26,12} }; static holiday_desc slovakia_holidays[] = { {1,1},{6,1},{1,5},{8,5},{5,7}, {29,8},{1,9},{15,9},{1,11},{17,11}, {24,12},{25,12},{26,12} }; static holiday_desc russian_holidays[] = { {1,1},{2,1},{3,1},{4,1},{5,1}, {7,1},{23,2},{8,3},{1,5},{9,5}, {12,6}, {4,11} }; static holiday_desc england_holidays[] = { {1,1},{2,1},{1,5},{29,5},{28,8}, {25,12},{26,12} }; static holiday_desc usa_holidays[] = { {1,1},{16,1},{20,2},{29,5},{4,7}, {4,9},{9,10},{11,11},{23,11},{25,12} }; cultural_info defaults_ci[] = { {SUNDAY | SATURDAY, true, true, czech_holidays, 11}, {SUNDAY | SATURDAY, true, true, germany_holidays, 9}, {SUNDAY | SATURDAY, true, false, poland_holidays, 9}, {SUNDAY | SATURDAY, true, false, austria_holidays, 13}, {SUNDAY | SATURDAY, true, true, slovakia_holidays, 13}, {SUNDAY | SATURDAY, false, false, russian_holidays, 12}, {SUNDAY | SATURDAY, true, true, england_holidays, 7}, {SUNDAY | SATURDAY, false, false, usa_holidays, 10} }; STRING_PTR_FIELD_TYPE states[] = { "Czech", "Germany", "Poland", "Austria", "Slovakia", "Russia", "Gb", "Usa", NULL, }; static int dateadt_comp(const void* a, const void* b) { DateADT *_a = (DateADT*)a; DateADT *_b = (DateADT*)b; return *_a - *_b; } static int holiday_desc_comp(const void* a, const void* b) { int result; if (0 == (result = ((holiday_desc*)a)->month - ((holiday_desc*)b)->month)) result = ((holiday_desc*)a)->day - ((holiday_desc*)b)->day; return result; } static void calc_easter_sunday(int year, int* dd, int* mm) { int b, d, e, q; if (year < 1900 || year > 2099) ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("date is out of range"), errdetail("Easter is defined only for years between 1900 and 2099"))); b = 255 - 11 * (year % 19); d = ((b - 21) % 30) + 21; if (d > 38) d -= 1; e = (year + year/4 + d + 1) % 7; q = d + 7 - e; if (q < 32) { *dd = q; *mm = 3; } else { *dd = q - 31; *mm = 4; } } /* * returns true, when day d is any easter holiday. * */ static bool easter_holidays(DateADT day, int y, int m) { if (use_great_friday || use_easter) { if (m == 3 || m == 4) { int easter_sunday_day; int easter_sunday_month; int easter_sunday; calc_easter_sunday(y, &easter_sunday_day, &easter_sunday_month); easter_sunday = date2j(y, easter_sunday_month, easter_sunday_day) - POSTGRES_EPOCH_JDATE; if (use_easter && (day == easter_sunday || day == easter_sunday + 1)) return true; if (use_great_friday && day == easter_sunday - 2) { /* Great Friday is introduced in Czech Republic in 2016 */ if (country_id == 0) { if (y >= 2016) return true; } else return true; } } } return false; } static DateADT ora_add_bizdays(DateADT day, int days) { int d, dx; int y, m, auxd; holiday_desc hd; d = j2day(day+POSTGRES_EPOCH_JDATE); dx = days > 0? 1 : -1; while (days != 0) { d = (d+dx) % 7; d = (d < 0) ? 6:d; day += dx; if ((1 << d) & nonbizdays) continue; if (NULL != bsearch(&day, exceptions, exceptions_c, sizeof(DateADT), dateadt_comp)) continue; j2date(day + POSTGRES_EPOCH_JDATE, &y, &m, &auxd); hd.day = (char) auxd; hd.month = (char) m; if (easter_holidays(day, y, m)) continue; if (NULL != bsearch(&hd, holidays, holidays_c, sizeof(holiday_desc), holiday_desc_comp)) continue; days -= dx; } return day; } static int ora_diff_bizdays(DateADT day1, DateADT day2) { int d, days; int y, m, auxd; holiday_desc hd; int loops = 0; bool start_is_bizday = false; DateADT aux_day; if (day1 > day2) { aux_day = day1; day1 = day2; day2 = aux_day; } /* d is incremented on start of cycle, so now I have to decrease one */ d = j2day(day1+POSTGRES_EPOCH_JDATE-1); days = 0; while (day1 <= day2) { loops++; day1 += 1; d = (d+1) % 7; if ((1 << d) & nonbizdays) continue; if (NULL != bsearch(&day1, exceptions, exceptions_c, sizeof(DateADT), dateadt_comp)) continue; j2date(day1 + POSTGRES_EPOCH_JDATE, &y, &m, &auxd); hd.day = (char) auxd; hd.month = (char) m; if (easter_holidays(day1, y, m)) continue; if (NULL != bsearch(&hd, holidays, holidays_c, sizeof(holiday_desc), holiday_desc_comp)) continue; /* now the day have to be bizday, remember if first day was bizday */ if (loops == 1) start_is_bizday = true; days += 1; } /* * decrease result when first day was bizday, but we don't want * calculate first day. */ if ( start_is_bizday && !include_start && days > 0) days -= 1; return days; } /**************************************************************** * PLVdate.add_bizdays * * Syntax: * FUNCTION add_bizdays(IN dt DATE, IN days int) RETURNS DATE; * * Purpouse: * Get the date created by adding business days to a date * ****************************************************************/ Datum plvdate_add_bizdays (PG_FUNCTION_ARGS) { DateADT day = PG_GETARG_DATEADT(0); int days = PG_GETARG_INT32(1); PG_RETURN_DATEADT(ora_add_bizdays(day,days)); } /**************************************************************** * PLVdate.nearest_bizday * * Syntax: * FUNCTION nearest_bizday(IN dt DATE) RETURNS DATE; * * Purpouse: * Get the nearest business date to a given date, user defined * ****************************************************************/ Datum plvdate_nearest_bizday (PG_FUNCTION_ARGS) { DateADT dt = PG_GETARG_DATEADT(0); DateADT d1, d2, res; d1 = ora_add_bizdays(dt, -1); d2 = ora_add_bizdays(dt, 1); if ((dt - d1) > (d2 - dt)) res = d2; else res = d1; PG_RETURN_DATEADT(res); } /**************************************************************** * PLVdate.next_bizday * * Syntax: * FUNCTION next_bizday(IN dt DATE) RETURNS DATE; * * Purpouse: * Get the next business date from a given date, user defined * ****************************************************************/ Datum plvdate_next_bizday (PG_FUNCTION_ARGS) { DateADT day = PG_GETARG_DATEADT(0); PG_RETURN_DATEADT(ora_add_bizdays(day,1)); } /**************************************************************** * PLVdate.bizdays_between * * Syntax: * FUNCTION bizdays_between(IN dt1 DATE, IN dt2 DATE) * RETURNS int; * * Purpouse: * Get the number of business days between two dates * ****************************************************************/ Datum plvdate_bizdays_between (PG_FUNCTION_ARGS) { DateADT day1 = PG_GETARG_DATEADT(0); DateADT day2 = PG_GETARG_DATEADT(1); PG_RETURN_INT32(ora_diff_bizdays(day1,day2)); } /**************************************************************** * PLVdate.prev_bizday * * Syntax: * FUNCTION prev_bizday(IN dt DATE) RETURNS date; * * Purpouse: * Get the previous business date from a given date, user * defined * ****************************************************************/ Datum plvdate_prev_bizday (PG_FUNCTION_ARGS) { DateADT day = PG_GETARG_DATEADT(0); PG_RETURN_DATEADT(ora_add_bizdays(day,-1)); } /**************************************************************** * PLVdate.isbizday * * Syntax: * FUNCTION isbizday(IN dt DATE) RETURNS bool; * * Purpouse: * Call this function to determine if a date is a business day * ****************************************************************/ Datum plvdate_isbizday (PG_FUNCTION_ARGS) { DateADT day = PG_GETARG_DATEADT(0); int y, m, d; holiday_desc hd; if (0 != ((1 << j2day(day+POSTGRES_EPOCH_JDATE)) & nonbizdays)) return false; if (NULL != bsearch(&day, exceptions, exceptions_c, sizeof(DateADT), dateadt_comp)) return false; j2date(day + POSTGRES_EPOCH_JDATE, &y, &m, &d); hd.month = m; hd.day = d; if (easter_holidays(day, y, m)) return false; PG_RETURN_BOOL (NULL == bsearch(&hd, holidays, holidays_c, sizeof(holiday_desc), holiday_desc_comp)); } /**************************************************************** * PLVdate.set_nonbizday * * Syntax: * FUNCTION set_nonbizday(IN dow VARCHAR) RETURNS void; * * Purpouse: * Set day of week as non bussines day * ****************************************************************/ Datum plvdate_set_nonbizday_dow (PG_FUNCTION_ARGS) { unsigned char check; text *day_txt = PG_GETARG_TEXT_PP(0); int d = ora_seq_search(VARDATA_ANY(day_txt), ora_days, VARSIZE_ANY_EXHDR(day_txt)); CHECK_SEQ_SEARCH(d, "DAY/Day/day"); check = nonbizdays | (1 << d); if (check == 0x7f) ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION), errmsg("nonbizday registeration error"), errdetail("Constraint violation."), errhint("One day in week have to be bizday."))); nonbizdays = nonbizdays | (1 << d); PG_RETURN_VOID(); } /**************************************************************** * PLVdate.unset_nonbizday * * Syntax: * FUNCTION unset_nonbizday(IN dow VARCHAR) RETURNS void; * * Purpouse: * Unset day of week as non bussines day * ****************************************************************/ Datum plvdate_unset_nonbizday_dow (PG_FUNCTION_ARGS) { text *day_txt = PG_GETARG_TEXT_PP(0); int d = ora_seq_search(VARDATA_ANY(day_txt), ora_days, VARSIZE_ANY_EXHDR(day_txt)); CHECK_SEQ_SEARCH(d, "DAY/Day/day"); nonbizdays = (nonbizdays | (1 << d)) ^ (1 << d); PG_RETURN_VOID(); } /**************************************************************** * PLVdate.set_nonbizday * * Syntax: * FUNCTION set_nonbizday(IN day DATE) RETURNS void; * FUNCTION set_nonbizday(IN day DATE, IN repeat := false BOOL) RETURNS void; * * Purpouse: * Set day as non bussines day, second arg specify year's * periodicity * ****************************************************************/ Datum plvdate_set_nonbizday_day (PG_FUNCTION_ARGS) { DateADT arg1 = PG_GETARG_DATEADT(0); bool arg2 = PG_GETARG_BOOL(1); int y, m, d; holiday_desc hd; if (arg2) { if (holidays_c == MAX_holidays) ereport(ERROR, (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("nonbizday registeration error"), errdetail("Too much registered nonbizdays."), errhint("Increase MAX_holidays in 'plvdate.c'."))); j2date(arg1 + POSTGRES_EPOCH_JDATE, &y, &m, &d); hd.month = m; hd.day = d; if (NULL != bsearch(&hd, holidays, holidays_c, sizeof(holiday_desc), holiday_desc_comp)) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("nonbizday registeration error"), errdetail("Date is registered."))); holidays[holidays_c].month = m; holidays[holidays_c].day = d; holidays_c += 1; qsort(holidays, holidays_c, sizeof(holiday_desc), holiday_desc_comp); } else { if (exceptions_c == MAX_EXCEPTIONS) ereport(ERROR, (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("nonbizday registeration error"), errdetail("Too much registered nonrepeated nonbizdays."), errhint("Increase MAX_EXCEPTIONS in 'plvdate.c'."))); if (NULL != bsearch(&arg1, exceptions, exceptions_c, sizeof(DateADT), dateadt_comp)) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("nonbizday registeration error"), errdetail("Date is registered."))); exceptions[exceptions_c++] = arg1; qsort(exceptions, exceptions_c, sizeof(DateADT), dateadt_comp); } PG_RETURN_VOID(); } /**************************************************************** * PLVdate.unset_nonbizday * * Syntax: * FUNCTION unset_nonbizday(IN day DATE) RETURNS void; * FUNCTION unset_nonbizday(IN day DATE, IN repeat := false BOOL) RETURNS void; * * Purpouse: * Unset day as non bussines day, second arg specify year's * periodicity * ****************************************************************/ Datum plvdate_unset_nonbizday_day (PG_FUNCTION_ARGS) { DateADT arg1 = PG_GETARG_DATEADT(0); bool arg2 = PG_GETARG_BOOL(1); int y, m, d; bool found = false; int i; if (arg2) { j2date(arg1 + POSTGRES_EPOCH_JDATE, &y, &m, &d); for (i = 0; i < holidays_c; i++) { if (!found && holidays[i].month == m && holidays[i].day == d) found = true; else if (found) { holidays[i-1].month = holidays[i].month; holidays[i-1].day = holidays[i].day; } } if (found) holidays_c -= 1; } else { for (i = 0; i < exceptions_c; i++) if (!found && exceptions[i] == arg1) found = true; else if (found) exceptions[i-1] = exceptions[i]; if (found) exceptions_c -= 1; } if (!found) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("nonbizday unregisteration error"), errdetail("Nonbizday not found."))); PG_RETURN_VOID(); } /**************************************************************** * PLVdate.use_easter * * Syntax: * FUNCTION unuse_easter() RETURNS void; * FUNCTION use_easter() RETURNS void; * FUNCTION use_easter(IN bool) RETURNS void * * Purpouse: * Have to use easter as nonbizday? * ****************************************************************/ Datum plvdate_use_easter (PG_FUNCTION_ARGS) { use_easter = PG_GETARG_BOOL(0); PG_RETURN_VOID(); } /**************************************************************** * PLVdate.using_easter * * Syntax: * FUNCTION using_easter() RETURNS bool * * Purpouse: * Use it easter as nonbizday? * ****************************************************************/ Datum plvdate_using_easter (PG_FUNCTION_ARGS) { PG_RETURN_BOOL(use_easter); } /**************************************************************** * PLVdate.use_great_friday * * Syntax: * FUNCTION unuse_great_friday() RETURNS void; * FUNCTION use_great_friday() RETURNS void; * FUNCTION use_great_friday(IN bool) RETURNS void * * Purpouse: * Have to use great_friday as nonbizday? * ****************************************************************/ Datum plvdate_use_great_friday (PG_FUNCTION_ARGS) { use_great_friday = PG_GETARG_BOOL(0); PG_RETURN_VOID(); } /**************************************************************** * PLVdate.using_great_friday * * Syntax: * FUNCTION using_great_friday() RETURNS bool * * Purpouse: * Use it great friday as nonbizday? * ****************************************************************/ Datum plvdate_using_great_friday (PG_FUNCTION_ARGS) { PG_RETURN_BOOL(use_great_friday); } /**************************************************************** * PLVdate.include_start * * Syntax: * FUNCTION include_start() RETURNS void; * FUNCTION noinclude_start() RETURNS void; * FUNCTION include_start(IN bool) RETURNS void * * Purpouse: * Have to include current day in bizdays_between calculation? * ****************************************************************/ Datum plvdate_include_start (PG_FUNCTION_ARGS) { include_start = PG_GETARG_BOOL(0); PG_RETURN_VOID(); } /**************************************************************** * PLVdate.including_start * * Syntax: * FUNCTION including_start() RETURNS bool * * Purpouse: * include current day in bizdays_between calculation? * ****************************************************************/ Datum plvdate_including_start (PG_FUNCTION_ARGS) { PG_RETURN_BOOL(include_start); } /* * Load some national configurations * */ Datum plvdate_default_holidays (PG_FUNCTION_ARGS) { text *country = PG_GETARG_TEXT_PP(0); country_id = ora_seq_search(VARDATA_ANY(country), states, VARSIZE_ANY_EXHDR(country)); CHECK_SEQ_SEARCH(country_id, "STATE/State/state"); nonbizdays = defaults_ci[country_id].nonbizdays; use_easter = defaults_ci[country_id].use_easter; use_great_friday = defaults_ci[country_id].use_great_friday; exceptions_c = 0; holidays_c = defaults_ci[country_id].holidays_c; memcpy(holidays, defaults_ci[country_id].holidays, holidays_c*sizeof(holiday_desc)); PG_RETURN_VOID(); } /* * helper maintaince functions */ Datum plvdate_version (PG_FUNCTION_ARGS) { PG_RETURN_CSTRING(PLVDATE_VERSION); } /**************************************************************** * PLVdate.days_inmonth * * Syntax: * FUNCTION days_inmonth(date) RETURNS integer * * Purpouse: * Returns month's length * ****************************************************************/ Datum plvdate_days_inmonth(PG_FUNCTION_ARGS) { DateADT day = PG_GETARG_DATEADT(0); int result; int y, m, d; j2date(day + POSTGRES_EPOCH_JDATE, &y, &m, &d); result = date2j(y, m+1, 1) - date2j(y, m, 1); PG_RETURN_INT32(result); } /**************************************************************** * PLVdate.isleapyear * * Syntax: * FUNCTION isleapyear() RETURNS bool * * Purpouse: * Returns true, if year is leap * ****************************************************************/ Datum plvdate_isleapyear(PG_FUNCTION_ARGS) { DateADT day = PG_GETARG_DATEADT(0); int y, m, d; bool result; j2date(day + POSTGRES_EPOCH_JDATE, &y, &m, &d); result = ((( y % 4) == 0) && ((y % 100) != 0)) || ((y / 400) == 0); PG_RETURN_BOOL(result); } /**************************************************************** * PLVdate.set_nonbizdays * * Syntax: * FUNCTION set_nonbizdays(IN dow bool[7]) RETURNS void; * * Purpouse: * Set pattern bussines/nonbussines days in week * ****************************************************************/ /**************************************************************** * PLVdate.set_nonbizday * * Syntax: * FUNCTION set_nonbizdays(IN days DATE[]) RETURNS void; * FUNCTION set_nonbizdays(IN days DATE[], IN repeat := false BOOL) RETURNS void; * * Purpouse: * Set days as non bussines day, second arg specify year's * periodicity * ****************************************************************/ /**************************************************************** * PLVdate.display * * Syntax: * FUNCTION display() RETURNS void; * * Purpouse: * Show current calendar * ****************************************************************/ orafce-VERSION_3_9_0/plvlex.c000066400000000000000000000152701362147214200160160ustar00rootroot00000000000000/* This code implements one part of functonality of free available library PL/Vision. Please look www.quest.com Original author: Steven Feuerstein, 1996 - 2002 PostgreSQL implementation author: Pavel Stehule, 2006-2018 This module is under BSD Licence History: 1.0. first public version 13. March 2006 */ #include #include #include "postgres.h" #include "catalog/pg_type.h" #include "lib/stringinfo.h" #include "nodes/pg_list.h" #include "utils/date.h" #include "utils/builtins.h" #include "plvlex.h" #include "sqlparse.h" #include "funcapi.h" #include "orafce.h" #include "builtins.h" typedef struct { List *nodes; int nnodes; int cnode; char **values; } tokensFctx; PG_FUNCTION_INFO_V1(plvlex_tokens); extern int orafce_sql_yyparse(); extern void orafce_sql_yyerror(List **result, const char *message); extern void orafce_sql_scanner_init(const char *str); extern void orafce_sql_scanner_finish(void); static orafce_lexnode *__node; static char *__result; static int __len; #define CSTRING(txt) \ ( \ __len = VARSIZE(txt) - VARHDRSZ, \ __result = palloc(__len + 1), \ memcpy(__result, VARDATA(txt), __len), \ __result[__len] = '\0', \ __result) #define COPY_TO_S(src,dest,col) (dest->col = (src->col ? pstrdup(src->col) : NULL)) #define COPY_TO(src,dest,col) (dest->col = src->col) #define COPY_FIELDS(src,dest) \ COPY_TO(src, dest, typenode), \ COPY_TO_S(src,dest,str), \ COPY_TO(src,dest,keycode), \ COPY_TO(src,dest,lloc), \ COPY_TO_S(src,dest,sep), \ COPY_TO(src,dest,modificator), \ COPY_TO(src,dest,classname) #define COPY_NODE(src) \ ( \ __node = (orafce_lexnode*) palloc(sizeof(orafce_lexnode)), \ COPY_FIELDS(src,__node), \ __node) /* Finding triplet a.b --> a */ #define IsType(node, type) (node->typenode == X_##type) #define APPEND_NODE(list,nd) \ if (nd) \ { \ list = lappend(list, nd); \ nd = NULL; \ } #define mod(a) (a->modificator) #define SF(a) (a ? a : "") #define NEWNODE(type) \ ( \ __node = (orafce_lexnode *) palloc(sizeof(orafce_lexnode)), \ __node->typenode = X_##type, \ __node->modificator = NULL, \ __node->sep = NULL, \ __node->keycode = -1, \ __node->classname = #type, \ __node->lloc = 0, \ __node ) static orafce_lexnode * compose(orafce_lexnode *a, orafce_lexnode *b) { orafce_lexnode *result; StringInfo sinfo; sinfo = makeStringInfo(); result = NEWNODE(IDENT); result->lloc = a->lloc; if (strcmp(SF(mod(a)), "dq") == 0) appendStringInfo(sinfo, "\"%s\".", a->str); else { appendStringInfoString(sinfo, a->str); appendStringInfoChar(sinfo, '.'); } if (strcmp(SF(mod(b)), "dq") == 0) appendStringInfo(sinfo, "\"%s\"", b->str); else appendStringInfoString(sinfo, b->str); result->str = sinfo->data; return result; } static List * filterList(List *list, bool skip_spaces, bool qnames) { List *result = NIL; ListCell *cell; bool isdot = false; orafce_lexnode *a = NULL; orafce_lexnode *dot = NULL; foreach(cell, list) { orafce_lexnode *nd = (orafce_lexnode *) lfirst(cell); if (qnames) { isdot = (IsType(nd, OTHERS) && (nd->str[0] == '.')); if (IsType(nd, IDENT) && dot && a) { a = compose(a, nd); dot = NULL; continue; } else if (isdot && !dot && a) { dot = COPY_NODE(nd); continue; } else if (IsType(nd, IDENT) && !a) { a = COPY_NODE(nd); continue; } } /* clean buffered values */ APPEND_NODE(result,a); APPEND_NODE(result,dot); if (!(skip_spaces && IsType(nd, WHITESPACE))) { result = lappend(result, COPY_NODE(nd)); } } /* clean buffered values */ APPEND_NODE(result,a); APPEND_NODE(result,dot); return result; } Datum plvlex_tokens(PG_FUNCTION_ARGS) { #ifdef _MSC_VER ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("plvlex.tokens is not available in the built"))); PG_RETURN_VOID(); #else FuncCallContext *funcctx; TupleDesc tupdesc; AttInMetadata *attinmeta; tokensFctx *fctx; if (SRF_IS_FIRSTCALL ()) { MemoryContext oldcontext; List *lexems; text *src = PG_GETARG_TEXT_P(0); bool skip_spaces = PG_GETARG_BOOL(1); bool qnames = PG_GETARG_BOOL(2); orafce_sql_scanner_init(CSTRING(src)); if (orafce_sql_yyparse(&lexems) != 0) orafce_sql_yyerror(NULL, "bogus input"); orafce_sql_scanner_finish(); funcctx = SRF_FIRSTCALL_INIT (); oldcontext = MemoryContextSwitchTo (funcctx->multi_call_memory_ctx); fctx = (tokensFctx*) palloc (sizeof (tokensFctx)); funcctx->user_fctx = (void *)fctx; fctx->nodes = filterList(lexems, skip_spaces, qnames); fctx->nnodes = list_length(fctx->nodes); fctx->cnode = 0; fctx->values = (char **) palloc (6 * sizeof (char *)); fctx->values [0] = (char*) palloc (16 * sizeof (char)); fctx->values [1] = (char*) palloc (1024 * sizeof (char)); fctx->values [2] = (char*) palloc (16 * sizeof (char)); fctx->values [3] = (char*) palloc (16 * sizeof (char)); fctx->values [4] = (char*) palloc (255 * sizeof (char)); fctx->values [5] = (char*) palloc (255 * sizeof (char)); #if PG_VERSION_NUM >= 120000 tupdesc = CreateTemplateTupleDesc (6); #else tupdesc = CreateTemplateTupleDesc (6, false); #endif TupleDescInitEntry (tupdesc, 1, "start_pos", INT4OID, -1, 0); TupleDescInitEntry (tupdesc, 2, "token", TEXTOID, -1, 0); TupleDescInitEntry (tupdesc, 3, "keycode", INT4OID, -1, 0); TupleDescInitEntry (tupdesc, 4, "class", TEXTOID, -1, 0); TupleDescInitEntry (tupdesc, 5, "separator", TEXTOID, -1, 0); TupleDescInitEntry (tupdesc, 6, "mod", TEXTOID, -1, 0); attinmeta = TupleDescGetAttInMetadata (tupdesc); funcctx -> attinmeta = attinmeta; MemoryContextSwitchTo (oldcontext); } funcctx = SRF_PERCALL_SETUP (); fctx = (tokensFctx*) funcctx->user_fctx; while (fctx->cnode < fctx->nnodes) { char **values; Datum result; HeapTuple tuple; char *back_vals[6]; orafce_lexnode *nd = (orafce_lexnode*) list_nth(fctx->nodes, fctx->cnode++); values = fctx->values; back_vals[2] = values[2]; back_vals[4] = values[4]; back_vals[5] = values[5]; snprintf(values[0], 16, "%d", nd->lloc); snprintf(values[1], 10000, "%s", SF(nd->str)); snprintf(values[2], 16, "%d", nd->keycode); snprintf(values[3], 16, "%s", nd->classname); snprintf(values[4], 255, "%s", SF(nd->sep)); snprintf(values[5], 48, "%s", SF(nd->modificator)); if (nd->keycode == -1) values[2] = NULL; if (!nd->sep) values[4] = NULL; if (!nd->modificator) values[5] = NULL; tuple = BuildTupleFromCStrings(funcctx->attinmeta, fctx->values); result = HeapTupleGetDatum(tuple); values[2] = back_vals[2]; values[4] = back_vals[4]; values[5] = back_vals[5]; SRF_RETURN_NEXT (funcctx, result); } SRF_RETURN_DONE (funcctx); #endif } orafce-VERSION_3_9_0/plvlex.h000066400000000000000000000002241362147214200160140ustar00rootroot00000000000000typedef struct { int typenode; char *str; int keycode; int lloc; char *sep; char *modificator; char *classname; } orafce_lexnode; orafce-VERSION_3_9_0/plvstr.c000066400000000000000000000661751362147214200160500ustar00rootroot00000000000000/* This code implements one part of functonality of free available library PL/Vision. Please look www.quest.com Original author: Steven Feuerstein, 1996 - 2002 PostgreSQL implementation author: Pavel Stehule, 2006-2018 This module is under BSD Licence History: 1.0. first public version 13. March 2006 */ #include "postgres.h" #include "utils/builtins.h" #include "utils/numeric.h" #include "string.h" #include "stdlib.h" #include "utils/pg_locale.h" #include "mb/pg_wchar.h" #include "nodes/execnodes.h" #include "catalog/pg_type.h" #include "libpq/pqformat.h" #include "orafce.h" #include "builtins.h" PG_FUNCTION_INFO_V1(plvstr_rvrs); PG_FUNCTION_INFO_V1(plvstr_normalize); PG_FUNCTION_INFO_V1(plvstr_is_prefix_text); PG_FUNCTION_INFO_V1(plvstr_is_prefix_int); PG_FUNCTION_INFO_V1(plvstr_is_prefix_int64); PG_FUNCTION_INFO_V1(plvstr_lpart); PG_FUNCTION_INFO_V1(plvstr_rpart); PG_FUNCTION_INFO_V1(plvstr_lstrip); PG_FUNCTION_INFO_V1(plvstr_rstrip); PG_FUNCTION_INFO_V1(plvstr_left); PG_FUNCTION_INFO_V1(plvstr_right); PG_FUNCTION_INFO_V1(plvstr_substr2); PG_FUNCTION_INFO_V1(plvstr_substr3); PG_FUNCTION_INFO_V1(plvstr_instr2); PG_FUNCTION_INFO_V1(plvstr_instr3); PG_FUNCTION_INFO_V1(plvstr_instr4); PG_FUNCTION_INFO_V1(plvstr_betwn_i); PG_FUNCTION_INFO_V1(plvstr_betwn_c); PG_FUNCTION_INFO_V1(plvstr_swap); PG_FUNCTION_INFO_V1(plvchr_nth); PG_FUNCTION_INFO_V1(plvchr_first); PG_FUNCTION_INFO_V1(plvchr_last); PG_FUNCTION_INFO_V1(plvchr_is_kind_i); PG_FUNCTION_INFO_V1(plvchr_is_kind_a); PG_FUNCTION_INFO_V1(plvchr_char_name); PG_FUNCTION_INFO_V1(oracle_substr2); PG_FUNCTION_INFO_V1(oracle_substr3); static text *ora_substr(Datum str, int start, int len); #define ora_substr_text(str, start, len) \ ora_substr(PointerGetDatum((str)), (start), (len)) static const char* char_names[] = { "NULL","SOH","STX","ETX","EOT","ENQ","ACK","DEL", "BS", "HT", "NL", "VT", "NP", "CR", "SO", "SI", "DLE", "DC1","DC2","DC3","DC4","NAK","SYN","ETB", "CAN", "EM","SUB","ESC","FS","GS","RS","US","SP" }; #define NON_EMPTY_CHECK(str) \ if (VARSIZE_ANY_EXHDR(str) == 0) \ ereport(ERROR, \ (errcode(ERRCODE_INVALID_PARAMETER_VALUE), \ errmsg("invalid parameter"), \ errdetail("Not allowed empty string."))); #define PARAMETER_ERROR(detail) \ ereport(ERROR, \ (errcode(ERRCODE_INVALID_PARAMETER_VALUE), \ errmsg("invalid parameter"), \ errdetail(detail))); #ifndef _pg_mblen #define _pg_mblen pg_mblen #endif typedef enum { POSITION, FIRST, LAST } position_mode; /* * Make substring, can handle negative start * */ int ora_mb_strlen(text *str, char **sizes, int **positions) { int r_len; int cur_size = 0; int sz; char *p; int cur = 0; p = VARDATA_ANY(str); r_len = VARSIZE_ANY_EXHDR(str); if (NULL != sizes) *sizes = palloc(r_len * sizeof(char)); if (NULL != positions) *positions = palloc(r_len * sizeof(int)); while (cur < r_len) { sz = _pg_mblen(p); if (sizes) (*sizes)[cur_size] = sz; if (positions) (*positions)[cur_size] = cur; cur += sz; p += sz; cur_size += 1; } return cur_size; } int ora_mb_strlen1(text *str) { int r_len; int c; char *p; r_len = VARSIZE_ANY_EXHDR(str); if (pg_database_encoding_max_length() == 1) return r_len; p = VARDATA_ANY(str); c = 0; while (r_len > 0) { int sz; sz = _pg_mblen(p); p += sz; r_len -= sz; c += 1; } return c; } /* * len < 0 means "length is not specified". */ static text * ora_substr(Datum str, int start, int len) { if (start == 0) start = 1; /* 0 is interpreted as 1 */ else if (start < 0) { text *t; int32 n; t = DatumGetTextPP(str); n = pg_mbstrlen_with_len(VARDATA_ANY(t), VARSIZE_ANY_EXHDR(t)); start = n + start + 1; if (start <= 0) return cstring_to_text(""); str = PointerGetDatum(t); /* save detoasted text */ } if (len < 0) return DatumGetTextP(DirectFunctionCall2(text_substr_no_len, str, Int32GetDatum(start))); else return DatumGetTextP(DirectFunctionCall3(text_substr, str, Int32GetDatum(start), Int32GetDatum(len))); } /* simply search algorhitm - can be better */ static int ora_instr_mb(text *txt, text *pattern, int start, int nth) { int c_len_txt, c_len_pat; int b_len_pat; int *pos_txt; const char *str_txt, *str_pat; int beg, end, i, dx; str_txt = VARDATA_ANY(txt); c_len_txt = ora_mb_strlen(txt, NULL, &pos_txt); str_pat = VARDATA_ANY(pattern); b_len_pat = VARSIZE_ANY_EXHDR(pattern); c_len_pat = pg_mbstrlen_with_len(str_pat, b_len_pat); if (start > 0) { dx = 1; beg = start - 1; end = c_len_txt - c_len_pat + 1; if (beg >= end) return 0; /* out of range */ } else { dx = -1; beg = Min(c_len_txt + start, c_len_txt - c_len_pat); end = -1; if (beg <= end) return 0; /* out of range */ } for (i = beg; i != end; i += dx) { if (memcmp(str_txt + pos_txt[i], str_pat, b_len_pat) == 0) { if (--nth == 0) return i + 1; } } return 0; } int ora_instr(text *txt, text *pattern, int start, int nth) { int len_txt, len_pat; const char *str_txt, *str_pat; int beg, end, i, dx; if (nth <= 0) PARAMETER_ERROR("Four parameter isn't positive."); /* Forward for multibyte strings */ if (pg_database_encoding_max_length() > 1) return ora_instr_mb(txt, pattern, start, nth); str_txt = VARDATA_ANY(txt); len_txt = VARSIZE_ANY_EXHDR(txt); str_pat = VARDATA_ANY(pattern); len_pat = VARSIZE_ANY_EXHDR(pattern); if (start > 0) { dx = 1; beg = start - 1; end = len_txt - len_pat + 1; if (beg >= end) return 0; /* out of range */ } else { dx = -1; beg = Min(len_txt + start, len_txt - len_pat); end = -1; if (beg <= end) return 0; /* out of range */ } for (i = beg; i != end; i += dx) { if (memcmp(str_txt + i, str_pat, len_pat) == 0) { if (--nth == 0) return i + 1; } } return 0; } /**************************************************************** * PLVstr.normalize * * Syntax: * FUNCTION plvstr.normalize (string_in IN VARCHAR) * RETURN VARCHAR; * * Purpouse: * Normalize string - replace white chars by space, replace * spaces by space * ****************************************************************/ Datum plvstr_normalize(PG_FUNCTION_ARGS) { text *str = PG_GETARG_TEXT_PP(0); text *result; char *aux, *aux_cur; int i; #if defined(_MSC_VER) && (defined(_M_X64) || defined(__amd64__)) __int64 l; #else int l; #endif char c, *cur; bool write_spc = false; bool ignore_stsp = true; bool mb_encode; int sz; mb_encode = pg_database_encoding_max_length() > 1; l = VARSIZE_ANY_EXHDR(str); aux_cur = aux = palloc(l); write_spc = false; cur = VARDATA_ANY(str); for (i = 0; i < l; i++) { switch ((c = *cur)) { case '\t': case '\n': case '\r': case ' ': write_spc = ignore_stsp ? false : true; break; default: /* ignore all other unvisible chars */ if (mb_encode) { sz = _pg_mblen(cur); if (sz > 1 || (sz == 1 && c > 32)) { int j; if (write_spc) { *aux_cur++ = ' '; write_spc = false; } for (j = 0; j < sz; j++) { *aux_cur++ = *cur++; } ignore_stsp = false; i += sz - 1; } continue; } else if (c > 32) { if (write_spc) { *aux_cur++ = ' '; write_spc = false; } *aux_cur++ = c; ignore_stsp = false; continue; } } cur += 1; } l = aux_cur - aux; result = palloc(l+VARHDRSZ); SET_VARSIZE(result, l + VARHDRSZ); memcpy(VARDATA(result), aux, l); PG_RETURN_TEXT_P(result); } /**************************************************************** * PLVstr.instr * * Syntax: * FUNCTION plvstr.instr (string_in VARCHAR, pattern VARCHAR) * FUNCTION plvstr.instr (string_in VARCHAR, pattern VARCHAR, * start_in INTEGER) * FUNCTION plvstr.instr (string_in VARCHAR, pattern VARCHAR, * start_in INTEGER, nth INTEGER) * RETURN INT; * * Purpouse: * Search pattern in string. * ****************************************************************/ Datum plvstr_instr2 (PG_FUNCTION_ARGS) { text *arg1 = PG_GETARG_TEXT_PP(0); text *arg2 = PG_GETARG_TEXT_PP(1); PG_RETURN_INT32(ora_instr(arg1, arg2, 1, 1)); } Datum plvstr_instr3 (PG_FUNCTION_ARGS) { text *arg1 = PG_GETARG_TEXT_PP(0); text *arg2 = PG_GETARG_TEXT_PP(1); int arg3 = PG_GETARG_INT32(2); PG_RETURN_INT32(ora_instr(arg1, arg2, arg3, 1)); } Datum plvstr_instr4 (PG_FUNCTION_ARGS) { text *arg1 = PG_GETARG_TEXT_PP(0); text *arg2 = PG_GETARG_TEXT_PP(1); int arg3 = PG_GETARG_INT32(2); int arg4 = PG_GETARG_INT32(3); PG_RETURN_INT32(ora_instr(arg1, arg2, arg3, arg4)); } /**************************************************************** * PLVstr.is_prefix * * Syntax: * FUNCTION plvstr.is_prefix (string_in IN VARCHAR, * prefix_in VARCHAR, * case_sensitive BOOL := true) * RETURN bool; * FUNCTION plvstr.is_prefix (num_in IN NUMERIC, * prefix_in NUMERIC) RETURN bool; * FUNCTION plvstr.is_prefix (int_in IN INT, * prefix_in INT) RETURN bool; * * Purpouse: * Returns true, if prefix_in is prefix of string_in * ****************************************************************/ Datum plvstr_is_prefix_text (PG_FUNCTION_ARGS) { text *str = PG_GETARG_TEXT_PP(0); text *prefix = PG_GETARG_TEXT_PP(1); bool case_sens = PG_GETARG_BOOL(2); bool mb_encode; int str_len = VARSIZE_ANY_EXHDR(str); int pref_len = VARSIZE_ANY_EXHDR(prefix); int i; char *ap, *bp; mb_encode = pg_database_encoding_max_length() > 1; if (mb_encode && !case_sens) { str = (text*)DatumGetPointer(DirectFunctionCall1(lower, PointerGetDatum(str))); prefix = (text*)DatumGetPointer(DirectFunctionCall1(lower, PointerGetDatum(prefix))); } ap = VARDATA_ANY(str); bp = VARDATA_ANY(prefix); for (i = 0; i < pref_len; i++) { if (i >= str_len) break; if (case_sens || mb_encode) { if (*ap++ != *bp++) break; } else if (!mb_encode) { if (pg_toupper((unsigned char) *ap++) != pg_toupper((unsigned char) *bp++)) break; } } PG_RETURN_BOOL(i == pref_len); } Datum plvstr_is_prefix_int (PG_FUNCTION_ARGS) { int n = PG_GETARG_INT32(0); int prefix = PG_GETARG_INT32(1); bool result = false; do { if (n == prefix) { result = true; break; } n = n / 10; } while (n >= prefix); PG_RETURN_BOOL(result); } Datum plvstr_is_prefix_int64 (PG_FUNCTION_ARGS) { int64 n = PG_GETARG_INT64(0); int64 prefix = PG_GETARG_INT64(1); bool result = false; do { if (n == prefix) { result = true; break; } n = n / 10; } while (n >= prefix); PG_RETURN_BOOL(result); } /**************************************************************** * PLVstr.rvrs * * Syntax: * FUNCTION plvstr.rvrs (string_in IN VARCHAR, * start_in IN INTEGER := 1, * end_in IN INTEGER := NULL) * RETURN VARCHAR2; * * Purpouse: * Reverse string or part of string * ****************************************************************/ Datum plvstr_rvrs(PG_FUNCTION_ARGS) { text *str; int start; int end; int len; int i; int new_len; text *result; char *data; char *sizes = NULL; int *positions = NULL; bool mb_encode; if (PG_ARGISNULL(0)) PG_RETURN_NULL(); str = PG_GETARG_TEXT_PP(0); mb_encode = pg_database_encoding_max_length() > 1; if (!mb_encode) len = VARSIZE_ANY_EXHDR(str); else len = ora_mb_strlen(str, &sizes, &positions); start = PG_ARGISNULL(1) ? 1 : PG_GETARG_INT32(1); end = PG_ARGISNULL(2) ? (start < 0 ? -len : len) : PG_GETARG_INT32(2); if ((start > end && start > 0) || (start < end && start < 0)) PARAMETER_ERROR("Second parameter is bigger than third."); if (start < 0) { int new_start, new_end; new_start = len + start + 1; new_end = len + end + 1; start = new_end; end = new_start; } start = start != 0 ? start : 1; end = end < len ? end : len; new_len = end - start + 1; new_len = new_len >= 0 ? new_len : 0; if (mb_encode) { int max_size; int cur_size; char *p; int j; int fz_size; fz_size = VARSIZE_ANY_EXHDR(str); if ((max_size = (new_len*pg_database_encoding_max_length())) > fz_size) result = palloc(fz_size + VARHDRSZ); else result = palloc(max_size + VARHDRSZ); data = (char*) VARDATA(result); cur_size = 0; p = VARDATA_ANY(str); for (i = end - 1; i>= start - 1; i--) { for (j=0; j= start - 1; i--) *data++ = p[i]; } PG_RETURN_TEXT_P(result); } /**************************************************************** * PLVstr.lpart * * Syntax: * FUNCTION PLVstr.lpart (string_in IN VARCHAR, * divider_in IN VARCHAR, * start_in IN INTEGER := 1, * nth_in IN INTEGER := 1, * all_if_notfound_in IN BOOLEAN := FALSE) * RETURN VARCHAR2; * * Purpouse: * Call this function to return the left part of a string. * ****************************************************************/ Datum plvstr_lpart (PG_FUNCTION_ARGS) { text *str = PG_GETARG_TEXT_P(0); text *div = PG_GETARG_TEXT_P(1); int start = PG_GETARG_INT32(2); int nth = PG_GETARG_INT32(3); bool all_if_notfound = PG_GETARG_BOOL(4); int loc; loc = ora_instr(str, div, start, nth); if (loc == 0) { if (all_if_notfound) PG_RETURN_TEXT_P(TextPCopy(str)); else PG_RETURN_NULL(); } else PG_RETURN_TEXT_P(ora_substr_text(str, 1, loc-1)); } /**************************************************************** * PLVstr.rpart * * Syntax: * FUNCTION PLVstr.rpart (string_in IN VARCHAR, * divider_in IN VARCHAR, * start_in IN INTEGER := 1, * nth_in IN INTEGER := 1, * all_if_notfound_in IN BOOLEAN := FALSE) * RETURN VARCHAR2; * * Purpouse: * Call this function to return the right part of a string. * ****************************************************************/ Datum plvstr_rpart (PG_FUNCTION_ARGS) { text *str = PG_GETARG_TEXT_P(0); text *div = PG_GETARG_TEXT_P(1); int start = PG_GETARG_INT32(2); int nth = PG_GETARG_INT32(3); bool all_if_notfound = PG_GETARG_BOOL(4); int loc; loc = ora_instr(str, div, start, nth); if (loc == 0) { if (all_if_notfound) PG_RETURN_TEXT_P(TextPCopy(str)); else PG_RETURN_NULL(); } else PG_RETURN_TEXT_P(ora_substr_text(str, loc+1, -1)); } /**************************************************************** * PLVstr.lstrip * * Syntax: * FUNCTION plvstr.lstrip (string_in IN VARCHAR, * substring_in IN VARCHAR, * num_in IN INTEGER := 1) * RETURN VARCHAR; * * Purpouse: * Call this function to remove characters from the beginning * (left) of a string. * ****************************************************************/ Datum plvstr_lstrip (PG_FUNCTION_ARGS) { text *str = PG_GETARG_TEXT_PP(0); text *pat = PG_GETARG_TEXT_PP(1); int num = PG_GETARG_INT32(2); int count = 0; int len_p, len_s, i; char *str_p, *aux_str_p, *pat_p; len_p = VARSIZE_ANY_EXHDR(pat); len_s = VARSIZE_ANY_EXHDR(str); str_p = VARDATA_ANY(str); while (count < num) { pat_p = VARDATA_ANY(pat); aux_str_p = str_p; if (len_s < len_p) break; for (i = 0; i < len_p; i++) if (*aux_str_p++ != *pat_p++) break; if (i >= len_p) { count++; /* found */ str_p = aux_str_p; len_s -= len_p; continue; } break; } PG_RETURN_TEXT_P(cstring_to_text_with_len(str_p,len_s)); } /**************************************************************** * PLVstr.rstrip * * Syntax: * FUNCTION plvstr.rstrip (string_in IN VARCHAR, * substring_in IN VARCHAR, * num_in IN INTEGER := 1) * RETURN VARCHAR; * * Purpouse: * Call this function to remove characters from the end * (right) of a string. * ****************************************************************/ Datum plvstr_rstrip (PG_FUNCTION_ARGS) { text *str = PG_GETARG_TEXT_PP(0); text *pat = PG_GETARG_TEXT_PP(1); int num = PG_GETARG_INT32(2); int count = 0; int len_p, len_s, i; char *str_p, *aux_str_p, *pat_p; len_p = VARSIZE_ANY_EXHDR(pat); len_s = VARSIZE_ANY_EXHDR(str); str_p = VARDATA_ANY(str) + len_s - 1; while (count < num) { pat_p = VARDATA_ANY(pat) + len_p - 1; aux_str_p = str_p; if (len_s < len_p) break; for (i = 0; i < len_p; i++) if (*aux_str_p-- != *pat_p--) break; if (i >= len_p) { count++; /* found */ str_p = aux_str_p; len_s -= len_p; continue; } break; } PG_RETURN_TEXT_P(cstring_to_text_with_len(VARDATA_ANY(str),len_s)); } /**************************************************************** * PLVstr.left * * Syntax: * FUNCTION plvstr.left (string_in IN VARCHAR, * num_in INTEGER) * RETURN VARCHAR; * * Purpouse: * Returns firs num_in charaters. You can use negative num_in * left('abcde', -2) -> abc * ****************************************************************/ Datum plvstr_left (PG_FUNCTION_ARGS) { text *str = PG_GETARG_TEXT_P(0); int n = PG_GETARG_INT32(1); if (n < 0) n = ora_mb_strlen1(str) + n; n = n < 0 ? 0 : n; PG_RETURN_TEXT_P(ora_substr_text(str, 1, n)); } /**************************************************************** * PLVstr.right * * Syntax: * FUNCTION plvstr.right (string_in IN VARCHAR, * num_in INTEGER) * RETURN VARCHAR; * * Purpouse: * Returns last (right) num_in characters. * ****************************************************************/ Datum plvstr_right (PG_FUNCTION_ARGS) { text *str = PG_GETARG_TEXT_P(0); int n = PG_GETARG_INT32(1); if (n < 0) n = ora_mb_strlen1(str) + n; n = (n < 0) ? 0 : n; PG_RETURN_TEXT_P(ora_substr_text(str, -n, -1)); } /**************************************************************** * PLVstr.substr2 * * Syntax: * FUNCTION plvstr.substr (string_in IN VARCHAR, * start INTEGER) * RETURN VARCHAR; * * Purpouse: * Returns substring started on start_in to end * ****************************************************************/ Datum plvstr_substr2 (PG_FUNCTION_ARGS) { return oracle_substr2(fcinfo); } /**************************************************************** * PLVstr.substr3 * * Syntax: * FUNCTION plvstr.substr (string_in IN VARCHAR, * start INTEGER, len INTEGER) * RETURN VARCHAR; * * Purpouse: * Returns len chars from start_in position * ****************************************************************/ Datum plvstr_substr3 (PG_FUNCTION_ARGS) { return oracle_substr3(fcinfo); } /**************************************************************** * PLVchr.nth * * Syntax: * FUNCTION plvchr.nth (string_in IN VARCHAR, * nth_in IN INTEGER) * RETURN VARCHAR; * * Purpouse: * Call this function to return the Nth character in a string. * ****************************************************************/ Datum plvchr_nth (PG_FUNCTION_ARGS) { PG_RETURN_TEXT_P(ora_substr(PG_GETARG_DATUM(0), PG_GETARG_INT32(1), 1)); } /**************************************************************** * PLVchr.first * * Syntax: * FUNCTION plvchr.first (string_in IN VARCHAR, * RETURN VARCHAR; * * Purpouse: * Call this function to return the first character in a string. * ****************************************************************/ Datum plvchr_first (PG_FUNCTION_ARGS) { PG_RETURN_TEXT_P(ora_substr(PG_GETARG_DATUM(0), 1, 1)); } /**************************************************************** * PLVchr.last * * Syntax: * FUNCTION plvchr.last (string_in IN VARCHAR, * RETURN VARCHAR; * * Purpouse: * Call this function to return the last character in a string. * ****************************************************************/ Datum plvchr_last (PG_FUNCTION_ARGS) { PG_RETURN_TEXT_P(ora_substr(PG_GETARG_DATUM(0), -1, 1)); } /**************************************************************** * PLVchr.is_blank, plvchr.is_digit, ... * * Syntax: * FUNCTION plvchr.is_kind (string_in IN VARCHAR, * kind INT) * RETURN VARCHAR; * * Purpouse: * Call this function to see if a character is blank, ... * 1 blank, 2 digit, 3 quote, 4 other, 5 letter * ****************************************************************/ static bool is_kind(char c, int kind) { switch (kind) { case 1: return c == ' '; case 2: return '0' <= c && c <= '9'; case 3: return c == '\''; case 4: return (32 <= c && c <= 47) || (58 <= c && c <= 64) || (91 <= c && c <= 96) || (123 <= c && c <= 126); case 5: return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z'); default: PARAMETER_ERROR("Second parametr isn't in enum {1,2,3,4,5}"); return false; } } Datum plvchr_is_kind_i (PG_FUNCTION_ARGS) { int32 c = PG_GETARG_INT32(0); int32 k = PG_GETARG_INT32(1); PG_RETURN_INT32(is_kind((char)c,k)); } Datum plvchr_is_kind_a (PG_FUNCTION_ARGS) { text *str = PG_GETARG_TEXT_PP(0); int32 k = PG_GETARG_INT32(1); char c; NON_EMPTY_CHECK(str); if (pg_database_encoding_max_length() > 1) { if (_pg_mblen(VARDATA_ANY(str)) > 1) PG_RETURN_INT32( (k == 5) ); } c = *VARDATA_ANY(str); PG_RETURN_INT32(is_kind(c,k)); } /**************************************************************** * PLVchr.char_name * * Syntax: * FUNCTION plvchr.char_name (letter_in IN VARCHAR) * RETURN VARCHAR; * * Purpouse: * Returns the name of the character to ascii code as a VARCHAR. * ****************************************************************/ Datum plvchr_char_name(PG_FUNCTION_ARGS) { text *str = PG_GETARG_TEXT_PP(0); text *result; unsigned char c; NON_EMPTY_CHECK(str); c = (unsigned char)*(VARDATA_ANY(str)); if (c >= lengthof(char_names)) result = ora_substr_text(str, 1, 1); else result = cstring_to_text(char_names[c]); PG_RETURN_TEXT_P(result); } /**************************************************************** * substr * * Syntax: * FUNCTION substr (string, start_position, [length]) * RETURN VARCHAR; * * Purpouse: * Returns len chars from start_in position, compatible with Oracle * ****************************************************************/ Datum oracle_substr3(PG_FUNCTION_ARGS) { int32 len = PG_GETARG_INT32(2); if (len < 0) PG_RETURN_NULL(); PG_RETURN_TEXT_P(ora_substr(PG_GETARG_DATUM(0), PG_GETARG_INT32(1), len)); } Datum oracle_substr2(PG_FUNCTION_ARGS) { PG_RETURN_TEXT_P(ora_substr(PG_GETARG_DATUM(0), PG_GETARG_INT32(1), -1)); } static text* ora_concat2(text *str1, text *str2) { int l1; int l2; text *result; l1 = VARSIZE_ANY_EXHDR(str1); l2 = VARSIZE_ANY_EXHDR(str2); result = palloc(l1+l2+VARHDRSZ); memcpy(VARDATA(result), VARDATA_ANY(str1), l1); memcpy(VARDATA(result) + l1, VARDATA_ANY(str2), l2); SET_VARSIZE(result, l1 + l2 + VARHDRSZ); return result; } static text* ora_concat3(text *str1, text *str2, text *str3) { int l1; int l2; int l3; text *result; l1 = VARSIZE_ANY_EXHDR(str1); l2 = VARSIZE_ANY_EXHDR(str2); l3 = VARSIZE_ANY_EXHDR(str3); result = palloc(l1+l2+l3+VARHDRSZ); memcpy(VARDATA(result), VARDATA_ANY(str1), l1); memcpy(VARDATA(result) + l1, VARDATA_ANY(str2), l2); memcpy(VARDATA(result) + l1+l2, VARDATA_ANY(str3), l3); SET_VARSIZE(result, l1 + l2 + l3 + VARHDRSZ); return result; } /**************************************************************** * PLVchr.swap * * Syntax: * FUNCTION swap * (string_in IN VARCHAR2, * replace_in IN VARCHAR2, * start_in IN INTEGER := 1, * oldlen_in IN INTEGER := NULL) * RETURN VARCHAR2 * * Purpouse: * Replace a substring in a string with a specified string. * ****************************************************************/ Datum plvstr_swap(PG_FUNCTION_ARGS) { text *string_in; text *replace_in; int start_in = 1; int oldlen_in; int v_len; if (PG_ARGISNULL(0)) PG_RETURN_NULL(); else string_in = PG_GETARG_TEXT_P(0); if (PG_ARGISNULL(1)) PG_RETURN_NULL(); else replace_in = PG_GETARG_TEXT_P(1); if (!PG_ARGISNULL(2)) start_in = PG_GETARG_INT32(2); if (PG_ARGISNULL(3)) oldlen_in = ora_mb_strlen1(replace_in); else oldlen_in = PG_GETARG_INT32(3); v_len = ora_mb_strlen1(string_in); start_in = start_in > 0 ? start_in : v_len + start_in + 1; if (start_in == 0 || start_in > v_len) PG_RETURN_TEXT_P(TextPCopy(string_in)); else if (start_in == 1) PG_RETURN_TEXT_P(ora_concat2( replace_in, ora_substr_text(string_in, oldlen_in+1, -1))); else PG_RETURN_TEXT_P(ora_concat3( ora_substr_text(string_in, 1, start_in - 1), replace_in, ora_substr_text(string_in, start_in + oldlen_in, -1))); } /**************************************************************** * PLVchr.betwn * * Find the Substring Between Start and End Locations * * Syntax: * FUNCTION plvstr.betwn (string_in IN VARCHAR2, * start_in IN INTEGER, * end_in IN INTEGER, * inclusive IN BOOLEAN := TRUE) * RETURN VARCHAR2; * * FUNCTION plvstr.betwn (string_in IN VARCHAR2, * start_in IN VARCHAR2, * end_in IN VARCHAR2 := NULL, * startnth_in IN INTEGER := 1, * endnth_in IN INTEGER := 1, * inclusive IN BOOLEAN := TRUE, * gotoend IN BOOLEAN := FALSE) * RETURN VARCHAR2; * * Purpouse: * Call this function to extract a sub-string from a string. This * function is overloaded. You can either provide the start and end * locations or you can provide start and end substrings. * ****************************************************************/ Datum plvstr_betwn_i(PG_FUNCTION_ARGS) { text *string_in = PG_GETARG_TEXT_P(0); int start_in = PG_GETARG_INT32(1); int end_in = PG_GETARG_INT32(2); bool inclusive = PG_GETARG_BOOL(3); if ((start_in < 0 && end_in > 0) || (start_in > 0 && end_in < 0) || (start_in > end_in)) PARAMETER_ERROR("Wrong positions."); if (start_in < 0) { int v_len = ora_mb_strlen1(string_in); start_in = v_len + start_in + 1; end_in = v_len + start_in + 1; } if (!inclusive) { start_in += 1; end_in -= 1; if (start_in > end_in) PG_RETURN_TEXT_P(cstring_to_text("")); } PG_RETURN_TEXT_P(ora_substr_text(string_in, start_in, end_in - start_in + 1)); } Datum plvstr_betwn_c(PG_FUNCTION_ARGS) { text *string_in; text *start_in; text *end_in; int startnth_in; int endnth_in; bool inclusive; bool gotoend; int v_start; int v_end; if (PG_ARGISNULL(0) || PG_ARGISNULL(1) || PG_ARGISNULL(3) || PG_ARGISNULL(4) || PG_ARGISNULL(5) || PG_ARGISNULL(6)) PG_RETURN_NULL(); string_in = PG_GETARG_TEXT_P(0); start_in = PG_GETARG_TEXT_P(1); end_in = PG_ARGISNULL(2) ? start_in : PG_GETARG_TEXT_P(2); startnth_in = PG_GETARG_INT32(3); endnth_in = PG_GETARG_INT32(4); inclusive = PG_GETARG_BOOL(5); gotoend = PG_GETARG_BOOL(6); if (startnth_in == 0) { v_start = 1; v_end = ora_instr(string_in, end_in, 1, endnth_in); } else { v_start = ora_instr(string_in, start_in, 1, startnth_in); v_end = ora_instr(string_in, end_in, v_start + 1, endnth_in); } if (v_start == 0) PG_RETURN_NULL(); if (!inclusive) { if (startnth_in > 0) v_start += ora_mb_strlen1(start_in); v_end -= 1; } else v_end += (ora_mb_strlen1(end_in) - 1); if (((v_start > v_end) && (v_end > 0)) || (v_end <= 0 && !gotoend)) PG_RETURN_NULL(); if (v_end <= 0) v_end = ora_mb_strlen1(string_in); PG_RETURN_TEXT_P(ora_substr_text(string_in, v_start, v_end - v_start + 1)); } orafce-VERSION_3_9_0/plvsubst.c000066400000000000000000000133231362147214200163630ustar00rootroot00000000000000/* This code implements one part of functonality of free available library PL/Vision. Please look www.quest.com Original author: Steven Feuerstein, 1996 - 2002 PostgreSQL implementation author: Pavel Stehule, 2006-2018 This module is under BSD Licence History: 1.0. first public version 22. September 2006 */ #include "postgres.h" #include "utils/builtins.h" #include "utils/numeric.h" #include "string.h" #include "stdlib.h" #include "utils/pg_locale.h" #include "mb/pg_wchar.h" #include "lib/stringinfo.h" #include "catalog/pg_type.h" #include "libpq/pqformat.h" #include "utils/array.h" #include "utils/memutils.h" #include "utils/lsyscache.h" #include "access/tupmacs.h" #include "orafce.h" #include "builtins.h" PG_FUNCTION_INFO_V1(plvsubst_string_array); PG_FUNCTION_INFO_V1(plvsubst_string_string); PG_FUNCTION_INFO_V1(plvsubst_setsubst); PG_FUNCTION_INFO_V1(plvsubst_setsubst_default); PG_FUNCTION_INFO_V1(plvsubst_subst); #define C_SUBST "%s" text *c_subst = NULL; static void init_c_subst() { if (!c_subst) { MemoryContext oldctx; oldctx = MemoryContextSwitchTo(TopMemoryContext); c_subst = cstring_to_text(C_SUBST); MemoryContextSwitchTo(oldctx); } } static void set_c_subst(text *sc) { MemoryContext oldctx; if (c_subst) pfree(c_subst); oldctx = MemoryContextSwitchTo(TopMemoryContext); c_subst = sc ? TextPCopy(sc) : cstring_to_text(C_SUBST); MemoryContextSwitchTo(oldctx); } static text* plvsubst_string(text *template_in, ArrayType *vals_in, text *c_subst, FunctionCallInfo fcinfo) { ArrayType *v = vals_in; int nitems, *dims, ndims; char *p; int16 typlen; bool typbyval; char typalign; char typdelim; Oid typelem; Oid typiofunc; FmgrInfo proc; int i = 0, items = 0; StringInfo sinfo; const char *template_str; int template_len; char *sizes; int *positions; int subst_mb_len; int subst_len; const bits8 *bitmap; int bitmask; if (v != NULL && (ndims = ARR_NDIM(v)) > 0) { if (ndims != 1) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid parameter"), errdetail("Array of arguments has wrong dimension: %d", ndims))); p = ARR_DATA_PTR(v); dims = ARR_DIMS(v); nitems = ArrayGetNItems(ndims, dims); bitmap = ARR_NULLBITMAP(v); get_type_io_data(ARR_ELEMTYPE(v), IOFunc_output, &typlen, &typbyval, &typalign, &typdelim, &typelem, &typiofunc); fmgr_info_cxt(typiofunc, &proc, fcinfo->flinfo->fn_mcxt); } else { nitems = 0; p = NULL; bitmap = NULL; } template_str = VARDATA(template_in); template_len = ora_mb_strlen(template_in, &sizes, &positions); subst_mb_len = ora_mb_strlen1(c_subst); subst_len = VARSIZE_ANY_EXHDR(c_subst); sinfo = makeStringInfo(); bitmask = 1; for (i = 0; i < template_len; i++) { if (strncmp(&template_str[positions[i]], VARDATA(c_subst), subst_len) == 0) { Datum itemvalue; char *value; if (items++ < nitems) { if (bitmap && (*bitmap & bitmask) == 0) value = pstrdup("NULL"); else { itemvalue = fetch_att(p, typbyval, typlen); value = DatumGetCString(FunctionCall3(&proc, itemvalue, ObjectIdGetDatum(typelem), Int32GetDatum(-1))); p = att_addlength_pointer(p, typlen, p); p = (char *) att_align_nominal(p, typalign); } appendStringInfoString(sinfo, value); pfree(value); if (bitmap) { bitmask <<= 1; if (bitmask == 0x100) { bitmap++; bitmask = 1; } } } else ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("too few parameters specified for template string"))); i += subst_mb_len - 1; } else appendBinaryStringInfo(sinfo, &template_str[positions[i]], sizes[i]); } return cstring_to_text(sinfo->data); } Datum plvsubst_string_array(PG_FUNCTION_ARGS) { init_c_subst(); if (PG_ARGISNULL(0) || PG_ARGISNULL(1)) PG_RETURN_NULL(); PG_RETURN_TEXT_P(plvsubst_string(PG_GETARG_TEXT_P(0), PG_GETARG_ARRAYTYPE_P(1), PG_ARGISNULL(2) ? c_subst : PG_GETARG_TEXT_P(2), fcinfo)); } Datum plvsubst_string_string(PG_FUNCTION_ARGS) { Datum r; ArrayType *array; #if PG_VERSION_NUM >= 120000 LOCAL_FCINFO(locfcinfo, 2); #else FunctionCallInfoData locfcinfo_data; FunctionCallInfo locfcinfo = &locfcinfo_data; #endif Oid collation = PG_GET_COLLATION(); init_c_subst(); if (PG_ARGISNULL(0) || PG_ARGISNULL(1)) PG_RETURN_NULL(); /* * I can't use DirectFunctionCall2 */ InitFunctionCallInfoData(*locfcinfo, fcinfo->flinfo, 2, collation, NULL, NULL); #if PG_VERSION_NUM >= 120000 locfcinfo->args[0].value = PG_GETARG_DATUM(1); locfcinfo->args[1].value = PG_GETARG_IF_EXISTS(2, DATUM, CStringGetTextDatum(",")); locfcinfo->args[0].isnull = false; locfcinfo->args[1].isnull = false; #else locfcinfo->arg[0] = PG_GETARG_DATUM(1); locfcinfo->arg[1] = PG_GETARG_IF_EXISTS(2, DATUM, CStringGetTextDatum(",")); locfcinfo->argnull[0] = false; locfcinfo->argnull[1] = false; #endif r = text_to_array(locfcinfo); if (locfcinfo->isnull || r == (Datum) 0) array = NULL; else array = DatumGetArrayTypeP(r); PG_RETURN_TEXT_P(plvsubst_string(PG_GETARG_TEXT_P(0), array, PG_GETARG_IF_EXISTS(3, TEXT_P, c_subst), fcinfo)); } Datum plvsubst_setsubst(PG_FUNCTION_ARGS) { if (PG_ARGISNULL(0)) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("substition is NULL"), errdetail("Substitution keyword may not be NULL."))); set_c_subst(PG_GETARG_TEXT_P(0)); PG_RETURN_VOID(); } Datum plvsubst_setsubst_default(PG_FUNCTION_ARGS) { set_c_subst(NULL); PG_RETURN_VOID(); } Datum plvsubst_subst(PG_FUNCTION_ARGS) { init_c_subst(); PG_RETURN_TEXT_P(TextPCopy(c_subst)); } orafce-VERSION_3_9_0/putline.c000066400000000000000000000157451362147214200161730ustar00rootroot00000000000000#include "postgres.h" #include "funcapi.h" #include "access/heapam.h" #include "access/htup_details.h" #include "catalog/pg_type.h" #include "lib/stringinfo.h" #undef USE_SSL #undef ENABLE_GSS #include "libpq/libpq.h" #include "libpq/pqformat.h" #include "utils/memutils.h" #include "utils/array.h" #include "utils/builtins.h" #include "utils/lsyscache.h" #include "orafce.h" #include "builtins.h" #if defined(WIN32) && !defined(_MSC_VER) extern PGDLLIMPORT ProtocolVersion FrontendProtocol; /* for mingw */ #endif /* * TODO: BUFSIZE_UNLIMITED to be truely unlimited (or INT_MAX), * and allocate buffers on-demand. */ #define BUFSIZE_DEFAULT 20000 #define BUFSIZE_MIN 2000 #define BUFSIZE_MAX 1000000 #define BUFSIZE_UNLIMITED BUFSIZE_MAX static bool is_server_output = false; static char *buffer = NULL; static int buffer_size = 0; /* allocated bytes in buffer */ static int buffer_len = 0; /* used bytes in buffer */ static int buffer_get = 0; /* retrieved bytes in buffer */ static void add_str(const char *str, int len); static void add_text(text *str); static void add_newline(void); static void send_buffer(void); /* * Aux. buffer functionality */ static void add_str(const char *str, int len) { /* Discard all buffers if get_line was called. */ if (buffer_get > 0) { buffer_get = 0; buffer_len = 0; } if (buffer_len + len > buffer_size) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_RESOURCES), errmsg("buffer overflow"), errdetail("Buffer overflow, limit of %d bytes", buffer_size), errhint("Increase buffer size in dbms_output.enable() next time"))); memcpy(buffer + buffer_len, str, len); buffer_len += len; buffer[buffer_len] = '\0'; } static void add_text(text *str) { add_str(VARDATA_ANY(str), VARSIZE_ANY_EXHDR(str)); } static void add_newline(void) { add_str("", 1); /* add \0 */ if (is_server_output) send_buffer(); } static void send_buffer() { if (buffer_len > 0) { StringInfoData msgbuf; char *cursor = buffer; while (--buffer_len > 0) { if (*cursor == '\0') *cursor = '\n'; cursor++; } if (*cursor != '\0') ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), errmsg("internal error"), errdetail("Wrong message format detected"))); pq_beginmessage(&msgbuf, 'N'); /* * FrontendProtocol is not avalilable in MSVC because it is not * PGDLLEXPORT'ed. So, we assume always the protocol >= 3. */ #ifndef _MSC_VER if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3) { #endif pq_sendbyte(&msgbuf, PG_DIAG_MESSAGE_PRIMARY); pq_sendstring(&msgbuf, buffer); pq_sendbyte(&msgbuf, '\0'); #ifndef _MSC_VER } else { *cursor++ = '\n'; *cursor = '\0'; pq_sendstring(&msgbuf, buffer); } #endif pq_endmessage(&msgbuf); pq_flush(); } } /* * Aux db functions * */ static void dbms_output_enable_internal(int32 n_buf_size) { /* We allocate +2 bytes for an end-of-line and a string terminator. */ if (buffer == NULL) { buffer = MemoryContextAlloc(TopMemoryContext, n_buf_size + 2); buffer_size = n_buf_size; buffer_len = 0; buffer_get = 0; } else if (n_buf_size > buffer_len) { /* We cannot shrink buffer less than current length. */ buffer = repalloc(buffer, n_buf_size + 2); buffer_size = n_buf_size; } } PG_FUNCTION_INFO_V1(dbms_output_enable_default); Datum dbms_output_enable_default(PG_FUNCTION_ARGS) { dbms_output_enable_internal(BUFSIZE_DEFAULT); PG_RETURN_VOID(); } PG_FUNCTION_INFO_V1(dbms_output_enable); Datum dbms_output_enable(PG_FUNCTION_ARGS) { int32 n_buf_size; if (PG_ARGISNULL(0)) n_buf_size = BUFSIZE_UNLIMITED; else { n_buf_size = PG_GETARG_INT32(0); if (n_buf_size > BUFSIZE_MAX) { n_buf_size = BUFSIZE_MAX; elog(WARNING, "Limit decreased to %d bytes.", BUFSIZE_MAX); } else if (n_buf_size < BUFSIZE_MIN) { n_buf_size = BUFSIZE_MIN; elog(WARNING, "Limit increased to %d bytes.", BUFSIZE_MIN); } } dbms_output_enable_internal(n_buf_size); PG_RETURN_VOID(); } PG_FUNCTION_INFO_V1(dbms_output_disable); Datum dbms_output_disable(PG_FUNCTION_ARGS) { if (buffer) pfree(buffer); buffer = NULL; buffer_size = 0; buffer_len = 0; buffer_get = 0; PG_RETURN_VOID(); } PG_FUNCTION_INFO_V1(dbms_output_serveroutput); Datum dbms_output_serveroutput(PG_FUNCTION_ARGS) { is_server_output = PG_GETARG_BOOL(0); if (is_server_output && !buffer) dbms_output_enable_internal(BUFSIZE_DEFAULT); PG_RETURN_VOID(); } /* * main functions */ PG_FUNCTION_INFO_V1(dbms_output_put); Datum dbms_output_put(PG_FUNCTION_ARGS) { if (buffer) add_text(PG_GETARG_TEXT_PP(0)); PG_RETURN_VOID(); } PG_FUNCTION_INFO_V1(dbms_output_put_line); Datum dbms_output_put_line(PG_FUNCTION_ARGS) { if (buffer) { add_text(PG_GETARG_TEXT_PP(0)); add_newline(); } PG_RETURN_VOID(); } PG_FUNCTION_INFO_V1(dbms_output_new_line); Datum dbms_output_new_line(PG_FUNCTION_ARGS) { if (buffer) add_newline(); PG_RETURN_VOID(); } static text * dbms_output_next(void) { if (buffer_get < buffer_len) { text *line = cstring_to_text(buffer + buffer_get); buffer_get += VARSIZE_ANY_EXHDR(line) + 1; return line; } else return NULL; } PG_FUNCTION_INFO_V1(dbms_output_get_line); Datum dbms_output_get_line(PG_FUNCTION_ARGS) { TupleDesc tupdesc; Datum result; HeapTuple tuple; Datum values[2]; bool nulls[2] = { false, false }; text *line; /* Build a tuple descriptor for our result type */ if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) elog(ERROR, "return type must be a row type"); if ((line = dbms_output_next()) != NULL) { values[0] = PointerGetDatum(line); values[1] = Int32GetDatum(0); /* 0: succeeded */ } else { nulls[0] = true; values[1] = Int32GetDatum(1); /* 1: failed */ } tuple = heap_form_tuple(tupdesc, values, nulls); result = HeapTupleGetDatum(tuple); PG_RETURN_DATUM(result); } PG_FUNCTION_INFO_V1(dbms_output_get_lines); Datum dbms_output_get_lines(PG_FUNCTION_ARGS) { TupleDesc tupdesc; Datum result; HeapTuple tuple; Datum values[2]; bool nulls[2] = { false, false }; text *line; int32 max_lines = PG_GETARG_INT32(0); int32 n; ArrayBuildState *astate = NULL; /* Build a tuple descriptor for our result type */ if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) elog(ERROR, "return type must be a row type"); for (n = 0; n < max_lines && (line = dbms_output_next()) != NULL; n++) { astate = accumArrayResult(astate, PointerGetDatum(line), false, TEXTOID, CurrentMemoryContext); } /* 0: lines as text array */ if (n > 0) values[0] = makeArrayResult(astate, CurrentMemoryContext); else { int16 typlen; bool typbyval; char typalign; ArrayType *arr; get_typlenbyvalalign(TEXTOID, &typlen, &typbyval, &typalign); arr = construct_md_array( NULL, NULL, 0, NULL, NULL, TEXTOID, typlen, typbyval, typalign); values[0] = PointerGetDatum(arr); } /* 1: # of lines as integer */ values[1] = Int32GetDatum(n); tuple = heap_form_tuple(tupdesc, values, nulls); result = HeapTupleGetDatum(tuple); PG_RETURN_DATUM(result); } orafce-VERSION_3_9_0/random.c000066400000000000000000000172551362147214200157710ustar00rootroot00000000000000/* * Note - I don't find any documentation about pseudo random * number generator used in Oracle. So the results of these * functions should be different then native Oracle functions! * This library is based on ANSI C implementation. */ #include "postgres.h" #include "access/hash.h" #include "lib/stringinfo.h" #include "utils/builtins.h" #include "stdlib.h" #include "time.h" #include #include #include "orafce.h" #include "builtins.h" PG_FUNCTION_INFO_V1(dbms_random_initialize); PG_FUNCTION_INFO_V1(dbms_random_normal); PG_FUNCTION_INFO_V1(dbms_random_random); PG_FUNCTION_INFO_V1(dbms_random_seed_int); PG_FUNCTION_INFO_V1(dbms_random_seed_varchar); PG_FUNCTION_INFO_V1(dbms_random_string); PG_FUNCTION_INFO_V1(dbms_random_terminate); PG_FUNCTION_INFO_V1(dbms_random_value); PG_FUNCTION_INFO_V1(dbms_random_value_range); /* Coefficients in rational approximations. */ static const double a[] = { -3.969683028665376e+01, 2.209460984245205e+02, -2.759285104469687e+02, 1.383577518672690e+02, -3.066479806614716e+01, 2.506628277459239e+00 }; static const double b[] = { -5.447609879822406e+01, 1.615858368580409e+02, -1.556989798598866e+02, 6.680131188771972e+01, -1.328068155288572e+01 }; static const double c[] = { -7.784894002430293e-03, -3.223964580411365e-01, -2.400758277161838e+00, -2.549732539343734e+00, 4.374664141464968e+00, 2.938163982698783e+00 }; static const double d[] = { 7.784695709041462e-03, 3.224671290700398e-01, 2.445134137142996e+00, 3.754408661907416e+00 }; #define LOW 0.02425 #define HIGH 0.97575 static double ltqnorm(double p); /* * dbms_random.initialize (seed IN BINARY_INTEGER) * * Initialize package with a seed value */ Datum dbms_random_initialize(PG_FUNCTION_ARGS) { int seed = PG_GETARG_INT32(0); srand(seed); PG_RETURN_VOID(); } /* * dbms_random.normal() RETURN NUMBER; * * Returns random numbers in a standard normal distribution */ Datum dbms_random_normal(PG_FUNCTION_ARGS) { float8 result; /* need random value from (0..1) */ result = ltqnorm(((double) rand() + 1) / ((double) RAND_MAX + 2)); PG_RETURN_FLOAT8(result); } /* * dbms_random.random() RETURN BINARY_INTEGER; * * Generate Random Numeric Values */ Datum dbms_random_random(PG_FUNCTION_ARGS) { int result; /* * Oracle generator generates numebers from -2^31 and +2^31, * ANSI C only from 0 .. RAND_MAX, */ result = 2 * (rand() - RAND_MAX / 2); PG_RETURN_INT32(result); } /* * dbms_random.seed(val IN BINARY_INTEGER); * dbms_random.seed(val IN VARCHAR2); * * Reset the seed value */ Datum dbms_random_seed_int(PG_FUNCTION_ARGS) { int seed = PG_GETARG_INT32(0); srand(seed); PG_RETURN_VOID(); } /* * Atention! * * Hash function should be changed between mayor pg versions, * don't use text based seed for regres tests! */ Datum dbms_random_seed_varchar(PG_FUNCTION_ARGS) { text *key = PG_GETARG_TEXT_P(0); Datum seed; seed = hash_any((unsigned char *) VARDATA_ANY(key), VARSIZE_ANY_EXHDR(key)); srand((int) seed); PG_RETURN_VOID(); } /* * dbms_random.string(opt IN CHAR, len IN NUMBER) RETURN VARCHAR2; * * Create Random Strings * opt seed values: * 'a','A' alpha characters only (mixed case) * 'l','L' lower case alpha characters only * 'p','P' any printable characters * 'u','U' upper case alpha characters only * 'x','X' any alpha-numeric characters (upper) */ static text * random_string(const char *charset, size_t chrset_size, int len) { StringInfo str; int i; str = makeStringInfo(); for (i = 0; i < len; i++) { int pos = (int) ((double) rand() / ((double) RAND_MAX + 1) * chrset_size); appendStringInfoChar(str, charset[pos]); } return cstring_to_text(str->data); } Datum dbms_random_string(PG_FUNCTION_ARGS) { char *option; int len; const char *charset; size_t chrset_size; const char *alpha_mixed = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; const char *lower_only = "abcdefghijklmnopqrstuvwxyz"; const char *upper_only = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; const char *upper_alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; const char *printable = "`1234567890-=qwertyuiop[]asdfghjkl;'zxcvbnm,./!@#$%^&*()_+QWERTYUIOP{}|ASDFGHJKL:\"ZXCVVBNM<>? "; if (PG_ARGISNULL(0) || PG_ARGISNULL(1)) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("an argument is NULL"))); option = text_to_cstring(PG_GETARG_TEXT_P(0)); len = PG_GETARG_INT32(1); switch (option[0]) { case 'a': case 'A': charset = alpha_mixed; chrset_size = strlen(alpha_mixed); break; case 'l': case 'L': charset = lower_only; chrset_size = strlen(lower_only); break; case 'u': case 'U': charset = upper_only; chrset_size = strlen(upper_only); break; case 'x': case 'X': charset = upper_alphanum; chrset_size = strlen(upper_alphanum); break; case 'p': case 'P': charset = printable; chrset_size = strlen(printable); break; default: ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("unknown option '%s'", option), errhint("available option \"aAlLuUxXpP\""))); /* be compiler a quiete */ charset = NULL; chrset_size = 0; } PG_RETURN_TEXT_P(random_string(charset, chrset_size, len)); } /* * dbms_random.terminate; * * Terminate use of the Package */ Datum dbms_random_terminate(PG_FUNCTION_ARGS) { /* do nothing */ PG_RETURN_VOID(); } /* * dbms_random.value() RETURN NUMBER; * * Gets a random number, greater than or equal to 0 and less than 1. */ Datum dbms_random_value(PG_FUNCTION_ARGS) { float8 result; /* result [0.0 - 1.0) */ result = (double) rand() / ((double) RAND_MAX + 1); PG_RETURN_FLOAT8(result); } /* * dbms_random.value(low NUMBER, high NUMBER) RETURN NUMBER * * Alternatively, you can get a random Oracle number x, * where x is greater than or equal to low and less than high */ Datum dbms_random_value_range(PG_FUNCTION_ARGS) { float8 low = PG_GETARG_FLOAT8(0); float8 high = PG_GETARG_FLOAT8(1); float8 result; if (low > high) PG_RETURN_NULL(); result = ((double) rand() / ((double) RAND_MAX + 1)) * ( high - low) + low; PG_RETURN_FLOAT8(result); } /* * Lower tail quantile for standard normal distribution function. * * This function returns an approximation of the inverse cumulative * standard normal distribution function. I.e., given P, it returns * an approximation to the X satisfying P = Pr{Z <= X} where Z is a * random variable from the standard normal distribution. * * The algorithm uses a minimax approximation by rational functions * and the result has a relative error whose absolute value is less * than 1.15e-9. * * Author: Peter J. Acklam * Time-stamp: 2002-06-09 18:45:44 +0200 * E-mail: jacklam@math.uio.no * WWW URL: http://www.math.uio.no/~jacklam * * C implementation adapted from Peter's Perl version */ static double ltqnorm(double p) { double q, r; errno = 0; if (p < 0 || p > 1) { errno = EDOM; return 0.0; } else if (p == 0) { errno = ERANGE; return -HUGE_VAL /* minus "infinity" */; } else if (p == 1) { errno = ERANGE; return HUGE_VAL /* "infinity" */; } else if (p < LOW) { /* Rational approximation for lower region */ q = sqrt(-2*log(p)); return (((((c[0]*q+c[1])*q+c[2])*q+c[3])*q+c[4])*q+c[5]) / ((((d[0]*q+d[1])*q+d[2])*q+d[3])*q+1); } else if (p > HIGH) { /* Rational approximation for upper region */ q = sqrt(-2*log(1-p)); return -(((((c[0]*q+c[1])*q+c[2])*q+c[3])*q+c[4])*q+c[5]) / ((((d[0]*q+d[1])*q+d[2])*q+d[3])*q+1); } else { /* Rational approximation for central region */ q = p - 0.5; r = q*q; return (((((a[0]*r+a[1])*r+a[2])*r+a[3])*r+a[4])*r+a[5])*q / (((((b[0]*r+b[1])*r+b[2])*r+b[3])*r+b[4])*r+1); } } orafce-VERSION_3_9_0/shmmc.c000066400000000000000000000155431362147214200156160ustar00rootroot00000000000000/* * * Shared memory control - based on alocating chunks aligned on * asize array (fibonachi), and dividing free bigger block. * */ #include "postgres.h" #include "shmmc.h" #include "stdlib.h" #include "string.h" #include "orafce.h" #include "stdint.h" #define LIST_ITEMS 512 int context; typedef struct { size_t size; void* first_byte_ptr; bool dispossible; /* int16 context; */ } list_item; typedef struct { int list_c; size_t max_size; vardata data[1]; /* flexible array member */ } mem_desc; #define MAX_SIZE 82688 static size_t asize[] = { 32, 64, 96, 160, 256, 416, 672, 1088, 1760, 2848, 4608, 7456, 12064, 19520, 31584, 51104, 82688}; int *list_c = NULL; list_item *list = NULL; size_t max_size; int cycle = 0; /* align requested size */ static int ptr_comp(const void* a, const void* b) { ptrdiff_t d; list_item *_a = (list_item*) a; list_item *_b = (list_item*) b; d = (uintptr_t)_a->first_byte_ptr - (uintptr_t)_b->first_byte_ptr; return d > 0 ? 1 : (d < 0 ? -1 : 0); } char * ora_sstrcpy(char *str) { size_t len; char *result; len = strlen(str); if (NULL != (result = ora_salloc(len+1))) memcpy(result, str, len + 1); else ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"), errdetail("Failed while allocation block %d bytes in shared memory.", (int) len+1), errhint("Increase SHMEMMSGSZ and recompile package."))); return result; } char * ora_scstring(text *str) { int len; char *result; len = VARSIZE_ANY_EXHDR(str); if (NULL != (result = ora_salloc(len+1))) { memcpy(result, VARDATA_ANY(str), len); result[len] = '\0'; } else ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"), errdetail("Failed while allocation block %d bytes in shared memory.", (int) len+1), errhint("Increase SHMEMMSGSZ and recompile package."))); return result; } /* * Compact the list of slots, by merging adjacent unused slots into larger * slots. */ static void defragmentation() { int src, target; /* Sort the array to pointer order */ qsort(list, *list_c, sizeof(list_item), ptr_comp); /* Merge adjacent dispossible slots, and move up other slots */ target = 0; for (src = 0; src < *list_c; src++) { if (target > 0 && list[src].dispossible && list[target - 1].dispossible) { list[target - 1].size += list[src].size; } else { if (src != target) memcpy(&list[target], &list[src], sizeof(list_item)); target++; } } *list_c = target; } static size_t align_size(size_t size) { int i; /* default, we can allocate max MAX_SIZE memory block */ for (i = 0; i < 17; i++) if (asize[i] >= size) return asize[i]; ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("too much large memory block request"), errdetail("Failed while allocation block %lu bytes in shared memory.", (unsigned long) size), errhint("Increase MAX_SIZE constant, fill table a_size and recompile package."))); return 0; } /* initialize shared memory. It works in two modes, create and no create. No create is used for mounting shared memory buffer. Top of memory is used for list_item array. */ void ora_sinit(void *ptr, size_t size, bool create) { if (list == NULL) { mem_desc *m = (mem_desc*)ptr; list = (list_item*)m->data; list_c = &m->list_c; max_size = m->max_size = size; if (create) { list[0].size = size - sizeof(list_item)*LIST_ITEMS - sizeof(mem_desc); list[0].first_byte_ptr = ((char *) &m->data) + sizeof(list_item)*LIST_ITEMS; list[0].dispossible = true; *list_c = 1; } } } void* ora_salloc(size_t size) { size_t aligned_size; int repeat_c; void *ptr = NULL; aligned_size = align_size(size); for (repeat_c = 0; repeat_c < 2; repeat_c++) { size_t max_min = max_size; int select = -1; int i; /* find first good free block */ for (i = 0; i < *list_c; i++) { if (list[i].dispossible) { /* If this block is just the right size, return it */ if (list[i].size == aligned_size) { list[i].dispossible = false; ptr = list[i].first_byte_ptr; /* list[i].context = context; */ return ptr; } if (list[i].size > aligned_size && list[i].size < max_min) { max_min = list[i].size; select = i; } } } /* If no suitable free slot found, defragment and try again. */ if (select == -1 || *list_c == LIST_ITEMS) { defragmentation(); continue; } /* * A slot larger than required was found. Divide it to avoid wasting * space, and return the slot of the right size. */ list[*list_c].size = list[select].size - aligned_size; list[*list_c].first_byte_ptr = (char*)list[select].first_byte_ptr + aligned_size; list[*list_c].dispossible = true; list[select].size = aligned_size; list[select].dispossible = false; /* list[select].context = context; */ ptr = list[select].first_byte_ptr; *list_c += 1; break; } return ptr; } void ora_sfree(void* ptr) { int i; /* if (cycle++ % 100 == 0) { size_t suma = 0; for (i = 0; i < *list_c; i++) if (list[i].dispossible) suma += list[i].size; elog(NOTICE, "=============== FREE MEM REPORT === %10d ================", suma); } */ for (i = 0; i < *list_c; i++) if (list[i].first_byte_ptr == ptr) { list[i].dispossible = true; /* list[i].context = -1; */ memset(list[i].first_byte_ptr, '#', list[i].size); return; } ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), errmsg("corrupted pointer"), errdetail("Failed while reallocating memory block in shared memory."), errhint("Report this bug to autors."))); } void* ora_srealloc(void *ptr, size_t size) { void *result; size_t aux_s = 0; int i; for (i = 0; i < *list_c; i++) if (list[i].first_byte_ptr == ptr) { if (align_size(size) <= list[i].size) return ptr; aux_s = list[i].size; } if (aux_s == 0) ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), errmsg("corrupted pointer"), errdetail("Failed while reallocating memory block in shared memory."), errhint("Report this bug to autors."))); if (NULL != (result = ora_salloc(size))) { memcpy(result, ptr, aux_s); ora_sfree(ptr); } return result; } /* * alloc shared memory, raise exception if not */ void* salloc(size_t size) { void* result; if (NULL == (result = ora_salloc(size))) ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"), errdetail("Failed while allocation block %lu bytes in shared memory.", (unsigned long) size), errhint("Increase SHMEMMSGSZ and recompile package."))); return result; } void* srealloc(void *ptr, size_t size) { void* result; if (NULL == (result = ora_srealloc(ptr, size))) ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"), errdetail("Failed while reallocation block %lu bytes in shared memory.", (unsigned long) size), errhint("Increase SHMEMMSGSZ and recompile package."))); return result; } orafce-VERSION_3_9_0/shmmc.h000066400000000000000000000005101362147214200156070ustar00rootroot00000000000000#ifndef __SHMMC__ #define __SHMMC__ void ora_sinit(void *ptr, size_t size, bool create); void* ora_salloc(size_t size); void* ora_srealloc(void *ptr, size_t size); void ora_sfree(void* ptr); char* ora_sstrcpy(char *str); char* ora_scstring(text *str); void* salloc(size_t size); void* srealloc(void *ptr,size_t size); #endif orafce-VERSION_3_9_0/sql/000077500000000000000000000000001362147214200151325ustar00rootroot00000000000000orafce-VERSION_3_9_0/sql/aggregates.sql000066400000000000000000000054621362147214200177730ustar00rootroot00000000000000-- Tests for the aggregate listagg SELECT listagg(i::text) from generate_series(1,3) g(i); SELECT listagg(i::text, ',') from generate_series(1,3) g(i); SELECT coalesce(listagg(i::text), '') from (SELECT ''::text) g(i); SELECT coalesce(listagg(i::text), '') from generate_series(1,0) g(i); SELECT wm_concat(i::text) from generate_series(1,3) g(i); -- Tests for the aggregate median( real | double ) CREATE FUNCTION checkMedianRealOdd() RETURNS real AS $$ DECLARE med real; BEGIN CREATE TABLE median_test (salary real); INSERT INTO median_test VALUES (4500); INSERT INTO median_test VALUES (NULL); INSERT INTO median_test VALUES (2100); INSERT INTO median_test VALUES (3600); INSERT INTO median_test VALUES (4000); SELECT into med median(salary) from median_test; DROP TABLE median_test; return med; END; $$ LANGUAGE plpgsql; CREATE FUNCTION checkMedianRealEven() RETURNS real AS $$ DECLARE med real; BEGIN CREATE TABLE median_test (salary real); INSERT INTO median_test VALUES (4500); INSERT INTO median_test VALUES (1500); INSERT INTO median_test VALUES (2100); INSERT INTO median_test VALUES (3600); INSERT INTO median_test VALUES (1000); INSERT INTO median_test VALUES (4000); select into med median(salary) from median_test; DROP TABLE median_test; return med; END; $$ LANGUAGE plpgsql; CREATE FUNCTION checkMedianDoubleOdd() RETURNS double precision AS $$ DECLARE med double precision; BEGIN CREATE TABLE median_test (salary double precision); INSERT INTO median_test VALUES (4500); INSERT INTO median_test VALUES (1500); INSERT INTO median_test VALUES (2100); INSERT INTO median_test VALUES (3600); INSERT INTO median_test VALUES (4000); select into med median(salary) from median_test; DROP TABLE median_test; return med; END; $$ LANGUAGE plpgsql; CREATE FUNCTION checkMedianDoubleEven() RETURNS double precision AS $$ DECLARE med double precision; BEGIN CREATE TABLE median_test (salary double precision); INSERT INTO median_test VALUES (4500); INSERT INTO median_test VALUES (1500); INSERT INTO median_test VALUES (2100); INSERT INTO median_test VALUES (3600); INSERT INTO median_test VALUES (4000); INSERT INTO median_test VALUES (1000); select into med median(salary) from median_test; DROP TABLE median_test; return med; END; $$ LANGUAGE plpgsql; SELECT checkMedianRealOdd(); SELECT checkMedianRealEven(); SELECT checkMedianDoubleOdd(); SELECT checkMedianDoubleEven(); DROP FUNCTION checkMedianRealOdd(); DROP FUNCTION checkMedianRealEven(); DROP FUNCTION checkMedianDoubleOdd(); DROP FUNCTION checkMedianDoubleEven(); orafce-VERSION_3_9_0/sql/dbms_alert_session_A.sql000066400000000000000000000042321362147214200217730ustar00rootroot00000000000000\set ECHO all SELECT pg_sleep(3); /* * DBMS_ALERT is used for one-way communication of one session to other. * * This session mainly sends signals for testing the alert functionality in * session B and C. * * The following alerts are used to ensure that signals are sent at correct * times to session B for testing. These signals are sent from session B * indicating completion of an event. * After the signal is received, the next required signal for testing is sent * from this session. */ SELECT dbms_alert.register('b1'); SELECT dbms_alert.register('b2'); SELECT dbms_alert.register('b3'); SELECT dbms_alert.register('b4'); SELECT dbms_alert.register('b5'); SELECT dbms_alert.signal('a1','Msg1 for a1'); SELECT dbms_alert.signal('a2','Msg1 for a2'); /* * Test: defered_signal * The signal is received only when the signalling transaction commits. * To test this, an explict BEGIN-COMMIT block is used. */ SELECT dbms_alert.signal('tds','Begin defered_signal test'); BEGIN; SELECT dbms_alert.signal('tds','Testing defered_signal'); /* The signal is received while transaction is running */ SELECT dbms_alert.waitone('b1',20); COMMIT; /* The signal is received after transaction completed. * After this the tds signal is received in session B indicating that the * signal is received only after commit. */ SELECT dbms_alert.waitone('b1',20); SELECT dbms_alert.waitone('b2',20); /* This signals a3 which is not registered in Session B */ SELECT dbms_alert.signal('a3','Msg1 for a3'); /* alert a4 is signalled soon after a3 */ SELECT dbms_alert.signal('a4','Test- Register after signal'); /* This signal indicates at remove() is called */ SELECT dbms_alert.waitone('b3',20); /* Send signal which is removed in session B */ SELECT dbms_alert.signal('a1','Msg2 for a1'); SELECT dbms_alert.waitone('b4',20); /* Send signal which is registered in B and not removed */ SELECT dbms_alert.signal('a4','Msg1 for a4'); /* This signal inidcates that removeall() is called */ SELECT dbms_alert.waitone('b5',20); /* Send a signal to test if session B receives it after removeall() */ SELECT dbms_alert.signal('a2','Msg2 for a2'); /* cleanup */ SELECT dbms_alert.removeall(); orafce-VERSION_3_9_0/sql/dbms_alert_session_B.sql000066400000000000000000000032331362147214200217740ustar00rootroot00000000000000\set ECHO all /* Register alerts */ SELECT dbms_alert.register('a1'); SELECT dbms_alert.register('a2'); SELECT dbms_alert.register('tds'); /* Test: multisession waitone */ SELECT dbms_alert.waitone('a1',20); /* Test: multisession waitany */ SELECT dbms_alert.waitany(10); /* Test defered_signal */ /* This indicated that the transaction has begun */ SELECT dbms_alert.waitone('tds',10); /* The signal will not be received because the transaction is running */ SELECT dbms_alert.waitone('tds',2); SELECT dbms_alert.signal('b1','Transaction still running'); SELECT dbms_alert.signal('b1','Transaction committed'); /* Since the transaction has commited, the signal will be received */ SELECT dbms_alert.waitone('tds',10); /* Signal session A to send msg1 for a3 */ SELECT dbms_alert.signal('b2','to check unregistered alert wait'); /* Test: wait for unregistered alert which is signaled*/ SELECT dbms_alert.waitone('a3',2); /* Test: Register after alert is signaled and wait */ SELECT dbms_alert.register('a4'); SELECT dbms_alert.waitone('a4',2); /* Test: remove one */ SELECT dbms_alert.remove('a1'); /* Signal session A to send msg2 for a1 */ SELECT dbms_alert.signal('b3','remove(a1) called'); /* Test: wait for removed alert */ SELECT dbms_alert.waitone('a1',2); /* Signal session A to send msg1 for a4 */ SELECT dbms_alert.signal('b4','to check unremoved alert'); /* Test: Check if unremoved alert is received */ SELECT dbms_alert.waitone('a4',10); /* Test removeall */ SELECT dbms_alert.removeall(); /* Signal session A to send msg2 for a2 */ SELECT dbms_alert.signal('b5','removeall called'); /* Test: Use waitany to see if any alert is received */ SELECT dbms_alert.waitany(2); orafce-VERSION_3_9_0/sql/dbms_alert_session_C.sql000066400000000000000000000004371362147214200220000ustar00rootroot00000000000000\set ECHO all /* Register alerts */ SELECT dbms_alert.register('a1'); SELECT dbms_alert.register('a2'); /* Test: multisession waitone */ SELECT dbms_alert.waitone('a1',20); /* Test: multisession waitany */ SELECT dbms_alert.waitany(10); /* cleanup */ SELECT dbms_alert.removeall(); orafce-VERSION_3_9_0/sql/dbms_output.sql000066400000000000000000000572351362147214200202340ustar00rootroot00000000000000\set ECHO none SET client_min_messages = warning; SET DATESTYLE TO ISO; SET client_encoding = utf8; \pset null '' \set ECHO all DROP FUNCTION dbms_output_test(); DROP TABLE dbms_output_test; -- DBMS_OUTPUT.DISABLE [0] CREATE TABLE dbms_output_test (buff VARCHAR(20), status INTEGER); CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ DECLARE buff VARCHAR(20); stts INTEGER; BEGIN PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 1'); SELECT INTO buff,stts line,status FROM DBMS_OUTPUT.GET_LINE(); INSERT INTO dbms_output_test VALUES (buff, stts); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); SELECT * FROM dbms_output_test; DROP TABLE dbms_output_test; DROP FUNCTION dbms_output_test(); -- DBMS_OUTPUT.PUT_LINE [1] CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ DECLARE buff1 VARCHAR(20) := 'orafce'; BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('t'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE'); PERFORM DBMS_OUTPUT.PUT_LINE (buff1); PERFORM DBMS_OUTPUT.PUT ('ABC'); PERFORM DBMS_OUTPUT.PUT_LINE (''); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); DROP FUNCTION dbms_output_test(); -- DBMS_OUTPUT.PUT_LINE [2] CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('t'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORA F CE'); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); DROP FUNCTION dbms_output_test(); -- DBMS_OUTPUT.PUT [1] CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ DECLARE buff1 VARCHAR(20) := 'ora'; buff2 VARCHAR(20) := 'f'; buff3 VARCHAR(20) := 'ce'; BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('t'); PERFORM DBMS_OUTPUT.PUT ('ORA'); PERFORM DBMS_OUTPUT.PUT ('F'); PERFORM DBMS_OUTPUT.PUT ('CE'); PERFORM DBMS_OUTPUT.PUT_LINE (''); PERFORM DBMS_OUTPUT.PUT ('ABC'); PERFORM DBMS_OUTPUT.PUT_LINE (''); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); DROP FUNCTION dbms_output_test(); -- DBMS_OUTPUT.PUT [2] CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('t'); PERFORM DBMS_OUTPUT.PUT ('ORA F CE'); PERFORM DBMS_OUTPUT.PUT_LINE (''); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); DROP FUNCTION dbms_output_test(); -- DBMS_OUTPUT.GET_LINE [1] CREATE TABLE dbms_output_test (buff VARCHAR(20), status INTEGER); CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ DECLARE buff VARCHAR(20); stts INTEGER; BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 1'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 2'); SELECT INTO buff,stts line,status FROM DBMS_OUTPUT.GET_LINE(); INSERT INTO dbms_output_test VALUES (buff, stts); SELECT INTO buff,stts line,status FROM DBMS_OUTPUT.GET_LINE(); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); SELECT * FROM dbms_output_test; DROP TABLE dbms_output_test; DROP FUNCTION dbms_output_test(); -- DBMS_OUTPUT.GET_LINE [2] CREATE TABLE dbms_output_test (buff VARCHAR(20), status INTEGER); CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ DECLARE buff VARCHAR(20); stts INTEGER; BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 1'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 2'); SELECT INTO buff,stts line,status FROM DBMS_OUTPUT.GET_LINE(); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 3'); SELECT INTO buff,stts line,status FROM DBMS_OUTPUT.GET_LINE(); INSERT INTO dbms_output_test VALUES (buff, stts); SELECT INTO buff,stts line,status FROM DBMS_OUTPUT.GET_LINE(); INSERT INTO dbms_output_test VALUES (buff, stts); SELECT INTO buff,stts line,status FROM DBMS_OUTPUT.GET_LINE(); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); SELECT * FROM dbms_output_test; DROP TABLE dbms_output_test; DROP FUNCTION dbms_output_test(); -- DBMS_OUTPUT.GET_LINE [3] CREATE TABLE dbms_output_test (buff VARCHAR(20), status INTEGER); CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ DECLARE buff VARCHAR(20); stts INTEGER; BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 1'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 2'); SELECT INTO buff,stts line,status FROM DBMS_OUTPUT.GET_LINE(); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.PUT ('ORA'); SELECT INTO buff,stts line,status FROM DBMS_OUTPUT.GET_LINE(); INSERT INTO dbms_output_test VALUES (buff, stts); SELECT INTO buff,stts line,status FROM DBMS_OUTPUT.GET_LINE(); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); SELECT * FROM dbms_output_test; DROP TABLE dbms_output_test; DROP FUNCTION dbms_output_test(); -- DBMS_OUTPUT.GET_LINE [4] CREATE TABLE dbms_output_test (buff VARCHAR(20), status INTEGER); CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ DECLARE buff VARCHAR(20); stts INTEGER; BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 1'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 2'); SELECT INTO buff,stts line,status FROM DBMS_OUTPUT.GET_LINE(); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.NEW_LINE(); SELECT INTO buff,stts line,status FROM DBMS_OUTPUT.GET_LINE(); INSERT INTO dbms_output_test VALUES (buff, stts); SELECT INTO buff,stts line,status FROM DBMS_OUTPUT.GET_LINE(); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); SELECT * FROM dbms_output_test; DROP TABLE dbms_output_test; DROP FUNCTION dbms_output_test(); -- DBMS_OUTPUT.GET_LINE [5] CREATE TABLE dbms_output_test (buff VARCHAR(20), status INTEGER); CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ DECLARE buff VARCHAR(20); stts INTEGER; BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 1 '); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 2'); SELECT INTO buff,stts line,status FROM DBMS_OUTPUT.GET_LINE(); INSERT INTO dbms_output_test VALUES (buff, stts); SELECT INTO buff,stts line,status FROM DBMS_OUTPUT.GET_LINE(); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); SELECT REPLACE(buff, ' ', '') FROM dbms_output_test; DROP TABLE dbms_output_test; DROP FUNCTION dbms_output_test(); -- DBMS_OUTPUT.GET_LINE [6] CREATE TABLE dbms_output_test (buff VARCHAR(20), status INTEGER); CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ DECLARE buff VARCHAR(20); stts INTEGER; BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORA F CE'); SELECT INTO buff,stts line,status FROM DBMS_OUTPUT.GET_LINE(); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); SELECT regexp_replace(buff, E'\n', '', 'g') FROM dbms_output_test limit 1; DROP TABLE dbms_output_test; DROP FUNCTION dbms_output_test(); -- DBMS_OUTPUT.GET_LINES [1] CREATE TABLE dbms_output_test (buff VARCHAR(20), status INTEGER); CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ DECLARE buff VARCHAR(20); buff1 VARCHAR(20); buff2 VARCHAR(20); buff3 VARCHAR(20); stts INTEGER := 10; BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 1'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 2'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 3'); SELECT INTO buff1,buff2,buff3,stts lines[1],lines[2],lines[3],numlines FROM DBMS_OUTPUT.GET_LINES(stts); INSERT INTO dbms_output_test VALUES (buff1, stts); INSERT INTO dbms_output_test VALUES (buff2, stts); INSERT INTO dbms_output_test VALUES (buff3, stts); SELECT INTO buff,stts lines[1],numlines FROM DBMS_OUTPUT.GET_LINES(stts); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); SELECT * FROM dbms_output_test; DROP TABLE dbms_output_test; DROP FUNCTION dbms_output_test(); -- DBMS_OUTPUT.GET_LINES [2] CREATE TABLE dbms_output_test (buff VARCHAR(20), status INTEGER); CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ DECLARE buff VARCHAR(20); buff1 VARCHAR(20); buff2 VARCHAR(20); stts INTEGER := 2; BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 1'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 2'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 3'); SELECT INTO buff1,buff2,stts lines[1],lines[2],numlines FROM DBMS_OUTPUT.GET_LINES(stts); INSERT INTO dbms_output_test VALUES (buff1, stts); INSERT INTO dbms_output_test VALUES (buff2, stts); SELECT INTO buff,stts lines[1],numlines FROM DBMS_OUTPUT.GET_LINES(stts); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); SELECT * FROM dbms_output_test; DROP TABLE dbms_output_test; DROP FUNCTION dbms_output_test(); -- DBMS_OUTPUT.GET_LINES [3] CREATE TABLE dbms_output_test (buff VARCHAR(20), status INTEGER); CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ DECLARE buff VARCHAR(20); stts INTEGER := 1; BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 1'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 2'); SELECT INTO buff,stts lines[1],numlines FROM DBMS_OUTPUT.GET_LINES(stts); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 3'); SELECT INTO buff,stts lines[1],numlines FROM DBMS_OUTPUT.GET_LINES(stts); INSERT INTO dbms_output_test VALUES (buff, stts); SELECT INTO buff,stts lines[1],numlines FROM DBMS_OUTPUT.GET_LINES(stts); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); SELECT * FROM dbms_output_test; DROP TABLE dbms_output_test; DROP FUNCTION dbms_output_test(); -- DBMS_OUTPUT.GET_LINES [4] CREATE TABLE dbms_output_test (buff VARCHAR(20), status INTEGER); CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ DECLARE buff VARCHAR(20); stts INTEGER := 1; BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 1'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 2'); SELECT INTO buff,stts lines[1],numlines FROM DBMS_OUTPUT.GET_LINES(stts); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.PUT ('ORA'); SELECT INTO buff,stts lines[1],numlines FROM DBMS_OUTPUT.GET_LINES(stts); INSERT INTO dbms_output_test VALUES (buff, stts); SELECT INTO buff,stts lines[1],numlines FROM DBMS_OUTPUT.GET_LINES(stts); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); SELECT * FROM dbms_output_test; DROP TABLE dbms_output_test; DROP FUNCTION dbms_output_test(); -- DBMS_OUTPUT.GET_LINES [5] CREATE TABLE dbms_output_test (buff VARCHAR(20), status INTEGER); CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ DECLARE buff VARCHAR(20); stts INTEGER := 1; BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 1'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 2'); SELECT INTO buff,stts lines[1],numlines FROM DBMS_OUTPUT.GET_LINES(stts); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.NEW_LINE(); SELECT INTO buff,stts lines[1],numlines FROM DBMS_OUTPUT.GET_LINES(stts); INSERT INTO dbms_output_test VALUES (buff, stts); SELECT INTO buff,stts lines[1],numlines FROM DBMS_OUTPUT.GET_LINES(stts); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); SELECT * FROM dbms_output_test; DROP TABLE dbms_output_test; DROP FUNCTION dbms_output_test(); -- DBMS_OUTPUT.GET_LINES [6] CREATE TABLE dbms_output_test (buff VARCHAR(20), status INTEGER); CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ DECLARE buff VARCHAR(20); stts INTEGER := 1; BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORA F CE'); SELECT INTO buff,stts lines[1],numlines FROM DBMS_OUTPUT.GET_LINES(stts); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); SELECT regexp_replace(buff, E'\n', '', 'g') FROM dbms_output_test limit 1; DROP TABLE dbms_output_test; DROP FUNCTION dbms_output_test(); -- DBMS_OUTPUT.NEW_LINE [1] CREATE TABLE dbms_output_test (buff VARCHAR(20), status INTEGER); CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ DECLARE buff1 VARCHAR(20); buff2 VARCHAR(20); stts INTEGER := 10; BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.PUT ('ORA'); PERFORM DBMS_OUTPUT.NEW_LINE(); PERFORM DBMS_OUTPUT.PUT ('FCE'); PERFORM DBMS_OUTPUT.NEW_LINE(); SELECT INTO buff1,buff2,stts lines[1],lines[2],numlines FROM DBMS_OUTPUT.GET_LINES(stts); INSERT INTO dbms_output_test VALUES (buff1, stts); INSERT INTO dbms_output_test VALUES (buff2, stts); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); SELECT * FROM dbms_output_test; DROP TABLE dbms_output_test; DROP FUNCTION dbms_output_test(); -- DBMS_OUTPUT.NEW_LINE [2] CREATE TABLE dbms_output_test (buff VARCHAR(3000), status INTEGER); CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ DECLARE buff1 VARCHAR(3000); stts INTEGER := 10; BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.ENABLE(2000); FOR j IN 1..1999 LOOP PERFORM DBMS_OUTPUT.PUT ('A'); END LOOP; PERFORM DBMS_OUTPUT.NEW_LINE(); SELECT INTO buff1,stts lines[1],numlines FROM DBMS_OUTPUT.GET_LINES(stts); INSERT INTO dbms_output_test VALUES (buff1, stts); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); SELECT buff FROM dbms_output_test; DROP TABLE dbms_output_test; DROP FUNCTION dbms_output_test(); -- DBMS_OUTPUT.DISABLE [1] CREATE TABLE dbms_output_test (buff VARCHAR(20), status INTEGER); CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ DECLARE buff VARCHAR(20); stts INTEGER; BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 1'); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); SELECT INTO buff,stts line,status FROM DBMS_OUTPUT.GET_LINE(); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 2'); PERFORM DBMS_OUTPUT.ENABLE(); SELECT INTO buff,stts line,status FROM DBMS_OUTPUT.GET_LINE(); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 3'); PERFORM DBMS_OUTPUT.DISABLE(); SELECT INTO buff,stts line,status FROM DBMS_OUTPUT.GET_LINE(); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.PUT ('ORAFCE TEST 4'); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.NEW_LINE(); SELECT INTO buff,stts line,status FROM DBMS_OUTPUT.GET_LINE(); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.PUT ('ORAFCE TEST 5'); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.NEW_LINE(); PERFORM DBMS_OUTPUT.ENABLE(); SELECT INTO buff,stts line,status FROM DBMS_OUTPUT.GET_LINE(); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); SELECT * FROM dbms_output_test; DROP TABLE dbms_output_test; DROP FUNCTION dbms_output_test(); -- DBMS_OUTPUT.DISABLE [2] CREATE TABLE dbms_output_test (buff VARCHAR(20), status INTEGER); CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ DECLARE buff VARCHAR(20); stts INTEGER := 10; BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 1'); SELECT INTO buff,stts lines[1],numlines FROM DBMS_OUTPUT.GET_LINES(stts); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.ENABLE(); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); SELECT * FROM dbms_output_test; DROP TABLE dbms_output_test; DROP FUNCTION dbms_output_test(); -- DBMS_OUTPUT.ENABLE [1] CREATE TABLE dbms_output_test (buff VARCHAR(20), status INTEGER); CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ DECLARE buff VARCHAR(20); status INTEGER; num INTEGER := 2000; BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('t'); PERFORM DBMS_OUTPUT.ENABLE(2000); PERFORM DBMS_OUTPUT.PUT ('ORAFCE TEST 1'); PERFORM DBMS_OUTPUT.NEW_LINE(); PERFORM DBMS_OUTPUT.ENABLE(); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); SELECT * FROM dbms_output_test; DROP TABLE dbms_output_test; DROP FUNCTION dbms_output_test(); -- DBMS_OUTPUT.ENABLE [2] CREATE TABLE dbms_output_test (buff VARCHAR(20), status INTEGER); CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ DECLARE buff VARCHAR(20); stts INTEGER; BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 1'); SELECT INTO buff,stts line,status FROM DBMS_OUTPUT.GET_LINE(); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.PUT ('ORAFCE TEST 2'); PERFORM DBMS_OUTPUT.NEW_LINE(); SELECT INTO buff,stts line,status FROM DBMS_OUTPUT.GET_LINE(); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.ENABLE(); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); SELECT * FROM dbms_output_test; DROP TABLE dbms_output_test; DROP FUNCTION dbms_output_test(); -- DBMS_OUTPUT.ENABLE [3] CREATE TABLE dbms_output_test (buff VARCHAR(20), status INTEGER); CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ DECLARE buff VARCHAR(20); stts INTEGER := 10; BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 1'); SELECT INTO buff,stts lines[1],numlines FROM DBMS_OUTPUT.GET_LINES(stts); INSERT INTO dbms_output_test VALUES (buff, stts); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); SELECT * FROM dbms_output_test; DROP TABLE dbms_output_test; DROP FUNCTION dbms_output_test(); -- DBMS_OUTPUT.ENABLE [4] CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('t'); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); FOR j IN 1..2000 LOOP PERFORM DBMS_OUTPUT.PUT ('A'); END LOOP; PERFORM DBMS_OUTPUT.NEW_LINE(); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); DROP FUNCTION dbms_output_test(); -- DBMS_OUTPUT.ENABLE [5] CREATE TABLE dbms_output_test (buff VARCHAR(20), status INTEGER); CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ DECLARE buff VARCHAR(20); stts INTEGER; BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(NULL); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 1'); SELECT INTO buff,stts line,status FROM DBMS_OUTPUT.GET_LINE(); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); SELECT * FROM dbms_output_test; DROP TABLE dbms_output_test; DROP FUNCTION dbms_output_test(); -- DBMS_OUTPUT.ENABLE [6] CREATE TABLE dbms_output_test (buff VARCHAR(20), status INTEGER); CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ DECLARE buff VARCHAR(20); stts INTEGER; BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 1'); PERFORM DBMS_OUTPUT.ENABLE(); SELECT INTO buff,stts line,status FROM DBMS_OUTPUT.GET_LINE(); INSERT INTO dbms_output_test VALUES (buff, stts); PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); SELECT * FROM dbms_output_test; DROP TABLE dbms_output_test; DROP FUNCTION dbms_output_test(); -- SERVEROUTPUT [1] CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 1'); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); DROP FUNCTION dbms_output_test(); CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ BEGIn PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('t'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 2'); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); DROP FUNCTION dbms_output_test(); -- SERVEROUTPUT [2] CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.PUT ('ORAFCE TEST 1'); PERFORM DBMS_OUTPUT.NEW_LINE(); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); DROP FUNCTION dbms_output_test(); CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('t'); PERFORM DBMS_OUTPUT.PUT ('ORAFCE TEST 2'); PERFORM DBMS_OUTPUT.NEW_LINE(); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); DROP FUNCTION dbms_output_test(); -- SERVEROUTPUT [3] CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.DISABLE(); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); DROP FUNCTION dbms_output_test(); CREATE FUNCTION dbms_output_test() RETURNS VOID AS $$ BEGIN PERFORM DBMS_OUTPUT.DISABLE(); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.SERVEROUTPUT ('t'); PERFORM DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 1'); END; $$ LANGUAGE plpgsql; SELECT dbms_output_test(); DROP FUNCTION dbms_output_test(); orafce-VERSION_3_9_0/sql/dbms_pipe.sql000066400000000000000000000031471362147214200176220ustar00rootroot00000000000000CREATE TYPE testt AS (x integer, y integer, v varchar); CREATE OR REPLACE FUNCTION st(integer, integer, varchar) RETURNS void AS $$ DECLARE t testt; r record; BEGIN t.x := $1; t.y := $2; t.v := $3; select into r 10,10,'boo'; PERFORM dbms_pipe.pack_message(t); END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION sk() RETURNS void AS $$ DECLARE t testt; o testt; BEGIN t.x := 1; t.y := 2; t.v := 'Pavel Stehule'; RAISE NOTICE 'SEND'; PERFORM dbms_pipe.pack_message(t); PERFORM dbms_pipe.send_message('boo',4,10); RAISE NOTICE 'RECEIVE'; -- PERFORM dbms_pipe.receive_message('boo',4); -- SELECT INTO o * from dbms_pipe.unpack_message_record() as (x integer, y integer, v varchar); -- RAISE NOTICE 'received %', o.v; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION SessionA() RETURNS void AS $$ BEGIN FOR i IN 1..100000 LOOP PERFORM dbms_pipe.pack_message('Prvni '||i); PERFORM dbms_pipe.pack_message('Druhy '||i); RAISE NOTICE 'SEND'; IF dbms_pipe.send_message('pipe_name',4,10) = 1 THEN RAISE NOTICE 'Timeout'; PERFORM pg_sleep(5); PERFORM dbms_pipe.send_message('pipe_name',4,10); END IF; PERFORM pg_sleep(random()); END LOOP; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION SessionB() RETURNS void AS $$ BEGIN FOR i IN 1..100000 LOOP IF dbms_pipe.receive_message('pipe_name',4) = 1 THEN RAISE NOTICE 'Timeout'; PERFORM pg_sleep(5); CONTINUE; END IF; RAISE NOTICE 'RECEIVE % %', dbms_pipe.unpack_message_text(), dbms_pipe.unpack_message_text(); PERFORM pg_sleep(random()); END LOOP; END; $$ LANGUAGE plpgsql; orafce-VERSION_3_9_0/sql/dbms_pipe_session_A.sql000066400000000000000000000157131362147214200216270ustar00rootroot00000000000000\set ECHO none SET client_min_messages = warning; DROP TABLE IF EXISTS TEMP; CREATE TABLE TEMP(id integer,name text); INSERT INTO TEMP VALUES (1,'bob'),(2,'rob'),(3,'john'); DROP USER IF EXISTS pipe_test_owner; CREATE ROLE pipe_test_owner WITH CREATEROLE; ALTER TABLE TEMP OWNER TO pipe_test_owner; SET client_min_messages = notice; -- Notify session B of 'pipe_test_owner' having been created. SELECT dbms_pipe.pack_message(1); SELECT dbms_pipe.send_message('pipe_test_owner_created_notifier'); -- Create a new connection under the userid of pipe_test_owner SET SESSION AUTHORIZATION pipe_test_owner; /* create an implicit pipe and sends message using * send_message(text,integer,integer) */ CREATE OR REPLACE FUNCTION send(pipename text) RETURNS void AS $$ BEGIN IF dbms_pipe.send_message(pipename,2,10) = 1 THEN RAISE NOTICE 'Timeout'; PERFORM pg_sleep(2); PERFORM dbms_pipe.send_message(pipename,2,10); END IF; END; $$ LANGUAGE plpgsql; -- Test pack_message for all supported types and send_message CREATE OR REPLACE FUNCTION createImplicitPipe() RETURNS void AS $$ DECLARE row TEMP%ROWTYPE; BEGIN PERFORM dbms_pipe.pack_message('Message From Session A'::text); PERFORM send('named_pipe'); PERFORM dbms_pipe.pack_message('2013-01-01'::date); PERFORM send('named_pipe'); PERFORM dbms_pipe.pack_message('2013-01-01 09:00:00'::timestamp); PERFORM send('named_pipe'); PERFORM dbms_pipe.pack_message('2013-01-01 09:00:00-08'::timestamptz); PERFORM send('named_pipe'); PERFORM dbms_pipe.pack_message(12345.6789::numeric); PERFORM send('named_pipe'); PERFORM dbms_pipe.pack_message(12345::integer); PERFORM send('named_pipe'); PERFORM dbms_pipe.pack_message(99999999999::bigint); PERFORM send('named_pipe'); PERFORM dbms_pipe.pack_message(E'\\201'::bytea); PERFORM send('named_pipe'); SELECT * INTO row FROM TEMP WHERE id=2; PERFORM dbms_pipe.pack_message(row); PERFORM send('named_pipe'); END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION bulkSend() RETURNS void AS $$ DECLARE row TEMP%ROWTYPE; BEGIN PERFORM dbms_pipe.pack_message('Message From Session A'::text); PERFORM dbms_pipe.pack_message('2013-01-01'::date); PERFORM dbms_pipe.pack_message('2013-01-01 09:00:00'::timestamp); PERFORM dbms_pipe.pack_message('2013-01-01 09:00:00-08'::timestamptz); PERFORM dbms_pipe.pack_message(12345.6789::numeric); PERFORM dbms_pipe.pack_message(12345::integer); PERFORM dbms_pipe.pack_message(99999999999::bigint); PERFORM dbms_pipe.pack_message(E'\\201'::bytea); SELECT * INTO row FROM TEMP WHERE id=2; PERFORM dbms_pipe.pack_message(row); PERFORM send('named_pipe_2'); END; $$ LANGUAGE plpgsql; /* Creates an explicit pipe using either create_pipe(text,integer,bool), * create_pipe(text,integer) OR create_pipe(text). * In case third parameter (bool) absent, default is false, that is, it's a public pipe. */ CREATE OR REPLACE FUNCTION createPipe(name text,ver integer) RETURNS void AS $$ BEGIN IF ver = 3 THEN PERFORM dbms_pipe.create_pipe(name,4,true); ELSIF ver = 2 THEN PERFORM dbms_pipe.create_pipe(name,4); ELSE PERFORM dbms_pipe.create_pipe(name); END IF; END; $$ LANGUAGE plpgsql; /* Testing create_pipe for different versions, one of them, is the case of * private pipe */ CREATE OR REPLACE FUNCTION createExplicitPipe(pipename text,create_version integer) RETURNS void AS $$ DECLARE row TEMP%ROWTYPE; BEGIN PERFORM createPipe(pipename,create_version); PERFORM dbms_pipe.reset_buffer(); PERFORM dbms_pipe.pack_message('Message From Session A'::text); PERFORM send(pipename); PERFORM dbms_pipe.pack_message('2013-01-01'::date); PERFORM send(pipename); PERFORM dbms_pipe.pack_message('2013-01-01 09:00:00'::timestamp); PERFORM send(pipename); PERFORM dbms_pipe.pack_message('2013-01-01 09:00:00-08'::timestamptz); PERFORM send(pipename); PERFORM dbms_pipe.pack_message(12345.6789::numeric); PERFORM send(pipename); PERFORM dbms_pipe.pack_message(12345::integer); PERFORM send(pipename); PERFORM dbms_pipe.pack_message(99999999999::bigint); PERFORM send(pipename); PERFORM dbms_pipe.pack_message(E'\\201'::bytea); PERFORM send(pipename); SELECT * INTO row FROM TEMP WHERE id=2; PERFORM dbms_pipe.pack_message(row); PERFORM send(pipename); END; $$ LANGUAGE plpgsql; -- Test send_message(text) CREATE OR REPLACE FUNCTION checkSend1() RETURNS void AS $$ BEGIN PERFORM dbms_pipe.pack_message('checking one-argument send_message()'); PERFORM dbms_pipe.send_message('pipe_name_1'); END; $$ LANGUAGE plpgsql; -- Test send_message(text,integer) CREATE OR REPLACE FUNCTION checkSend2() RETURNS void AS $$ BEGIN PERFORM dbms_pipe.pack_message('checking two-argument send_message()'); IF dbms_pipe.send_message('pipe_name_2',2) = 1 THEN RAISE NOTICE 'Timeout'; PERFORM pg_sleep(2); PERFORM dbms_pipe.send_message('pipe_name_2',2); END IF; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION notifyDropTemp() RETURNS void AS $$ BEGIN PERFORM dbms_pipe.pack_message(1); PERFORM dbms_pipe.send_message('pipe_name_3'); END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION checkUniqueSessionNameA() RETURNS void AS $$ BEGIN PERFORM dbms_pipe.pack_message(dbms_pipe.unique_session_name()); PERFORM dbms_pipe.send_message('pipe_name_4'); END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION notify(pipename text) RETURNS void AS $$ BEGIN PERFORM dbms_pipe.pack_message(1); PERFORM dbms_pipe.send_message(pipename); END; $$ LANGUAGE plpgsql; \set ECHO all SELECT createImplicitPipe(); -- Bulk send messages SELECT bulkSend(); -- An explicit private pipe SELECT notify('recv_private1_notifier'); SELECT createExplicitPipe('private_pipe_1',3); -- An explicit private pipe SELECT notify('recv_private2_notifier'); SELECT createExplicitPipe('private_pipe_2',3); -- An explicit public pipe (uses two-argument create_pipe) SELECT notify('recv_public1_notifier'); SELECT createExplicitPipe('public_pipe_3',2); -- An explicit public pipe (uses one-argument create_pipe) SELECT notify('recv_public2_notifier'); SELECT createExplicitPipe('public_pipe_4',1); -- tests send_message(text) SELECT checkSend1(); -- tests send_message(text,integer) SELECT checkSend2(); SELECT notifyDropTemp(); -- tests unique_session_name() SELECT checkUniqueSessionNameA(); DROP FUNCTION createImplicitPipe(); DROP FUNCTION createExplicitPipe(text,integer); DROP FUNCTION createPipe(text,integer); DROP FUNCTION checkSend1(); DROP FUNCTION checkSend2(); DROP FUNCTION checkUniqueSessionNameA(); DROP FUNCTION bulkSend(); DROP FUNCTION notifyDropTemp(); DROP FUNCTION notify(text); DROP FUNCTION send(text); orafce-VERSION_3_9_0/sql/dbms_pipe_session_B.sql000066400000000000000000000136241362147214200216270ustar00rootroot00000000000000\set ECHO none \set VERBOSITY terse --Wait for 'pipe_test_owner' created notification to be sent by session A SELECT dbms_pipe.receive_message('pipe_test_owner_created_notifier'); -- create new connection under the userid of 'pipe_test_owner' SET SESSION AUTHORIZATION pipe_test_owner; /* Tests receive_message(text,integer), next_item_type() and all versions of * unpack_message_() and purge(text) */ CREATE OR REPLACE FUNCTION receiveFrom(pipename text) RETURNS void AS $$ DECLARE typ INTEGER; BEGIN WHILE true LOOP PERFORM dbms_pipe.receive_message(pipename,2); SELECT dbms_pipe.next_item_type() INTO typ; IF typ = 0 THEN EXIT; ELSIF typ=9 THEN RAISE NOTICE 'RECEIVE %: %', typ, dbms_pipe.unpack_message_number(); ELSIF typ=11 THEN RAISE NOTICE 'RECEIVE %: %', typ, dbms_pipe.unpack_message_text(); ELSIF typ=12 THEN RAISE NOTICE 'RECEIVE %: %', typ, dbms_pipe.unpack_message_date(); ELSIF typ=13 THEN RAISE NOTICE 'RECEIVE %: %', typ, dbms_pipe.unpack_message_timestamp(); ELSIF typ=23 THEN RAISE NOTICE 'RECEIVE %: %', typ, encode(dbms_pipe.unpack_message_bytea(),'escape'); ELSIF typ=24 THEN RAISE NOTICE 'RECEIVE %: %', typ, dbms_pipe.unpack_message_record(); END IF; END LOOP; PERFORM dbms_pipe.purge(pipename); END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION bulkReceive() RETURNS void AS $$ DECLARE typ INTEGER; BEGIN IF dbms_pipe.receive_message('named_pipe_2',2) = 1 THEN RAISE NOTICE 'Timeout'; PERFORM pg_sleep(2); PERFORM dbms_pipe.receive_message('named_pipe_2',2); END IF; WHILE true LOOP SELECT dbms_pipe.next_item_type() INTO typ; IF typ = 0 THEN EXIT; ELSIF typ=9 THEN RAISE NOTICE 'RECEIVE %: %', typ, dbms_pipe.unpack_message_number(); ELSIF typ=11 THEN RAISE NOTICE 'RECEIVE %: %', typ, dbms_pipe.unpack_message_text(); ELSIF typ=12 THEN RAISE NOTICE 'RECEIVE %: %', typ, dbms_pipe.unpack_message_date(); ELSIF typ=13 THEN RAISE NOTICE 'RECEIVE %: %', typ, dbms_pipe.unpack_message_timestamp(); ELSIF typ=23 THEN RAISE NOTICE 'RECEIVE %: %', typ, encode(dbms_pipe.unpack_message_bytea()::bytea,'escape'); ELSIF typ=24 THEN RAISE NOTICE 'RECEIVE %: %', typ, dbms_pipe.unpack_message_record(); END IF; END LOOP; PERFORM dbms_pipe.purge('named_pipe_2'); END; $$ LANGUAGE plpgsql; -- Tests receive_message(text) CREATE OR REPLACE FUNCTION checkReceive1(pipename text) RETURNS void AS $$ BEGIN PERFORM dbms_pipe.receive_message(pipename); RAISE NOTICE 'RECEIVE %',dbms_pipe.unpack_message_text(); END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION dropTempTable() RETURNS void AS $$ BEGIN WHILE dbms_pipe.receive_message('pipe_name_3') <> 0 LOOP CONTINUE; END LOOP; DROP TABLE TEMP; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION checkUniqueSessionNameB() RETURNS bool AS $$ DECLARE result bool; BEGIN PERFORM dbms_pipe.receive_message('pipe_name_4'); SELECT dbms_pipe.unpack_message_text() = dbms_pipe.unique_session_name() INTO result; RETURN result; END; $$ LANGUAGE plpgsql; \set ECHO all -- Receives messages sent via an implicit pipe SELECT receiveFrom('named_pipe'); -- Bulk receive messages SELECT bulkReceive(); -- Receives messages sent via an explicit private pipe under the same user -- 'pipe_test_owner' SELECT dbms_pipe.receive_message('recv_private1_notifier'); SELECT receiveFrom('private_pipe_1'); -- Switch user to 'pipe_test_other' DROP USER IF EXISTS pipe_test_other; CREATE USER pipe_test_other; SET SESSION AUTHORIZATION pipe_test_other; -- Try to receive messages sent via an explicit private pipe under the user -- 'pipe_test_other' who is not the owner of pipe. -- insufficient privileges in case of 'private_pipe_2'. SELECT dbms_pipe.receive_message('recv_private2_notifier'); SELECT receiveFrom('private_pipe_2'); -- These are explicit private pipes created using create_pipe(text,integer) -- and create_pipe(text) SELECT dbms_pipe.receive_message('recv_public1_notifier'); SELECT receiveFrom('public_pipe_3'); SELECT dbms_pipe.receive_message('recv_public2_notifier'); SELECT receiveFrom('public_pipe_4'); -- Switch back to user 'pipe_test_owner' SET SESSION AUTHORIZATION pipe_test_owner; DROP USER pipe_test_other; -- Tests receive_message(text) SELECT checkReceive1('pipe_name_1'); SELECT checkReceive1('pipe_name_2'); -- Tests dbms_pipe.db_pipes view SELECT name, items, "limit", private, owner FROM dbms_pipe.db_pipes WHERE name LIKE 'private%' ORDER BY name; -- Tests dbms_pipe.__list_pipes(); attribute size is not included -- since it can be different across runs. SELECT name, items, "limit", private, owner FROM dbms_pipe.__list_pipes() AS (name varchar, items int4, siz int4, "limit" int4, private bool, owner varchar) WHERE name <> 'pipe_name_4' ORDER BY 1; -- Tests remove_pipe(text) SELECT dbms_pipe.remove_pipe('private_pipe_1'); SELECT dbms_pipe.remove_pipe('private_pipe_2'); SELECT dbms_pipe.remove_pipe('public_pipe_3'); SELECT dbms_pipe.remove_pipe('public_pipe_4'); SELECT dbms_pipe.purge('pipe_name_1'); SELECT dbms_pipe.purge('pipe_name_2'); -- Receives drop table notification from session A via 'pipe_name_3' SELECT dropTempTable(); SELECT dbms_pipe.purge('pipe_name_3'); -- tests unique_session_name() (uses 'pipe_name_4') SELECT checkUniqueSessionNameB(); SELECT dbms_pipe.purge('pipe_name_4'); DROP FUNCTION receiveFrom(text); DROP FUNCTION checkReceive1(text); DROP FUNCTION checkUniqueSessionNameB(); DROP FUNCTION bulkReceive(); DROP FUNCTION dropTempTable(); -- Perform a recieve on removed pipe resulting on timeout SELECT dbms_pipe.receive_message('public_pipe_4',2); SELECT dbms_pipe.purge('public_pipe_4'); SET SESSION AUTHORIZATION DEFAULT; DROP USER pipe_test_owner; orafce-VERSION_3_9_0/sql/dbms_random.sql000066400000000000000000000010721362147214200201400ustar00rootroot00000000000000-- Tests for package DBMS_RANDOM SELECT dbms_random.initialize(8); SELECT dbms_random.normal()::numeric(10, 8); SELECT dbms_random.normal()::numeric(10, 8); SELECT dbms_random.seed(8); SELECT dbms_random.random(); SELECT dbms_random.seed('test'); SELECT dbms_random.string('U',5); SELECT dbms_random.string('P',2); SELECT dbms_random.string('x',4); SELECT dbms_random.string('a',2); SELECT dbms_random.string('l',3); SELECT dbms_random.seed(5); SELECT dbms_random.value()::numeric(10, 8); SELECT dbms_random.value(10,15)::numeric(10, 8); SELECT dbms_random.terminate(); orafce-VERSION_3_9_0/sql/dbms_utility.sql000066400000000000000000000041521362147214200203650ustar00rootroot00000000000000\set ECHO none \pset format unaligned /* * Test for dbms_utility.format_call_stack(char mode). * Mode is hex. * The callstack returned is passed to regex_replace function. * Regex_replace replaces the function oid from the stack with zero. * This is done to avoid random results due to different oids generated. * Also the line number and () of the function is removed since it is different * across different pg version. */ CREATE OR REPLACE FUNCTION checkHexCallStack() returns text as $$ DECLARE stack text; BEGIN select * INTO stack from dbms_utility.format_call_stack('o'); select * INTO stack from regexp_replace(stack,'[ 0-9a-fA-F]{4}[0-9a-fA-F]{4}',' 0','g'); select * INTO stack from regexp_replace(stack,'[45()]','','g'); return stack; END; $$ LANGUAGE plpgsql; /* * Test for dbms_utility.format_call_stack(char mode). * Mode is integer. */ CREATE OR REPLACE FUNCTION checkIntCallStack() returns text as $$ DECLARE stack text; BEGIN select * INTO stack from dbms_utility.format_call_stack('p'); select * INTO stack from regexp_replace(stack,'[ 0-9]{3}[0-9]{5}',' 0','g'); select * INTO stack from regexp_replace(stack,'[45()]','','g'); return stack; END; $$ LANGUAGE plpgsql; /* * Test for dbms_utility.format_call_stack(char mode). * Mode is integer with unpadded output. */ CREATE OR REPLACE FUNCTION checkIntUnpaddedCallStack() returns text as $$ DECLARE stack text; BEGIN select * INTO stack from dbms_utility.format_call_stack('s'); select * INTO stack from regexp_replace(stack,'[0-9]{5,}','0','g'); select * INTO stack from regexp_replace(stack,'[45()]','','g'); return stack; END; $$ LANGUAGE plpgsql; select * from checkHexCallStack(); select * from checkIntCallStack(); select * from checkIntUnpaddedCallStack(); DROP FUNCTION checkHexCallStack(); DROP FUNCTION checkIntCallStack(); DROP FUNCTION checkIntUnpaddedCallStack(); orafce-VERSION_3_9_0/sql/files.sql000066400000000000000000000107251362147214200167620ustar00rootroot00000000000000SET client_min_messages = NOTICE; \set VERBOSITY terse \set ECHO all CREATE OR REPLACE FUNCTION gen_file(dir text) RETURNS void AS $$ DECLARE f utl_file.file_type; BEGIN f := utl_file.fopen(dir, 'regress_orafce.txt', 'w'); PERFORM utl_file.put_line(f, 'ABC'); PERFORM utl_file.put_line(f, '123'::numeric); PERFORM utl_file.put_line(f, '-----'); PERFORM utl_file.new_line(f); PERFORM utl_file.put_line(f, '-----'); PERFORM utl_file.new_line(f, 0); PERFORM utl_file.put_line(f, '-----'); PERFORM utl_file.new_line(f, 2); PERFORM utl_file.put_line(f, '-----'); PERFORM utl_file.put(f, 'A'); PERFORM utl_file.put(f, 'B'); PERFORM utl_file.new_line(f); PERFORM utl_file.putf(f, '[1=%s, 2=%s, 3=%s, 4=%s, 5=%s]', '1', '2', '3', '4', '5'); PERFORM utl_file.new_line(f); PERFORM utl_file.put_line(f, '1234567890'); f := utl_file.fclose(f); END; $$ LANGUAGE plpgsql; /* Test functions utl_file.fflush(utl_file.file_type) and * utl_file.get_nextline(utl_file.file_type) * This function tests the positive test case of fflush by reading from the * file after flushing the contents to the file. */ CREATE OR REPLACE FUNCTION checkFlushFile(dir text) RETURNS void AS $$ DECLARE f utl_file.file_type; f1 utl_file.file_type; ret_val text; i integer; BEGIN f := utl_file.fopen(dir, 'regressflush_orafce.txt', 'a'); PERFORM utl_file.put_line(f, 'ABC'); PERFORM utl_file.new_line(f); PERFORM utl_file.put_line(f, '123'::numeric); PERFORM utl_file.new_line(f); PERFORM utl_file.putf(f, '[1=%s, 2=%s, 3=%s, 4=%s, 5=%s]', '1', '2', '3', '4', '5'); PERFORM utl_file.fflush(f); f1 := utl_file.fopen(dir, 'regressflush_orafce.txt', 'r'); ret_val=utl_file.get_nextline(f1); i:=1; WHILE ret_val IS NOT NULL LOOP RAISE NOTICE '[%] >>%<<', i,ret_val; ret_val := utl_file.get_nextline(f1); i:=i+1; END LOOP; RAISE NOTICE '>>%<<', ret_val; f1 := utl_file.fclose(f1); f := utl_file.fclose(f); END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION read_file(dir text) RETURNS void AS $$ DECLARE f utl_file.file_type; BEGIN f := utl_file.fopen(dir, 'regress_orafce.txt', 'r'); FOR i IN 1..11 LOOP RAISE NOTICE '[%] >>%<<', i, utl_file.get_line(f); END LOOP; RAISE NOTICE '>>%<<', utl_file.get_line(f, 4); RAISE NOTICE '>>%<<', utl_file.get_line(f, 4); RAISE NOTICE '>>%<<', utl_file.get_line(f); RAISE NOTICE '>>%<<', utl_file.get_line(f); EXCEPTION -- WHEN no_data_found THEN, 8.1 plpgsql doesn't know no_data_found WHEN others THEN RAISE NOTICE 'finish % ', sqlerrm; RAISE NOTICE 'is_open = %', utl_file.is_open(f); PERFORM utl_file.fclose_all(); RAISE NOTICE 'is_open = %', utl_file.is_open(f); END; $$ LANGUAGE plpgsql; SELECT EXISTS(SELECT * FROM pg_catalog.pg_class where relname='utl_file_dir') AS exists; SELECT EXISTS(SELECT * FROM pg_catalog.pg_type where typname='file_type') AS exists; -- Trying to access a file in path not registered SELECT utl_file.fopen(utl_file.tmpdir(),'sample.txt','r'); -- Trying to access file in a non-existent directory INSERT INTO utl_file.utl_file_dir(dir) VALUES('test_tmp_dir'); SELECT utl_file.fopen('test_tmp_dir','file.txt.','w'); DELETE FROM utl_file.utl_file_dir WHERE dir LIKE 'test_tmp_dir'; -- Add tmpdir() to utl_file_dir table INSERT INTO utl_file.utl_file_dir(dir) VALUES(utl_file.tmpdir()); SELECT count(*) from utl_file.utl_file_dir where dir <> ''; -- Trying to access non-existent file SELECT utl_file.fopen(utl_file.tmpdir(),'non_existent_file.txt','r'); --Other test cases SELECT gen_file(utl_file.tmpdir()); SELECT fexists FROM utl_file.fgetattr(utl_file.tmpdir(), 'regress_orafce.txt'); SELECT utl_file.fcopy(utl_file.tmpdir(), 'regress_orafce.txt', utl_file.tmpdir(), 'regress_orafce2.txt'); SELECT fexists FROM utl_file.fgetattr(utl_file.tmpdir(), 'regress_orafce2.txt'); SELECT utl_file.frename(utl_file.tmpdir(), 'regress_orafce2.txt', utl_file.tmpdir(), 'regress_orafce.txt', true); SELECT fexists FROM utl_file.fgetattr(utl_file.tmpdir(), 'regress_orafce.txt'); SELECT fexists FROM utl_file.fgetattr(utl_file.tmpdir(), 'regress_orafce2.txt'); SELECT read_file(utl_file.tmpdir()); SELECT utl_file.fremove(utl_file.tmpdir(), 'regress_orafce.txt'); SELECT fexists FROM utl_file.fgetattr(utl_file.tmpdir(), 'regress_orafce.txt'); DROP FUNCTION gen_file(text); DROP FUNCTION read_file(text); SELECT checkFlushFile(utl_file.tmpdir()); SELECT utl_file.fremove(utl_file.tmpdir(), 'regressflush_orafce.txt'); DROP FUNCTION checkFlushFile(text); DELETE FROM utl_file.utl_file_dir; orafce-VERSION_3_9_0/sql/init.sql000066400000000000000000000001731362147214200166170ustar00rootroot00000000000000\set ECHO none set client_min_messages TO error; CREATE EXTENSION IF NOT EXISTS orafce; set client_min_messages TO default;orafce-VERSION_3_9_0/sql/nlssort.sql000066400000000000000000000015511362147214200173610ustar00rootroot00000000000000-- Tests for nlssort \set ECHO none SET client_min_messages = error; DROP DATABASE IF EXISTS regression_sort; CREATE DATABASE regression_sort WITH TEMPLATE = template0 ENCODING='SQL_ASCII' LC_COLLATE='C' LC_CTYPE='C'; \c regression_sort SET client_min_messages = error; CREATE EXTENSION orafce; SET client_min_messages = default; CREATE TABLE test_sort (name TEXT); INSERT INTO test_sort VALUES ('red'), ('brown'), ('yellow'), ('Purple'); SELECT * FROM test_sort ORDER BY NLSSORT(name, 'en_US.utf8'); SELECT * FROM test_sort ORDER BY NLSSORT(name, ''); SELECT set_nls_sort('invalid'); SELECT * FROM test_sort ORDER BY NLSSORT(name); SELECT set_nls_sort(''); SELECT * FROM test_sort ORDER BY NLSSORT(name); SELECT set_nls_sort('en_US.utf8'); SELECT * FROM test_sort ORDER BY NLSSORT(name); INSERT INTO test_sort VALUES(NULL); SELECT * FROM test_sort ORDER BY NLSSORT(name); orafce-VERSION_3_9_0/sql/nvarchar2.sql000066400000000000000000000022351362147214200175430ustar00rootroot00000000000000\set VERBOSITY terse SET client_encoding = utf8; -- -- test type modifier related rules -- -- ERROR (typmod >= 1) CREATE TABLE bar (a NVARCHAR2(0)); -- ERROR (number of typmods = 1) CREATE TABLE bar (a NVARCHAR2(10, 1)); -- OK CREATE TABLE bar (a VARCHAR(5000)); CREATE INDEX ON bar(a); -- cleanup DROP TABLE bar; -- OK CREATE TABLE bar (a NVARCHAR2(5)); -- -- test that no value longer than maxlen is allowed -- -- ERROR (length > 5) INSERT INTO bar VALUES ('abcdef'); -- ERROR (length > 5); -- NVARCHAR2 does not truncate blank spaces on implicit coercion INSERT INTO bar VALUES ('abcde '); -- OK INSERT INTO bar VALUES ('abcde'); -- OK INSERT INTO bar VALUES ('abcdef'::NVARCHAR2(5)); -- OK INSERT INTO bar VALUES ('abcde '::NVARCHAR2(5)); --OK INSERT INTO bar VALUES ('abc'::NVARCHAR2(5)); -- -- test whitespace semantics on comparison -- -- equal SELECT 'abcde '::NVARCHAR2(10) = 'abcde '::NVARCHAR2(10); -- not equal SELECT 'abcde '::NVARCHAR2(10) = 'abcde '::NVARCHAR2(10); -- null safe concat (disabled by default) SELECT NULL || 'hello'::varchar2 || NULL; SET orafce.varchar2_null_safe_concat TO true; SELECT NULL || 'hello'::varchar2 || NULL; orafce-VERSION_3_9_0/sql/orafce.sql000066400000000000000000001576561362147214200171360ustar00rootroot00000000000000\set ECHO none SET client_min_messages = warning; SET DATESTYLE TO ISO; SET client_encoding = utf8; \set ECHO all -- -- test built-in date type oracle compatibility functions -- SELECT add_months ('2003-08-01', 3); SELECT add_months ('2003-08-01', -3); SELECT add_months ('2003-08-21', -3); SELECT add_months ('2003-01-31', 1); SELECT add_months ('2008-02-28', 1); SELECT add_months ('2008-02-29', 1); SELECT add_months ('2008-01-31', 12); SELECT add_months ('2008-01-31', -12); SELECT add_months ('2008-01-31', 95903); SELECT add_months ('2008-01-31', -80640); SELECT add_months ('03-21-2008',3); SELECT add_months ('21-MAR-2008',3); SELECT add_months ('21-MAR-08',3); SELECT add_months ('2008-MAR-21',3); SELECT add_months ('March 21,2008',3); SELECT add_months('03/21/2008',3); SELECT add_months('20080321',3); SELECT add_months('080321',3); SET search_path TO oracle,"$user", public, pg_catalog; SELECT add_months ('2003-08-01 10:12:21', 3); SELECT add_months ('2003-08-01 10:21:21', -3); SELECT add_months ('2003-08-21 12:21:21', -3); SELECT add_months ('2003-01-31 01:12:45', 1); SELECT add_months ('2008-02-28 02:12:12', 1); SELECT add_months ('2008-02-29 12:12:12', 1); SELECT add_months ('2008-01-31 11:11:21', 12); SELECT add_months ('2008-01-31 11:21:21', -12); SELECT add_months ('2008-01-31 12:12:12', 95903); SELECT add_months ('2008-01-31 11:32:12', -80640); SELECT add_months ('03-21-2008 08:12:22',3); SELECT add_months ('21-MAR-2008 06:02:12',3); SELECT add_months ('21-MAR-08 12:11:22',3); SELECT add_months ('2008-MAR-21 11:32:43',3); SELECT add_months ('March 21,2008 12:32:12',3); SELECT add_months('03/21/2008 12:32:12',3); SELECT add_months('20080321 123244',3); SELECT add_months('080321 121212',3); SET search_path TO default; SELECT last_day(to_date('2003/03/15', 'yyyy/mm/dd')); SELECT last_day(to_date('2003/02/03', 'yyyy/mm/dd')); SELECT last_day(to_date('2004/02/03', 'yyyy/mm/dd')); SELECT last_day('1900-02-01'); SELECT last_day('2000-02-01'); SELECT last_day('2007-02-01'); SELECT last_day('2008-02-01'); SET search_path TO oracle,"$user", public, pg_catalog; SELECT last_day(to_date('2003/03/15 11:12:21', 'yyyy/mm/dd hh:mi:ss')); SELECT last_day(to_date('2003/02/03 10:21:32', 'yyyy/mm/dd hh:mi:ss')); SELECT last_day(to_date('2004/02/03 11:32:12', 'yyyy/mm/dd hh:mi:ss')); SELECT last_day('1900-02-01 12:12:11'); SELECT last_day('2000-02-01 121143'); SELECT last_day('2007-02-01 12:21:33'); SELECT last_day('2008-02-01 121212'); SET search_path TO default; SELECT next_day ('2003-08-01', 'TUESDAY'); SELECT next_day ('2003-08-06', 'WEDNESDAY'); SELECT next_day ('2003-08-06', 'SUNDAY'); SELECT next_day ('2008-01-01', 'sun'); SELECT next_day ('2008-01-01', 'sunAAA'); SELECT next_day ('2008-01-01', 1); SELECT next_day ('2008-01-01', 7); SET search_path TO oracle,"$user", public, pg_catalog; SELECT next_day ('2003-08-01 111211', 'TUESDAY'); SELECT next_day ('2003-08-06 10:11:43', 'WEDNESDAY'); SELECT next_day ('2003-08-06 11:21:21', 'SUNDAY'); SELECT next_day ('2008-01-01 111343', 'sun'); SELECT next_day ('2008-01-01 121212', 'sunAAA'); SELECT next_day ('2008-01-01 111213', 1); SELECT next_day ('2008-01-01 11:12:13', 7); SET search_path TO default; SELECT months_between (to_date ('2003/01/01', 'yyyy/mm/dd'), to_date ('2003/03/14', 'yyyy/mm/dd')); SELECT months_between (to_date ('2003/07/01', 'yyyy/mm/dd'), to_date ('2003/03/14', 'yyyy/mm/dd')); SELECT months_between (to_date ('2003/07/02', 'yyyy/mm/dd'), to_date ('2003/07/02', 'yyyy/mm/dd')); SELECT months_between (to_date ('2003/08/02', 'yyyy/mm/dd'), to_date ('2003/06/02', 'yyyy/mm/dd')); SELECT months_between ('2007-02-28', '2007-04-30'); SELECT months_between ('2008-01-31', '2008-02-29'); SELECT months_between ('2008-02-29', '2008-03-31'); SELECT months_between ('2008-02-29', '2008-04-30'); SELECT trunc(months_between('21-feb-2008', '2008-02-29')); SET search_path TO oracle,"$user", public, pg_catalog; SELECT months_between (to_date ('2003/01/01 12:12:12', 'yyyy/mm/dd h24:mi:ss'), to_date ('2003/03/14 11:11:11', 'yyyy/mm/dd h24:mi:ss')); SELECT months_between (to_date ('2003/07/01 10:11:11', 'yyyy/mm/dd h24:mi:ss'), to_date ('2003/03/14 10:12:12', 'yyyy/mm/dd h24:mi:ss')); SELECT months_between (to_date ('2003/07/02 11:21:21', 'yyyy/mm/dd h24:mi:ss'), to_date ('2003/07/02 11:11:11', 'yyyy/mm/dd h24:mi:ss')); SELECT months_between (to_timestamp ('2003/08/02 10:11:12', 'yyyy/mm/dd h24:mi:ss'), to_date ('2003/06/02 10:10:11', 'yyyy/mm/dd h24:mi:ss')); SELECT months_between ('2007-02-28 111111', '2007-04-30 112121'); SELECT months_between ('2008-01-31 11:32:11', '2008-02-29 11:12:12'); SELECT months_between ('2008-02-29 10:11:13', '2008-03-31 10:12:11'); SELECT months_between ('2008-02-29 111111', '2008-04-30 12:12:12'); SELECT trunc(months_between('21-feb-2008 12:11:11', '2008-02-29 11:11:11')); SET search_path TO default; select length('jmenuji se Pavel Stehule'),dbms_pipe.pack_message('jmenuji se Pavel Stehule'); select length('a bydlim ve Skalici'),dbms_pipe.pack_message('a bydlim ve Skalici'); select dbms_pipe.send_message('pavel',0,1); select dbms_pipe.send_message('pavel',0,2); select dbms_pipe.receive_message('pavel',0); select '>>>>'||dbms_pipe.unpack_message_text()||'<<<<'; select '>>>>'||dbms_pipe.unpack_message_text()||'<<<<'; select dbms_pipe.receive_message('pavel',0); select dbms_pipe.purge('bob'); select dbms_pipe.reset_buffer(); select dbms_pipe.pack_message('012345678901234+1'); select dbms_pipe.send_message('bob',0,10); select dbms_pipe.pack_message('012345678901234+2'); select dbms_pipe.send_message('bob',0,10); select dbms_pipe.pack_message('012345678901234+3'); select dbms_pipe.send_message('bob',0,10); -------------------------------------------- select dbms_pipe.receive_message('bob',0); select dbms_pipe.unpack_message_text(); select dbms_pipe.receive_message('bob',0); select dbms_pipe.unpack_message_text(); select dbms_pipe.receive_message('bob',0); select dbms_pipe.unpack_message_text(); select dbms_pipe.unique_session_name() LIKE 'PG$PIPE$%'; select dbms_pipe.pack_message('012345678901234-1'); select dbms_pipe.send_message('bob',0,10); select dbms_pipe.receive_message('bob',0); select dbms_pipe.unpack_message_text(); select dbms_pipe.pack_message('012345678901234-2'); select dbms_pipe.send_message('bob',0,10); select dbms_pipe.send_message('bob',0,10); select dbms_pipe.receive_message('bob',0); select dbms_pipe.unpack_message_text(); select dbms_pipe.pack_message(TO_DATE('2006-10-11', 'YYYY-MM-DD')); select dbms_pipe.send_message('test_date'); select dbms_pipe.receive_message('test_date'); select dbms_pipe.next_item_type(); select dbms_pipe.unpack_message_date(); select dbms_pipe.pack_message(to_timestamp('2008-10-30 01:23:45', 'YYYY-MM-DD HH24:MI:SS')); select dbms_pipe.send_message('test_timestamp'); select dbms_pipe.receive_message('test_timestamp'); select dbms_pipe.next_item_type(); select to_char(dbms_pipe.unpack_message_timestamp(), 'YYYY-MM-DD HH24:MI:SS'); select dbms_pipe.pack_message(6262626262::numeric); select dbms_pipe.send_message('test_int'); select dbms_pipe.receive_message('test_int'); select dbms_pipe.next_item_type(); select dbms_pipe.unpack_message_number(); select dbms_pipe.purge('bob'); select name, items, "limit", private, owner from dbms_pipe.db_pipes where name = 'bob'; select PLVstr.betwn('Harry and Sally are very happy', 7, 9); select PLVstr.betwn('Harry and Sally are very happy', 7, 9, FALSE); select PLVstr.betwn('Harry and Sally are very happy', -3, -1); select PLVstr.betwn('Harry and Sally are very happy', 'a', 'ry'); select PLVstr.betwn('Harry and Sally are very happy', 'a', 'ry', 1,1,FALSE,FALSE); select PLVstr.betwn('Harry and Sally are very happy', 'a', 'ry', 2,1,TRUE,FALSE); select PLVstr.betwn('Harry and Sally are very happy', 'a', 'y', 2,1); select PLVstr.betwn('Harry and Sally are very happy', 'a', 'a', 2, 2); select PLVstr.betwn('Harry and Sally are very happy', 'a', 'a', 2, 3, FALSE,FALSE); select plvsubst.string('My name is %s %s.', ARRAY['Pavel','Stěhule']); select plvsubst.string('My name is % %.', ARRAY['Pavel','Stěhule'], '%'); select plvsubst.string('My name is %s.', ARRAY['Stěhule']); select plvsubst.string('My name is %s %s.', 'Pavel,Stěhule'); select plvsubst.string('My name is %s %s.', 'Pavel|Stěhule','|'); select plvsubst.string('My name is %s.', 'Stěhule'); select plvsubst.string('My name is %s.', ''); select plvsubst.string('My name is empty.', ''); select round(to_date ('22-AUG-03', 'DD-MON-YY'),'YEAR') = to_date ('01-JAN-04', 'DD-MON-YY'); select round(to_date ('22-AUG-03', 'DD-MON-YY'),'Q') = to_date ('01-OCT-03', 'DD-MON-YY'); select round(to_date ('22-AUG-03', 'DD-MON-YY'),'MONTH') = to_date ('01-SEP-03', 'DD-MON-YY'); select round(to_date ('22-AUG-03', 'DD-MON-YY'),'DDD') = to_date ('22-AUG-03', 'DD-MON-YY'); select round(to_date ('22-AUG-03', 'DD-MON-YY'),'DAY') = to_date ('24-AUG-03', 'DD-MON-YY'); select trunc(to_date('22-AUG-03', 'DD-MON-YY'), 'YEAR') = to_date ('01-JAN-03', 'DD-MON-YY'); select trunc(to_date('22-AUG-03', 'DD-MON-YY'), 'Q') = to_date ('01-JUL-03', 'DD-MON-YY'); select trunc(to_date('22-AUG-03', 'DD-MON-YY'), 'MONTH') = to_date ('01-AUG-03', 'DD-MON-YY'); select trunc(to_date('22-AUG-03', 'DD-MON-YY'), 'DDD') = to_date ('22-AUG-03', 'DD-MON-YY'); select trunc(to_date('22-AUG-03', 'DD-MON-YY'), 'DAY') = to_date ('17-AUG-03', 'DD-MON-YY'); select trunc(TIMESTAMP WITH TIME ZONE '2004-10-19 10:23:54+02','YEAR') = '2004-01-01 00:00:00-08'; select trunc(TIMESTAMP WITH TIME ZONE '2004-10-19 10:23:54+02','Q') = '2004-10-01 00:00:00-07'; select trunc(TIMESTAMP WITH TIME ZONE '2004-10-19 10:23:54+02','MONTH') = '2004-10-01 00:00:00-07'; select trunc(TIMESTAMP WITH TIME ZONE '2004-10-19 10:23:54+02','DDD') = '2004-10-19 00:00:00-07'; select trunc(TIMESTAMP WITH TIME ZONE '2004-10-19 10:23:54+02','DAY') = '2004-10-17 00:00:00-07'; select trunc(TIMESTAMP WITH TIME ZONE '2004-10-19 10:23:54+02','HH') = '2004-10-19 01:00:00-07'; select trunc(TIMESTAMP WITH TIME ZONE '2004-10-19 10:23:54+02','MI') = '2004-10-19 01:23:00-07'; select next_day(to_date('01-Aug-03', 'DD-MON-YY'), 'TUESDAY') = to_date ('05-Aug-03', 'DD-MON-YY'); select next_day(to_date('06-Aug-03', 'DD-MON-YY'), 'WEDNESDAY') = to_date ('13-Aug-03', 'DD-MON-YY'); select next_day(to_date('06-Aug-03', 'DD-MON-YY'), 'SUNDAY') = to_date ('10-Aug-03', 'DD-MON-YY'); SET search_path TO oracle,"$user", public, pg_catalog; select next_day(to_date('01-Aug-03 101111', 'DD-MON-YY h24miss'), 'TUESDAY') = to_date ('05-Aug-03 101111', 'DD-MON-YY h24miss'); select next_day(to_date('06-Aug-03 10:12:13', 'DD-MON-YY H24:MI:SS'), 'WEDNESDAY') = to_date ('13-Aug-03 10:12:13', 'DD-MON-YY H24:MI:SS'); select next_day(to_date('06-Aug-03 11:11:11', 'DD-MON-YY HH:MI:SS'), 'SUNDAY') = to_date ('10-Aug-03 11:11:11', 'DD-MON-YY HH:MI:SS'); SET search_path TO default; select instr('Tech on the net', 'e') =2; select instr('Tech on the net', 'e', 1, 1) = 2; select instr('Tech on the net', 'e', 1, 2) = 11; select instr('Tech on the net', 'e', 1, 3) = 14; select instr('Tech on the net', 'e', -3, 2) = 2; select instr('abc', NULL) IS NULL; select 1 = instr('abc', ''); select 1 = instr('abc', 'a'); select 3 = instr('abc', 'c'); select 0 = instr('abc', 'z'); select 1 = instr('abcabcabc', 'abca', 1); select 4 = instr('abcabcabc', 'abca', 2); select 0 = instr('abcabcabc', 'abca', 7); select 0 = instr('abcabcabc', 'abca', 9); select 4 = instr('abcabcabc', 'abca', -1); select 1 = instr('abcabcabc', 'abca', -8); select 1 = instr('abcabcabc', 'abca', -9); select 0 = instr('abcabcabc', 'abca', -10); select 1 = instr('abcabcabc', 'abca', 1, 1); select 4 = instr('abcabcabc', 'abca', 1, 2); select 0 = instr('abcabcabc', 'abca', 1, 3); select oracle.substr('This is a test', 6, 2) = 'is'; select oracle.substr('This is a test', 6) = 'is a test'; select oracle.substr('TechOnTheNet', 1, 4) = 'Tech'; select oracle.substr('TechOnTheNet', -3, 3) = 'Net'; select oracle.substr('TechOnTheNet', -6, 3) = 'The'; select oracle.substr('TechOnTheNet', -8, 2) = 'On'; select oracle.substr('TechOnTheNet', -8, 0) = ''; select oracle.substr('TechOnTheNet', -8, -1) = ''; select oracle.substr(1234567,3.6::smallint)='4567'; select oracle.substr(1234567,3.6::int)='4567'; select oracle.substr(1234567,3.6::bigint)='4567'; select oracle.substr(1234567,3.6::numeric)='34567'; select oracle.substr(1234567,-1)='7'; select oracle.substr(1234567,3.6::smallint,2.6)='45'; select oracle.substr(1234567,3.6::smallint,2.6::smallint)='456'; select oracle.substr(1234567,3.6::smallint,2.6::int)='456'; select oracle.substr(1234567,3.6::smallint,2.6::bigint)='456'; select oracle.substr(1234567,3.6::smallint,2.6::numeric)='45'; select oracle.substr(1234567,3.6::int,2.6::smallint)='456'; select oracle.substr(1234567,3.6::int,2.6::int)='456'; select oracle.substr(1234567,3.6::int,2.6::bigint)='456'; select oracle.substr(1234567,3.6::int,2.6::numeric)='45'; select oracle.substr(1234567,3.6::bigint,2.6::smallint)='456'; select oracle.substr(1234567,3.6::bigint,2.6::int)='456'; select oracle.substr(1234567,3.6::bigint,2.6::bigint)='456'; select oracle.substr(1234567,3.6::bigint,2.6::numeric)='45'; select oracle.substr(1234567,3.6::numeric,2.6::smallint)='345'; select oracle.substr(1234567,3.6::numeric,2.6::int)='345'; select oracle.substr(1234567,3.6::numeric,2.6::bigint)='345'; select oracle.substr(1234567,3.6::numeric,2.6::numeric)='34'; select oracle.substr('abcdef'::varchar,3.6::smallint)='def'; select oracle.substr('abcdef'::varchar,3.6::int)='def'; select oracle.substr('abcdef'::varchar,3.6::bigint)='def'; select oracle.substr('abcdef'::varchar,3.6::numeric)='cdef'; select oracle.substr('abcdef'::varchar,3.5::int,3.5::int)='def'; select oracle.substr('abcdef'::varchar,3.5::numeric,3.5::numeric)='cde'; select oracle.substr('abcdef'::varchar,3.5::numeric,3.5::int)='cdef'; select concat('Tech on', ' the Net') = 'Tech on the Net'; select concat('a', 'b') = 'ab'; select concat('a', NULL) = 'a'; select concat(NULL, 'b') = 'b'; select concat('a', 2) = 'a2'; select concat(1, 'b') = '1b'; select concat(1, 2) = '12'; select concat(1, NULL) = '1'; select concat(NULL, 2) = '2'; select nvl('A'::text, 'B'); select nvl(NULL::text, 'B'); select nvl(NULL::text, NULL); select nvl(1, 2); select nvl(NULL, 2); select nvl2('A'::text, 'B', 'C'); select nvl2(NULL::text, 'B', 'C'); select nvl2('A'::text, NULL, 'C'); select nvl2(NULL::text, 'B', NULL); select nvl2(1, 2, 3); select nvl2(NULL, 2, 3); select lnnvl(true); select lnnvl(false); select lnnvl(NULL); select decode(1, 1, 100, 2, 200); select decode(2, 1, 100, 2, 200); select decode(3, 1, 100, 2, 200); select decode(3, 1, 100, 2, 200, 300); select decode(NULL, 1, 100, NULL, 200, 300); select decode('1'::text, '1', 100, '2', 200); select decode(2, 1, 'ABC', 2, 'DEF'); select decode('2009-02-05'::date, '2009-02-05', 'ok'); select decode('2009-02-05 01:02:03'::timestamp, '2009-02-05 01:02:03', 'ok'); -- For type 'bpchar' select decode('a'::bpchar, 'a'::bpchar,'postgres'::bpchar); select decode('c'::bpchar, 'a'::bpchar,'postgres'::bpchar); select decode('a'::bpchar, 'a'::bpchar,'postgres'::bpchar,'default value'::bpchar); select decode('c', 'a'::bpchar,'postgres'::bpchar,'default value'::bpchar); select decode('a'::bpchar, 'a'::bpchar,'postgres'::bpchar,'b'::bpchar,'database'::bpchar); select decode('d'::bpchar, 'a'::bpchar,'postgres'::bpchar,'b'::bpchar,'database'::bpchar); select decode('a'::bpchar, 'a'::bpchar,'postgres'::bpchar,'b'::bpchar,'database'::bpchar,'default value'::bpchar); select decode('d'::bpchar, 'a'::bpchar,'postgres'::bpchar,'b'::bpchar,'database'::bpchar,'default value'::bpchar); select decode('a'::bpchar, 'a'::bpchar,'postgres'::bpchar,'b'::bpchar,'database'::bpchar, 'c'::bpchar, 'system'::bpchar); select decode('d'::bpchar, 'a'::bpchar,'postgres'::bpchar,'b'::bpchar,'database'::bpchar, 'c'::bpchar, 'system'::bpchar); select decode('a'::bpchar, 'a'::bpchar,'postgres'::bpchar,'b'::bpchar,'database'::bpchar, 'c'::bpchar, 'system'::bpchar,'default value'::bpchar); select decode('d'::bpchar, 'a'::bpchar,'postgres'::bpchar,'b'::bpchar,'database'::bpchar, 'c'::bpchar, 'system'::bpchar,'default value'::bpchar); select decode(NULL, 'a'::bpchar, 'postgres'::bpchar, NULL,'database'::bpchar); select decode(NULL, 'a'::bpchar, 'postgres'::bpchar, 'b'::bpchar,'database'::bpchar); select decode(NULL, 'a'::bpchar, 'postgres'::bpchar, NULL,'database'::bpchar,'default value'::bpchar); select decode(NULL, 'a'::bpchar, 'postgres'::bpchar, 'b'::bpchar,'database'::bpchar,'default value'::bpchar); -- For type 'bigint' select decode(2147483651::bigint, 2147483650::bigint,2147483650::bigint); select decode(2147483653::bigint, 2147483651::bigint,2147483650::bigint); select decode(2147483653::bigint, 2147483651::bigint,2147483650::bigint,9999999999::bigint); select decode(2147483653::bigint, 2147483651::bigint,2147483650::bigint,9999999999::bigint); select decode(2147483651::bigint, 2147483651::bigint,2147483650::bigint,2147483652::bigint,2147483651::bigint); select decode(2147483654::bigint, 2147483651::bigint,2147483650::bigint,2147483652::bigint,2147483651::bigint); select decode(2147483651::bigint, 2147483651::bigint,2147483650::bigint,2147483652::bigint,2147483651::bigint,9999999999::bigint); select decode(2147483654::bigint, 2147483651::bigint,2147483650::bigint,2147483652::bigint,2147483651::bigint,9999999999::bigint); select decode(2147483651::bigint, 2147483651::bigint,2147483650::bigint, 2147483652::bigint,2147483651::bigint, 2147483653::bigint, 2147483652::bigint); select decode(2147483654::bigint, 2147483651::bigint,2147483650::bigint, 2147483652::bigint,2147483651::bigint, 2147483653::bigint, 2147483652::bigint); select decode(2147483651::bigint, 2147483651::bigint,2147483650::bigint, 2147483652::bigint,2147483651::bigint, 2147483653::bigint, 2147483652::bigint,9999999999::bigint); select decode(2147483654::bigint, 2147483651::bigint,2147483650::bigint, 2147483652::bigint,2147483651::bigint, 2147483653::bigint, 2147483652::bigint,9999999999::bigint); select decode(NULL, 2147483651::bigint, 2147483650::bigint, NULL,2147483651::bigint); select decode(NULL, 2147483651::bigint, 2147483650::bigint, 2147483652::bigint,2147483651::bigint); select decode(NULL, 2147483651::bigint, 2147483650::bigint, NULL,2147483651::bigint,9999999999::bigint); select decode(NULL, 2147483651::bigint, 2147483650::bigint, 2147483652::bigint,2147483651::bigint,9999999999::bigint); -- For type 'numeric' select decode(12.001::numeric(5,3), 12.001::numeric(5,3),214748.3650::numeric(10,4)); select decode(12.003::numeric(5,3), 12.001::numeric(5,3),214748.3650::numeric(10,4)); select decode(12.001::numeric(5,3), 12.001::numeric(5,3),214748.3650::numeric(10,4),999999.9999::numeric(10,4)); select decode(12.003::numeric(5,3), 12.001::numeric(5,3),214748.3650::numeric(10,4),999999.9999::numeric(10,4)); select decode(12.001::numeric(5,3), 12.001::numeric(5,3),214748.3650::numeric(10,4),12.002::numeric(5,3),214748.3651::numeric(10,4)); select decode(12.004::numeric(5,3), 12.001::numeric(5,3),214748.3650::numeric(10,4),12.002::numeric(5,3),214748.3651::numeric(10,4)); select decode(12.001::numeric(5,3), 12.001::numeric(5,3),214748.3650::numeric(10,4),12.002::numeric(5,3),214748.3651::numeric(10,4),999999.9999::numeric(10,4)); select decode(12.004::numeric(5,3), 12.001::numeric(5,3),214748.3650::numeric(10,4),12.002::numeric(5,3),214748.3651::numeric(10,4),999999.9999::numeric(10,4)); select decode(12.001::numeric(5,3), 12.001::numeric(5,3),214748.3650::numeric(10,4),12.002::numeric(5,3),214748.3651::numeric(10,4), 12.003::numeric(5,3), 214748.3652::numeric(10,4)); select decode(12.004::numeric(5,3), 12.001::numeric(5,3),214748.3650::numeric(10,4),12.002::numeric(5,3),214748.3651::numeric(10,4), 12.003::numeric(5,3), 214748.3652::numeric(10,4)); select decode(12.001::numeric(5,3), 12.001::numeric(5,3),214748.3650::numeric(10,4),12.002::numeric(5,3),214748.3651::numeric(10,4), 12.003::numeric(5,3), 214748.3652::numeric(10,4),999999.9999::numeric(10,4)); select decode(12.004::numeric(5,3), 12.001::numeric(5,3),214748.3650::numeric(10,4),12.002::numeric(5,3),214748.3651::numeric(10,4), 12.003::numeric(5,3), 214748.3652::numeric(10,4),999999.9999::numeric(10,4)); select decode(NULL, 12.001::numeric(5,3), 214748.3650::numeric(10,4), NULL,214748.3651::numeric(10,4)); select decode(NULL, 12.001::numeric(5,3), 214748.3650::numeric(10,4), 12.002::numeric(5,3),214748.3651::numeric(10,4)); select decode(NULL, 12.001::numeric(5,3), 214748.3650::numeric(10,4), NULL,214748.3651::numeric(10,4),999999.9999::numeric(10,4)); select decode(NULL, 12.001::numeric(5,3), 214748.3650::numeric(10,4), 12.002::numeric(5,3),214748.3651::numeric(10,4),999999.9999::numeric(10,4)); --For type 'date' select decode('2020-01-01'::date, '2020-01-01'::date,'2012-12-20'::date); select decode('2020-01-03'::date, '2020-01-01'::date,'2012-12-20'::date); select decode('2020-01-01'::date, '2020-01-01'::date,'2012-12-20'::date,'2012-12-21'::date); select decode('2020-01-03'::date, '2020-01-01'::date,'2012-12-20'::date,'2012-12-21'::date); select decode('2020-01-01'::date, '2020-01-01'::date,'2012-12-20'::date,'2020-01-02'::date,'2012-12-21'::date); select decode('2020-01-04'::date, '2020-01-01'::date,'2012-12-20'::date,'2020-01-02'::date,'2012-12-21'::date); select decode('2020-01-01'::date, '2020-01-01'::date,'2012-12-20'::date,'2020-01-02'::date,'2012-12-21'::date,'2012-12-31'::date); select decode('2020-01-04'::date, '2020-01-01'::date,'2012-12-20'::date,'2020-01-02'::date,'2012-12-21'::date,'2012-12-31'::date); select decode('2020-01-01'::date, '2020-01-01'::date,'2012-12-20'::date,'2020-01-02'::date,'2012-12-21'::date, '2020-01-03'::date, '2012-12-31'::date); select decode('2020-01-04'::date, '2020-01-01'::date,'2012-12-20'::date,'2020-01-02'::date,'2012-12-21'::date, '2020-01-03'::date, '2012-12-31'::date); select decode('2020-01-01'::date, '2020-01-01'::date,'2012-12-20'::date,'2020-01-02'::date,'2012-12-21'::date, '2020-01-03'::date, '2012-12-31'::date,'2013-01-01'::date); select decode('2020-01-04'::date, '2020-01-01'::date,'2012-12-20'::date,'2020-01-02'::date,'2012-12-21'::date, '2020-01-03'::date, '2012-12-31'::date,'2013-01-01'::date); select decode(NULL, '2020-01-01'::date, '2012-12-20'::date, NULL,'2012-12-21'::date); select decode(NULL, '2020-01-01'::date, '2012-12-20'::date, '2020-01-02'::date,'2012-12-21'::date); select decode(NULL, '2020-01-01'::date, '2012-12-20'::date, NULL,'2012-12-21'::date,'2012-12-31'::date); select decode(NULL, '2020-01-01'::date, '2012-12-20'::date, '2020-01-02'::date,'2012-12-21'::date,'2012-12-31'::date); -- For type 'time' select decode('01:00:01'::time, '01:00:01'::time,'09:00:00'::time); select decode('01:00:03'::time, '01:00:01'::time,'09:00:00'::time); select decode('01:00:01'::time, '01:00:01'::time,'09:00:00'::time,'00:00:00'::time); select decode('01:00:03'::time, '01:00:01'::time,'09:00:00'::time,'00:00:00'::time); select decode('01:00:01'::time, '01:00:01'::time,'09:00:00'::time,'01:00:02'::time,'12:00:00'::time); select decode('01:00:04'::time, '01:00:01'::time,'09:00:00'::time,'01:00:02'::time,'12:00:00'::time); select decode('01:00:01'::time, '01:00:01'::time,'09:00:00'::time,'01:00:02'::time,'12:00:00'::time,'00:00:00'::time); select decode('01:00:04'::time, '01:00:01'::time,'09:00:00'::time,'01:00:01'::time,'12:00:00'::time,'00:00:00'::time); select decode('01:00:01'::time, '01:00:01'::time,'09:00:00'::time,'01:00:02'::time,'12:00:00'::time, '01:00:03'::time, '15:00:00'::time); select decode('01:00:04'::time, '01:00:01'::time,'09:00:00'::time,'01:00:02'::time,'12:00:00'::time, '01:00:03'::time, '15:00:00'::time); select decode('01:00:01'::time, '01:00:01'::time,'09:00:00'::time,'01:00:02'::time,'12:00:00'::time, '01:00:03'::time, '15:00:00'::time,'00:00:00'::time); select decode('01:00:04'::time, '01:00:01'::time,'09:00:00'::time,'01:00:02'::time,'12:00:00'::time, '01:00:03'::time, '15:00:00'::time,'00:00:00'::time); select decode(NULL, '01:00:01'::time, '09:00:00'::time, NULL,'12:00:00'::time); select decode(NULL, '01:00:01'::time, '09:00:00'::time, '01:00:02'::time,'12:00:00'::time); select decode(NULL, '01:00:01'::time, '09:00:00'::time, NULL,'12:00:00'::time,'00:00:00'::time); select decode(NULL, '01:00:01'::time, '09:00:00'::time, '01:00:02'::time,'12:00:00'::time,'00:00:00'::time); -- For type 'timestamp' select decode('2020-01-01 01:00:01'::timestamp, '2020-01-01 01:00:01'::timestamp,'2012-12-20 09:00:00'::timestamp); select decode('2020-01-03 01:00:01'::timestamp, '2020-01-01 01:00:01'::timestamp,'2012-12-20 09:00:00'::timestamp); select decode('2020-01-01 01:00:01'::timestamp, '2020-01-01 01:00:01'::timestamp,'2012-12-20 09:00:00'::timestamp,'2012-12-20 00:00:00'::timestamp); select decode('2020-01-03 01:00:01'::timestamp, '2020-01-01 01:00:01'::timestamp,'2012-12-20 09:00:00'::timestamp,'2012-12-20 00:00:00'::timestamp); select decode('2020-01-01 01:00:01'::timestamp, '2020-01-01 01:00:01'::timestamp,'2012-12-20 09:00:00'::timestamp,'2020-01-02 01:00:01'::timestamp,'2012-12-20 12:00:00'::timestamp); select decode('2020-01-04 01:00:01'::timestamp, '2020-01-01 01:00:01'::timestamp,'2012-12-20 09:00:00'::timestamp,'2020-01-02 01:00:01'::timestamp,'2012-12-20 12:00:00'::timestamp); select decode('2020-01-01 01:00:01'::timestamp, '2020-01-01 01:00:01'::timestamp,'2012-12-20 09:00:00'::timestamp,'2020-01-02 01:00:01'::timestamp,'2012-12-20 12:00:00'::timestamp,'2012-12-20 00:00:00'::timestamp); select decode('2020-01-04 01:00:01'::timestamp, '2020-01-01 01:00:01'::timestamp,'2012-12-20 09:00:00'::timestamp,'2020-01-02 01:00:01'::timestamp,'2012-12-20 12:00:00'::timestamp,'2012-12-20 00:00:00'::timestamp); select decode('2020-01-01 01:00:01'::timestamp, '2020-01-01 01:00:01'::timestamp,'2012-12-20 09:00:00'::timestamp,'2020-01-02 01:00:01'::timestamp,'2012-12-20 12:00:00'::timestamp, '2020-01-03 01:00:01'::timestamp, '2012-12-20 15:00:00'::timestamp); select decode('2020-01-04 01:00:01'::timestamp, '2020-01-01 01:00:01'::timestamp,'2012-12-20 09:00:00'::timestamp,'2020-01-02 01:00:01'::timestamp,'2012-12-20 12:00:00'::timestamp, '2020-01-03 01:00:01'::timestamp, '2012-12-20 15:00:00'::timestamp); select decode('2020-01-01 01:00:01'::timestamp, '2020-01-01 01:00:01'::timestamp,'2012-12-20 09:00:00'::timestamp,'2020-01-02 01:00:01'::timestamp,'2012-12-20 12:00:00'::timestamp, '2020-01-03 01:00:01'::timestamp, '2012-12-20 15:00:00'::timestamp,'2012-12-20 00:00:00'::timestamp); select decode('2020-01-04 01:00:01'::timestamp, '2020-01-01 01:00:01'::timestamp,'2012-12-20 09:00:00'::timestamp,'2020-01-02 01:00:01'::timestamp,'2012-12-20 12:00:00'::timestamp, '2020-01-03 01:00:01'::timestamp, '2012-12-20 15:00:00'::timestamp,'2012-12-20 00:00:00'::timestamp); select decode(NULL, '2020-01-01 01:00:01'::timestamp, '2012-12-20 09:00:00'::timestamp, NULL,'2012-12-20 12:00:00'::timestamp); select decode(NULL, '2020-01-01 01:00:01'::timestamp, '2012-12-20 09:00:00'::timestamp, '2020-01-02 01:00:01'::timestamp,'2012-12-20 12:00:00'::timestamp); select decode(NULL, '2020-01-01 01:00:01'::timestamp, '2012-12-20 09:00:00'::timestamp, NULL,'2012-12-20 12:00:00'::timestamp,'2012-12-20 00:00:00'::timestamp); select decode(NULL, '2020-01-01 01:00:01'::timestamp, '2012-12-20 09:00:00'::timestamp, '2020-01-02 01:00:01'::timestamp,'2012-12-20 12:00:00'::timestamp,'2012-12-20 00:00:00'::timestamp); -- For type 'timestamptz' select decode('2020-01-01 01:00:01-08'::timestamptz, '2020-01-01 01:00:01-08'::timestamptz,'2012-12-20 09:00:00-08'::timestamptz); select decode('2020-01-03 01:00:01-08'::timestamptz, '2020-01-01 01:00:01-08'::timestamptz,'2012-12-20 09:00:00-08'::timestamptz); select decode('2020-01-01 01:00:01-08'::timestamptz, '2020-01-01 01:00:01-08'::timestamptz,'2012-12-20 09:00:00-08'::timestamptz,'2012-12-20 00:00:00-08'::timestamptz); select decode('2020-01-03 01:00:01-08'::timestamptz, '2020-01-01 01:00:01-08'::timestamptz,'2012-12-20 09:00:00-08'::timestamptz,'2012-12-20 00:00:00-08'::timestamptz); select decode('2020-01-01 01:00:01-08'::timestamptz, '2020-01-01 01:00:01-08'::timestamptz,'2012-12-20 09:00:00-08'::timestamptz,'2020-01-02 01:00:01-08'::timestamptz,'2012-12-20 12:00:00-08'::timestamptz); select decode('2020-01-04 01:00:01-08'::timestamptz, '2020-01-01 01:00:01-08'::timestamptz,'2012-12-20 09:00:00-08'::timestamptz,'2020-01-02 01:00:01-08'::timestamptz,'2012-12-20 12:00:00-08'::timestamptz); select decode('2020-01-01 01:00:01-08'::timestamptz, '2020-01-01 01:00:01-08'::timestamptz,'2012-12-20 09:00:00-08'::timestamptz,'2020-01-02 01:00:01-08'::timestamptz,'2012-12-20 12:00:00-08'::timestamptz,'2012-12-20 00:00:00-08'::timestamptz); select decode('2020-01-04 01:00:01-08'::timestamptz, '2020-01-01 01:00:01-08'::timestamptz,'2012-12-20 09:00:00-08'::timestamptz,'2020-01-02 01:00:01-08'::timestamptz,'2012-12-20 12:00:00-08'::timestamptz,'2012-12-20 00:00:00-08'::timestamptz); select decode('2020-01-01 01:00:01-08'::timestamptz, '2020-01-01 01:00:01-08'::timestamptz,'2012-12-20 09:00:00-08'::timestamptz,'2020-01-02 01:00:01-08'::timestamptz,'2012-12-20 12:00:00-08'::timestamptz, '2020-01-03 01:00:01-08'::timestamptz, '2012-12-20 15:00:00-08'::timestamptz); select decode('2020-01-04 01:00:01-08'::timestamptz, '2020-01-01 01:00:01-08'::timestamptz,'2012-12-20 09:00:00-08'::timestamptz,'2020-01-02 01:00:01-08'::timestamptz,'2012-12-20 12:00:00-08'::timestamptz, '2020-01-03 01:00:01-08'::timestamptz, '2012-12-20 15:00:00-08'::timestamptz); select decode('2020-01-01 01:00:01-08'::timestamptz, '2020-01-01 01:00:01-08'::timestamptz,'2012-12-20 09:00:00-08'::timestamptz,'2020-01-02 01:00:01-08'::timestamptz,'2012-12-20 12:00:00-08'::timestamptz, '2020-01-03 01:00:01-08'::timestamptz, '2012-12-20 15:00:00-08'::timestamptz,'2012-12-20 00:00:00-08'::timestamptz); select decode(4, 1,'2012-12-20 09:00:00-08'::timestamptz,2,'2012-12-20 12:00:00-08'::timestamptz, 3, '2012-12-20 15:00:00-08'::timestamptz,'2012-12-20 00:00:00-08'::timestamptz); select decode(NULL, '2020-01-01 01:00:01-08'::timestamptz, '2012-12-20 09:00:00-08'::timestamptz, NULL,'2012-12-20 12:00:00-08'::timestamptz); select decode(NULL, '2020-01-01 01:00:01-08'::timestamptz, '2012-12-20 09:00:00-08'::timestamptz, '2020-01-02 01:00:01-08'::timestamptz,'2012-12-20 12:00:00-08'::timestamptz); select decode(NULL, '2020-01-01 01:00:01-08'::timestamptz, '2012-12-20 09:00:00-08'::timestamptz, NULL,'2012-12-20 12:00:00-08'::timestamptz,'2012-12-20 00:00:00-08'::timestamptz); select decode(NULL, '2020-01-01 01:00:01-08'::timestamptz, '2012-12-20 09:00:00-08'::timestamptz, '2020-01-02 01:00:01-08'::timestamptz,'2012-12-20 12:00:00-08'::timestamptz,'2012-12-20 00:00:00-08'::timestamptz); --Test case to check if decode accepts other expressions as a key CREATE OR REPLACE FUNCTION five() RETURNS integer AS $$ BEGIN RETURN 5; END; $$ LANGUAGE plpgsql; select decode(five(), 1, 'one', 2, 'two', 5, 'five'); DROP FUNCTION five(); -- Test case to check duplicate keys in search list select decode(1, 1, 'one', 2, 'two', 1, 'one-again') = 'one'; /* Test case to check explicit type casting of keys in search list in * case of ambiguous key (1st argument) provided. */ -- 1) succeed and return 'result-1' select decode('2012-01-01', '2012-01-01'::date,'result-1','2012-01-02', 'result-2'); select decode('2012-01-01', '2012-01-01', 'result-1', '2012-02-01'::date, 'result-2'); select PLVstr.rvrs ('Jumping Jack Flash') ='hsalF kcaJ gnipmuJ'; select PLVstr.rvrs ('Jumping Jack Flash', 9) = 'hsalF kcaJ'; select PLVstr.rvrs ('Jumping Jack Flash', 4, 6) = 'nip'; select PLVstr.rvrs (NULL, 10, 20); select PLVstr.rvrs ('alphabet', -2, -5); select PLVstr.rvrs ('alphabet', -2); select PLVstr.rvrs ('alphabet', 2, 200); select PLVstr.rvrs ('alphabet', 20, 200); select PLVstr.lstrip ('*val1|val2|val3|*', '*') = 'val1|val2|val3|*'; select PLVstr.lstrip (',,,val1,val2,val3,', ',', 3)= 'val1,val2,val3,'; select PLVstr.lstrip ('WHERE WHITE = ''FRONT'' AND COMP# = 1500', 'WHERE ') = 'WHITE = ''FRONT'' AND COMP# = 1500'; select plvstr.left('Příliš žluťoučký kůň',4) = pg_catalog.substr('Příl', 1, 4); select pos,token from plvlex.tokens('select * from a.b.c join d ON x=y', true, true); SET lc_numeric TO 'C'; select to_char(22); select to_char(99::smallint); select to_char(-44444); select to_char(1234567890123456::bigint); select to_char(123.456::real); select to_char(1234.5678::double precision); select to_char(12345678901234567890::numeric); select to_char(1234567890.12345); select to_char('4.00'::numeric); select to_char('4.0010'::numeric); SELECT to_number('123'::text); SELECT to_number('123.456'::text); SELECT to_number(123); SELECT to_number(123::smallint); SELECT to_number(123::int); SELECT to_number(123::bigint); SELECT to_number(123::numeric); SELECT to_number(123.456); SELECT to_number(1210.73, 9999.99); SELECT to_number(1210::smallint, 9999::smallint); SELECT to_number(1210::int, 9999::int); SELECT to_number(1210::bigint, 9999::bigint); SELECT to_number(1210.73::numeric, 9999.99::numeric); SELECT to_date('2009-01-02'); SELECT bitand(5,1), bitand(5,2), bitand(5,4); SELECT sinh(1.570796)::numeric(10, 8), cosh(1.570796)::numeric(10, 8), tanh(4)::numeric(10, 8); SELECT nanvl(12345, 1), nanvl('NaN', 1); SELECT nanvl(12345::float4, 1), nanvl('NaN'::float4, 1); SELECT nanvl(12345::float8, 1), nanvl('NaN'::float8, 1); SELECT nanvl(12345::numeric, 1), nanvl('NaN'::numeric, 1); SELECT nanvl(12345, '1'::varchar), nanvl('NaN', 1::varchar); SELECT nanvl(12345::float4, '1'::varchar), nanvl('NaN'::float4, '1'::varchar); SELECT nanvl(12345::float8, '1'::varchar), nanvl('NaN'::float8, '1'::varchar); SELECT nanvl(12345::numeric, '1'::varchar), nanvl('NaN'::numeric, '1'::varchar); SELECT nanvl(12345, '1'::char), nanvl('NaN', 1::char); SELECT nanvl(12345::float4, '1'::char), nanvl('NaN'::float4, '1'::char); SELECT nanvl(12345::float8, '1'::char), nanvl('NaN'::float8, '1'::char); SELECT nanvl(12345::numeric, '1'::char), nanvl('NaN'::numeric, '1'::char); select dbms_assert.enquote_literal('some text '' some text'); select dbms_assert.enquote_name('''"AAA'); select dbms_assert.enquote_name('''"AAA', false); select dbms_assert.noop('some string'); select dbms_assert.qualified_sql_name('aaa.bbb.ccc."aaaa""aaa"'); select dbms_assert.qualified_sql_name('aaa.bbb.cc%c."aaaa""aaa"'); select dbms_assert.schema_name('dbms_assert'); select dbms_assert.schema_name('jabadabado'); select dbms_assert.simple_sql_name('"Aaa dghh shsh"'); select dbms_assert.simple_sql_name('ajajaj -- ajaj'); select dbms_assert.object_name('pg_catalog.pg_class'); select dbms_assert.object_name('dbms_assert.fooo'); select dbms_assert.enquote_literal(NULL); select dbms_assert.enquote_name(NULL); select dbms_assert.enquote_name(NULL, false); select dbms_assert.noop(NULL); select dbms_assert.qualified_sql_name(NULL); select dbms_assert.qualified_sql_name(NULL); select dbms_assert.schema_name(NULL); select dbms_assert.schema_name(NULL); select dbms_assert.simple_sql_name(NULL); select dbms_assert.simple_sql_name(NULL); select dbms_assert.object_name(NULL); select dbms_assert.object_name(NULL); select plunit.assert_true(NULL); select plunit.assert_true(1 = 2); select plunit.assert_true(1 = 2, 'one is not two'); select plunit.assert_true(1 = 1); select plunit.assert_false(1 = 1); select plunit.assert_false(1 = 1, 'trap is open'); select plunit.assert_false(NULL); select plunit.assert_null(current_date); select plunit.assert_null(NULL::date); select plunit.assert_not_null(current_date); select plunit.assert_not_null(NULL::date); select plunit.assert_equals('Pavel','Pa'||'vel'); select plunit.assert_equals(current_date, current_date + 1, 'diff dates'); select plunit.assert_equals(10.2, 10.3, 0.5); select plunit.assert_equals(10.2, 10.3, 0.01, 'attention some diff'); select plunit.assert_not_equals(current_date, current_date + 1, 'yestarday is today'); select plunit.fail(); select plunit.fail('custom exception'); SELECT dump('Yellow dog'::text) ~ E'^Typ=25 Len=(\\d+): \\d+(,\\d+)*$' AS t; SELECT dump('Yellow dog'::text, 10) ~ E'^Typ=25 Len=(\\d+): \\d+(,\\d+)*$' AS t; SELECT dump('Yellow dog'::text, 17) ~ E'^Typ=25 Len=(\\d+): .(,.)*$' AS t; SELECT dump(10::int2) ~ E'^Typ=21 Len=2: \\d+(,\\d+){1}$' AS t; SELECT dump(10::int4) ~ E'^Typ=23 Len=4: \\d+(,\\d+){3}$' AS t; SELECT dump(10::int8) ~ E'^Typ=20 Len=8: \\d+(,\\d+){7}$' AS t; SELECT dump(10.23::float4) ~ E'^Typ=700 Len=4: \\d+(,\\d+){3}$' AS t; SELECT dump(10.23::float8) ~ E'^Typ=701 Len=8: \\d+(,\\d+){7}$' AS t; SELECT dump(10.23::numeric) ~ E'^Typ=1700 Len=(\\d+): \\d+(,\\d+)*$' AS t; SELECT dump('2008-10-10'::date) ~ E'^Typ=1082 Len=4: \\d+(,\\d+){3}$' AS t; SELECT dump('2008-10-10'::timestamp) ~ E'^Typ=1114 Len=8: \\d+(,\\d+){7}$' AS t; SELECT dump('2009-10-10'::timestamp) ~ E'^Typ=1114 Len=8: \\d+(,\\d+){7}$' AS t; -- Tests for to_multi_byte SELECT to_multi_byte('123$test'); -- Check internal representation difference SELECT octet_length('abc'); SELECT octet_length(to_multi_byte('abc')); -- Tests for to_single_byte SELECT to_single_byte('123$test'); SELECT to_single_byte('123$test'); -- Check internal representation difference SELECT octet_length('abc'); SELECT octet_length(to_single_byte('abc')); -- Tests for round(TIMESTAMP WITH TIME ZONE) select round(TIMESTAMP WITH TIME ZONE'12/08/1990 05:35:25','YEAR') = '1991-01-01 00:00:00'; select round(TIMESTAMP WITH TIME ZONE'05/08/1990 05:35:25','Q') = '1990-04-01 00:00:00'; select round(TIMESTAMP WITH TIME ZONE'12/08/1990 05:35:25','MONTH') = '1990-12-01 00:00:00'; select round(TIMESTAMP WITH TIME ZONE'12/08/1990 05:35:25','DDD') = '1990-12-08 00:00:00'; select round(TIMESTAMP WITH TIME ZONE'12/08/1990 05:35:25','DAY') = '1990-12-09 00:00:00'; select round(TIMESTAMP WITH TIME ZONE'12/08/1990 05:35:25','hh') = '1990-12-08 06:00:00'; select round(TIMESTAMP WITH TIME ZONE'12/08/1990 05:35:25','mi') = '1990-12-08 05:35:00'; -- Tests for to_date SET DATESTYLE TO SQL, MDY; SELECT to_date('2009-01-02'); select to_date('January 8,1999'); SET DATESTYLE TO POSTGRES, MDY; select to_date('1999-01-08'); select to_date('1/12/1999'); SET DATESTYLE TO SQL, DMY; select to_date('01/02/03'); select to_date('1999-Jan-08'); select to_date('Jan-08-1999'); select to_date('08-Jan-1999'); SET DATESTYLE TO ISO, YMD; select to_date('99-Jan-08'); SET DATESTYLE TO ISO, DMY; select to_date('08-Jan-99'); select to_date('Jan-08-99'); select to_date('19990108'); select to_date('990108'); select to_date('J2451187'); set orafce.nls_date_format='YY-MonDD HH24:MI:SS'; select to_date('14-Jan08 11:44:49+05:30'); set orafce.nls_date_format='YY-DDMon HH24:MI:SS'; select to_date('14-08Jan 11:44:49+05:30'); set orafce.nls_date_format='DDMMYYYY HH24:MI:SS'; select to_date('21052014 12:13:44+05:30'); set orafce.nls_date_format='DDMMYY HH24:MI:SS'; select to_date('210514 12:13:44+05:30'); set orafce.nls_date_format='DDMMYY HH24:MI:SS.MS'; select pg_catalog.to_date('210514 12:13:44.55'); select oracle.to_date('210514 12:13:44.55'); -- Tests for oracle.to_date(text,text) SET search_path TO oracle,"$user", public, pg_catalog; select to_date('2014/04/25 10:13', 'YYYY/MM/DD HH:MI'); select to_date('16-Feb-09 10:11:11', 'DD-Mon-YY HH:MI:SS'); select to_date('02/16/09 04:12:12', 'MM/DD/YY HH24:MI:SS'); select to_date('021609 111213', 'MMDDYY HHMISS'); select to_date('16-Feb-09 11:12:12', 'DD-Mon-YY HH:MI:SS'); select to_date('Feb/16/09 11:21:23', 'Mon/DD/YY HH:MI:SS'); select to_date('February.16.2009 10:11:12', 'Month.DD.YYYY HH:MI:SS'); select to_date('20020315111212', 'yyyymmddhh12miss'); select to_date('January 15, 1989, 11:00 A.M.','Month dd, YYYY, HH:MI A.M.'); select to_date('14-Jan08 11:44:49+05:30' ,'YY-MonDD HH24:MI:SS'); select to_date('14-08Jan 11:44:49+05:30','YY-DDMon HH24:MI:SS'); select to_date('21052014 12:13:44+05:30','DDMMYYYY HH24:MI:SS'); select to_date('210514 12:13:44+05:30','DDMMYY HH24:MI:SS'); SET search_path TO default; -- Tests for + operator with DATE and number(smallint,integer,bigint,numeric) SET search_path TO oracle,"$user", public, pg_catalog; SET orafce.nls_date_format='YYYY-MM-DD HH24:MI:SS'; SELECT to_date('2014-07-02 10:08:55') + 9::smallint; SET orafce.nls_date_format='MM-DD-YYYY HH24:MI:SS'; SELECT to_date('07-02-2014 10:08:55') + 9::smallint; SET orafce.nls_date_format='DD-MM-YYYY HH24:MI:SS'; SELECT to_date('02-07-2014 10:08:55') + 9::smallint; SET orafce.nls_date_format='YYYY-MM-DD HH24:MI:SS'; SELECT to_date('2014-07-02 10:08:55') + 9; SELECT to_date('2014-07-02 10:08:55','YYYY-MM-DD HH:MI:SS') + 9::smallint; SELECT to_date('02-07-2014 10:08:55','DD-MM-YYYY HH:MI:SS') + 9::smallint; SELECT to_date('07-02-2014 10:08:55','MM-DD-YYYY HH:MI:SS') + 9::smallint; SET orafce.nls_date_format='YYYY-MM-DD HH24:MI:SS'; SELECT to_date('2014-07-02 10:08:55') + 9::bigint; SET orafce.nls_date_format='MM-DD-YYYY HH24:MI:SS'; SELECT to_date('07-02-2014 10:08:55') + 9::bigint; SET orafce.nls_date_format='DD-MM-YYYY HH24:MI:SS'; SELECT to_date('02-07-2014 10:08:55') + 9::bigint; SELECT to_date('2014-07-02 10:08:55','YYYY-MM-DD HH:MI:SS') + 9::bigint; SELECT to_date('02-07-2014 10:08:55','DD-MM-YYYY HH:MI:SS') + 9::bigint; SELECT to_date('07-02-2014 10:08:55','MM-DD-YYYY HH:MI:SS') + 9::bigint; SET orafce.nls_date_format='YYYY-MM-DD HH24:MI:SS'; SELECT to_date('2014-07-02 10:08:55') + 9::integer; SET orafce.nls_date_format='MM-DD-YYYY HH24:MI:SS'; SELECT to_date('07-02-2014 10:08:55') + 9::integer; SET orafce.nls_date_format='DD-MM-YYYY HH24:MI:SS'; SELECT to_date('02-07-2014 10:08:55') + 9::integer; SELECT to_date('2014-07-02 10:08:55','YYYY-MM-DD HH:MI:SS') + 9::integer; SELECT to_date('02-07-2014 10:08:55','DD-MM-YYYY HH:MI:SS') + 9::integer; SELECT to_date('07-02-2014 10:08:55','MM-DD-YYYY HH:MI:SS') + 9::integer; SET orafce.nls_date_format='YYYY-MM-DD HH24:MI:SS'; SELECT to_date('2014-07-02 10:08:55') + 9::numeric; SET orafce.nls_date_format='MM-DD-YYYY HH24:MI:SS'; SELECT to_date('07-02-2014 10:08:55') + 9::numeric; SET orafce.nls_date_format='DD-MM-YYYY HH24:MI:SS'; SELECT to_date('02-07-2014 10:08:55') + 9::numeric; SELECT to_date('2014-07-02 10:08:55','YYYY-MM-DD HH:MI:SS') + 9::numeric; SELECT to_date('02-07-2014 10:08:55','DD-MM-YYYY HH:MI:SS') + 9::numeric; SELECT to_date('07-02-2014 10:08:55','MM-DD-YYYY HH:MI:SS') + 9::numeric; SET orafce.nls_date_format='YYYY-MM-DD HH24:MI:SS'; SELECT to_date('2014-01-01 00:00:00') + 1.5; SELECT to_date('2014-01-01 00:00:00','yyyy-mm-dd hh24:mi:ss') + 1.5; SET search_path TO default; -- Tests for - operator with DATE and number(smallint,integer,bigint,numeric) SET search_path TO oracle,"$user", public, pg_catalog; SET orafce.nls_date_format='YYYY-MM-DD HH24:MI:SS'; SELECT to_date('2014-07-02 10:08:55') - 9::smallint; SET orafce.nls_date_format='MM-DD-YYYY HH24:MI:SS'; SELECT to_date('07-02-2014 10:08:55') - 9::smallint; SET orafce.nls_date_format='DD-MM-YYYY HH24:MI:SS'; SELECT to_date('02-07-2014 10:08:55') - 9::smallint; SET orafce.nls_date_format='YYYY-MM-DD HH24:MI:SS'; SELECT to_date('2014-07-02 10:08:55') - 9; SELECT to_date('2014-07-02 10:08:55','YYYY-MM-DD HH:MI:SS') - 9::smallint; SELECT to_date('02-07-2014 10:08:55','DD-MM-YYYY HH:MI:SS') - 9::smallint; SELECT to_date('07-02-2014 10:08:55','MM-DD-YYYY HH:MI:SS') - 9::smallint; SET orafce.nls_date_format='YYYY-MM-DD HH24:MI:SS'; SELECT to_date('2014-07-02 10:08:55') - 9::bigint; SET orafce.nls_date_format='MM-DD-YYYY HH24:MI:SS'; SELECT to_date('07-02-2014 10:08:55') - 9::bigint; SET orafce.nls_date_format='DD-MM-YYYY HH24:MI:SS'; SELECT to_date('02-07-2014 10:08:55') - 9::bigint; SELECT to_date('2014-07-02 10:08:55','YYYY-MM-DD HH:MI:SS') - 9::bigint; SELECT to_date('02-07-2014 10:08:55','DD-MM-YYYY HH:MI:SS') - 9::bigint; SELECT to_date('07-02-2014 10:08:55','MM-DD-YYYY HH:MI:SS') - 9::bigint; SET orafce.nls_date_format='YYYY-MM-DD HH24:MI:SS'; SELECT to_date('2014-07-02 10:08:55') - 9::integer; SET orafce.nls_date_format='MM-DD-YYYY HH24:MI:SS'; SELECT to_date('07-02-2014 10:08:55') - 9::integer; SET orafce.nls_date_format='DD-MM-YYYY HH24:MI:SS'; SELECT to_date('02-07-2014 10:08:55') - 9::integer; SELECT to_date('2014-07-02 10:08:55','YYYY-MM-DD HH:MI:SS') - 9::integer; SELECT to_date('02-07-2014 10:08:55','DD-MM-YYYY HH:MI:SS') - 9::integer; SELECT to_date('07-02-2014 10:08:55','MM-DD-YYYY HH:MI:SS') - 9::integer; SET orafce.nls_date_format='YYYY-MM-DD HH24:MI:SS'; SELECT to_date('2014-07-02 10:08:55') - 9::numeric; SET orafce.nls_date_format='MM-DD-YYYY HH24:MI:SS'; SELECT to_date('07-02-2014 10:08:55') - 9::numeric; SET orafce.nls_date_format='DD-MM-YYYY HH24:MI:SS'; SELECT to_date('02-07-2014 10:08:55') - 9::numeric; SELECT to_date('2014-07-02 10:08:55','YYYY-MM-DD HH:MI:SS') - 9::numeric; SELECT to_date('02-07-2014 10:08:55','DD-MM-YYYY HH:MI:SS') - 9::numeric; SELECT to_date('07-02-2014 10:08:55','MM-DD-YYYY HH:MI:SS') - 9::numeric; SET orafce.nls_date_format='YYYY-MM-DD HH24:MI:SS'; SELECT to_date('2014-01-01 00:00:00') - 1.5; SELECT to_date('2014-01-01 00:00:00','yyyy-mm-dd hh24:mi:ss') - 1.5; SET search_path TO default; --Tests for oracle.to_char(timestamp)-used to set the DATE output format SET search_path TO oracle,"$user", public, pg_catalog; SET orafce.nls_date_format to default; select oracle.to_char(to_date('19-APR-16 21:41:48')); set orafce.nls_date_format='YY-MonDD HH24:MI:SS'; select oracle.to_char(to_date('14-Jan08 11:44:49+05:30')); set orafce.nls_date_format='YY-DDMon HH24:MI:SS'; select oracle.to_char(to_date('14-08Jan 11:44:49+05:30')); set orafce.nls_date_format='DDMMYYYY HH24:MI:SS'; select oracle.to_char(to_date('21052014 12:13:44+05:30')); set orafce.nls_date_format='DDMMYY HH24:MI:SS'; select oracle.to_char(to_date('210514 12:13:44+05:30')); set orafce.nls_date_format='DDMMYYYY HH24:MI:SS'; select oracle.to_char(oracle.to_date('2014/04/25 10:13', 'YYYY/MM/DD HH:MI')); set orafce.nls_date_format='YY-DDMon HH24:MI:SS'; select oracle.to_char(oracle.to_date('16-Feb-09 10:11:11', 'DD-Mon-YY HH:MI:SS')); set orafce.nls_date_format='YY-DDMon HH24:MI:SS'; select oracle.to_char(oracle.to_date('02/16/09 04:12:12', 'MM/DD/YY HH24:MI:SS')); set orafce.nls_date_format='YY-MonDD HH24:MI:SS'; select oracle.to_char(oracle.to_date('021609 111213', 'MMDDYY HHMISS')); set orafce.nls_date_format='DDMMYYYY HH24:MI:SS'; select oracle.to_char(oracle.to_date('16-Feb-09 11:12:12', 'DD-Mon-YY HH:MI:SS')); set orafce.nls_date_format='DDMMYYYY HH24:MI:SS'; select oracle.to_char(oracle.to_date('Feb/16/09 11:21:23', 'Mon/DD/YY HH:MI:SS')); set orafce.nls_date_format='DDMMYYYY HH24:MI:SS'; select oracle.to_char(oracle.to_date('February.16.2009 10:11:12', 'Month.DD.YYYY HH:MI:SS')); set orafce.nls_date_format='YY-MonDD HH24:MI:SS'; select oracle.to_char(oracle.to_date('20020315111212', 'yyyymmddhh12miss')); set orafce.nls_date_format='DDMMYYYY HH24:MI:SS'; select oracle.to_char(oracle.to_date('January 15, 1989, 11:00 A.M.','Month dd, YYYY, HH:MI A.M.')); set orafce.nls_date_format='DDMMYY HH24:MI:SS'; select oracle.to_char(oracle.to_date('14-Jan08 11:44:49+05:30' ,'YY-MonDD HH24:MI:SS')); set orafce.nls_date_format='DDMMYYYY HH24:MI:SS'; select oracle.to_char(oracle.to_date('14-08Jan 11:44:49+05:30','YY-DDMon HH24:MI:SS')); set orafce.nls_date_format='YY-MonDD HH24:MI:SS'; select oracle.to_char(oracle.to_date('21052014 12:13:44+05:30','DDMMYYYY HH24:MI:SS')); set orafce.nls_date_format='DDMMYY HH24:MI:SS'; select oracle.to_char(oracle.to_date('210514 12:13:44+05:30','DDMMYY HH24:MI:SS')); SET search_path TO default; --Tests for oracle.-(oracle.date,oracle.date) SET search_path TO oracle,"$user", public, pg_catalog; SELECT (to_date('2014-07-17 11:10:15', 'yyyy-mm-dd hh24:mi:ss') - to_date('2014-02-01 10:00:00', 'yyyy-mm-dd hh24:mi:ss'))::numeric(10,4); SELECT (to_date('2014-07-17 13:14:15', 'yyyy-mm-dd hh24:mi:ss') - to_date('2014-02-01 10:00:00', 'yyyy-mm-dd hh24:mi:ss'))::numeric(10,4); SELECT (to_date('07-17-2014 13:14:15', 'mm-dd-yyyy hh24:mi:ss') - to_date('2014-02-01 10:00:00', 'yyyy-mm-dd hh24:mi:ss'))::numeric(10,4); SELECT (to_date('07-17-2014 13:14:15', 'mm-dd-yyyy hh24:mi:ss') - to_date('2015-02-01 10:00:00', 'yyyy-mm-dd hh24:mi:ss'))::numeric(10,4); SELECT (to_date('07-17-2014 13:14:15', 'mm-dd-yyyy hh24:mi:ss') - to_date('01-01-2013 10:00:00', 'mm-dd-yyyy hh24:mi:ss'))::numeric(10,4); SELECT (to_date('17-07-2014 13:14:15', 'dd-mm-yyyy hh24:mi:ss') - to_date('01-01-2013 10:00:00', 'dd--mm-yyyy hh24:mi:ss'))::numeric(10,4); SELECT (to_date('2014/02/01 10:11:12', 'YYYY/MM/DD hh12:mi:ss') - to_date('2013/02/01 10:11:12', 'YYYY/MM/DD hh12:mi:ss'))::numeric(10,4); SELECT (to_date('17-Jul-14 10:11:11', 'DD-Mon-YY HH:MI:SS') - to_date('17-Jan-14 00:00:00', 'DD-Mon-YY HH24:MI:SS'))::numeric(10,4); SELECT (to_date('July.17.2014 10:11:12', 'Month.DD.YYYY HH:MI:SS') - to_date('February.16.2014 10:21:12', 'Month.DD.YYYY HH:MI:SS'))::numeric(10,4); SELECT (to_date('20140717111211', 'yyyymmddhh12miss') - to_date('20140315111212', 'yyyymmddhh12miss'))::numeric(10,4); SELECT (to_date('January 15, 1990, 11:00 A.M.','Month dd, YYYY, HH:MI A.M.') - to_date('January 15, 1989, 10:00 A.M.','Month dd, YYYY, HH:MI A.M.'))::numeric(10,4); SELECT (to_date('14-Jul14 11:44:49' ,'YY-MonDD HH24:MI:SS') - to_date('14-Jan14 12:44:49' ,'YY-MonDD HH24:MI:SS'))::numeric(10,4); SELECT (to_date('210514 12:13:44','DDMMYY HH24:MI:SS') - to_date('210114 10:13:44','DDMMYY HH24:MI:SS'))::numeric(10,4); SELECT trunc(to_date('210514 12:13:44','DDMMYY HH24:MI:SS')); SELECT round(to_date('210514 12:13:44','DDMMYY HH24:MI:SS')); SET search_path TO default; -- -- Note: each Japanese character used below has display width of 2, otherwise 1. -- Note: each output string is surrounded by '|' for improved readability -- -- -- test LPAD family of functions -- /* cases where one or more arguments are of type CHAR */ SELECT '|' || oracle.lpad('あbcd'::char(8), 10) || '|'; SELECT '|' || oracle.lpad('あbcd'::char(8), 5) || '|'; SELECT '|' || oracle.lpad('あbcd'::char(8), 1) || '|'; SELECT '|' || oracle.lpad('あbcd'::char(5), 10, 'xい'::char(3)) || '|'; SELECT '|' || oracle.lpad('あbcd'::char(5), 5, 'xい'::char(3)) || '|'; SELECT '|' || oracle.lpad('あbcd'::char(5), 10, 'xい'::text) || '|'; SELECT '|' || oracle.lpad('あbcd'::char(5), 10, 'xい'::varchar2(5)) || '|'; SELECT '|' || oracle.lpad('あbcd'::char(5), 10, 'xい'::nvarchar2(3)) || '|'; SELECT '|' || oracle.lpad('あbcd'::text, 10, 'xい'::char(3)) || '|'; SELECT '|' || oracle.lpad('あbcd'::text, 5, 'xい'::char(3)) || '|'; SELECT '|' || oracle.lpad('あbcd'::varchar2(5), 10, 'xい'::char(3)) || '|'; SELECT '|' || oracle.lpad('あbcd'::varchar2(5), 5, 'xい'::char(3)) || '|'; SELECT '|' || oracle.lpad('あbcd'::nvarchar2(5), 10, 'xい'::char(3)) || '|'; SELECT '|' || oracle.lpad('あbcd'::nvarchar2(5), 5, 'xい'::char(3)) || '|'; /* test oracle.lpad(text, int [, text]) */ SELECT '|' || oracle.lpad('あbcd'::text, 10) || '|'; SELECT '|' || oracle.lpad('あbcd'::text, 5) || '|'; SELECT '|' || oracle.lpad('あbcd'::varchar2(10), 10) || '|'; SELECT '|' || oracle.lpad('あbcd'::varchar2(10), 5) || '|'; SELECT '|' || oracle.lpad('あbcd'::nvarchar2(10), 10) || '|'; SELECT '|' || oracle.lpad('あbcd'::nvarchar2(10), 5) || '|'; SELECT '|' || oracle.lpad('あbcd'::text, 10, 'xい'::text) || '|'; SELECT '|' || oracle.lpad('あbcd'::text, 10, 'xい'::varchar2(5)) || '|'; SELECT '|' || oracle.lpad('あbcd'::text, 10, 'xい'::nvarchar2(3)) || '|'; SELECT '|' || oracle.lpad('あbcd'::varchar2(5), 10, 'xい'::text) || '|'; SELECT '|' || oracle.lpad('あbcd'::varchar2(5), 10, 'xい'::varchar2(5)) || '|'; SELECT '|' || oracle.lpad('あbcd'::varchar2(5), 10, 'xい'::nvarchar2(5)) || '|'; SELECT '|' || oracle.lpad('あbcd'::nvarchar2(5), 10, 'xい'::text) || '|'; SELECT '|' || oracle.lpad('あbcd'::nvarchar2(5), 10, 'xい'::varchar2(5)) || '|'; SELECT '|' || oracle.lpad('あbcd'::nvarchar2(5), 10, 'xい'::nvarchar2(5)) || '|'; -- -- test RPAD family of functions -- /* cases where one or more arguments are of type CHAR */ SELECT '|' || oracle.rpad('あbcd'::char(8), 10) || '|'; SELECT '|' || oracle.rpad('あbcd'::char(8), 5) || '|'; SELECT '|' || oracle.rpad('あbcd'::char(8), 1) || '|'; SELECT '|' || oracle.rpad('あbcd'::char(5), 10, 'xい'::char(3)) || '|'; SELECT '|' || oracle.rpad('あbcd'::char(5), 5, 'xい'::char(3)) || '|'; SELECT '|' || oracle.rpad('あbcd'::char(5), 10, 'xい'::text) || '|'; SELECT '|' || oracle.rpad('あbcd'::char(5), 10, 'xい'::varchar2(5)) || '|'; SELECT '|' || oracle.rpad('あbcd'::char(5), 10, 'xい'::nvarchar2(3)) || '|'; SELECT '|' || oracle.rpad('あbcd'::text, 10, 'xい'::char(3)) || '|'; SELECT '|' || oracle.rpad('あbcd'::text, 5, 'xい'::char(3)) || '|'; SELECT '|' || oracle.rpad('あbcd'::varchar2(5), 10, 'xい'::char(3)) || '|'; SELECT '|' || oracle.rpad('あbcd'::varchar2(5), 5, 'xい'::char(3)) || '|'; SELECT '|' || oracle.rpad('あbcd'::nvarchar2(5), 10, 'xい'::char(3)) || '|'; SELECT '|' || oracle.rpad('あbcd'::nvarchar2(5), 5, 'xい'::char(3)) || '|'; /* test oracle.lpad(text, int [, text]) */ SELECT '|' || oracle.rpad('あbcd'::text, 10) || '|'; SELECT '|' || oracle.rpad('あbcd'::text, 5) || '|'; SELECT '|' || oracle.rpad('あbcd'::varchar2(10), 10) || '|'; SELECT '|' || oracle.rpad('あbcd'::varchar2(10), 5) || '|'; SELECT '|' || oracle.rpad('あbcd'::nvarchar2(10), 10) || '|'; SELECT '|' || oracle.rpad('あbcd'::nvarchar2(10), 5) || '|'; SELECT '|' || oracle.rpad('あbcd'::text, 10, 'xい'::text) || '|'; SELECT '|' || oracle.rpad('あbcd'::text, 10, 'xい'::varchar2(5)) || '|'; SELECT '|' || oracle.rpad('あbcd'::text, 10, 'xい'::nvarchar2(3)) || '|'; SELECT '|' || oracle.rpad('あbcd'::varchar2(5), 10, 'xい'::text) || '|'; SELECT '|' || oracle.rpad('あbcd'::varchar2(5), 10, 'xい'::varchar2(5)) || '|'; SELECT '|' || oracle.rpad('あbcd'::varchar2(5), 10, 'xい'::nvarchar2(5)) || '|'; SELECT '|' || oracle.rpad('あbcd'::nvarchar2(5), 10, 'xい'::text) || '|'; SELECT '|' || oracle.rpad('あbcd'::nvarchar2(5), 10, 'xい'::varchar2(5)) || '|'; SELECT '|' || oracle.rpad('あbcd'::nvarchar2(5), 10, 'xい'::nvarchar2(5)) || '|'; -- -- test TRIM family of functions -- /* test that trailing blanks of CHAR arguments are not removed and are significant */ -- -- LTRIM -- SELECT '|' || oracle.ltrim(' abcd'::char(10)) || '|' as LTRIM; SELECT '|' || oracle.ltrim(' abcd'::char(10),'a'::char(3)) || '|' as LTRIM; SELECT '|' || oracle.ltrim(' abcd'::char(10),'a'::text) || '|' as LTRIM; SELECT '|' || oracle.ltrim(' abcd'::char(10),'a'::varchar2(3)) || '|' as LTRIM; SELECT '|' || oracle.ltrim(' abcd'::char(10),'a'::nvarchar2(3)) || '|' as LTRIM; SELECT '|' || oracle.ltrim(' abcd '::text,'a'::char(3)) || '|' as LTRIM; SELECT '|' || oracle.ltrim(' abcd '::varchar2(10),'a'::char(3)) || '|' as LTRIM; SELECT '|' || oracle.ltrim(' abcd '::nvarchar2(10),'a'::char(3)) || '|' as LTRIM; -- -- RTRIM -- SELECT '|' || oracle.rtrim(' abcd'::char(10)) || '|' as LTRIM; SELECT '|' || oracle.rtrim(' abcd'::char(10),'d'::char(3)) || '|' as LTRIM; SELECT '|' || oracle.rtrim(' abcd'::char(10),'d'::text) || '|' as LTRIM; SELECT '|' || oracle.rtrim(' abcd'::char(10),'d'::varchar2(3)) || '|' as LTRIM; SELECT '|' || oracle.rtrim(' abcd'::char(10),'d'::nvarchar2(3)) || '|' as LTRIM; SELECT '|' || oracle.rtrim(' abcd '::text,'d'::char(3)) || '|' as LTRIM; SELECT '|' || oracle.rtrim(' abcd '::varchar2(10),'d'::char(3)) || '|' as LTRIM; SELECT '|' || oracle.rtrim(' abcd '::nvarchar2(10),'d'::char(3)) || '|' as LTRIM; -- -- BTRIM -- SELECT '|' || oracle.btrim(' abcd'::char(10)) || '|' as LTRIM; SELECT '|' || oracle.btrim(' abcd'::char(10),'ad'::char(3)) || '|' as LTRIM; SELECT '|' || oracle.btrim(' abcd'::char(10),'ad'::text) || '|' as LTRIM; SELECT '|' || oracle.btrim(' abcd'::char(10),'ad'::varchar2(3)) || '|' as LTRIM; SELECT '|' || oracle.btrim(' abcd'::char(10),'ad'::nvarchar2(3)) || '|' as LTRIM; SELECT '|' || oracle.btrim(' abcd '::text,'d'::char(3)) || '|' as LTRIM; SELECT '|' || oracle.btrim(' abcd '::varchar2(10),'d'::char(3)) || '|' as LTRIM; SELECT '|' || oracle.btrim(' abcd '::nvarchar2(10),'d'::char(3)) || '|' as LTRIM; -- -- test oracle.length() -- /* test that trailing blanks are not ignored */ SELECT oracle.length('あbb'::char(6)); SELECT oracle.length(''::char(6)); -- -- test plvdate.bizdays_between -- SELECT plvdate.including_start(); SELECT plvdate.bizdays_between('2016-02-24','2016-02-26'); SELECT plvdate.bizdays_between('2016-02-21','2016-02-27'); SELECT plvdate.include_start(false); SELECT plvdate.bizdays_between('2016-02-24','2016-02-26'); SELECT plvdate.bizdays_between('2016-02-21','2016-02-27'); SELECT oracle.round(1.234::double precision, 2), oracle.trunc(1.234::double precision, 2); SELECT oracle.round(1.234::float, 2), oracle.trunc(1.234::float, 2); -- -- should not fail - fix: Crashes due to insufficent argument checking (#59) -- select dbms_random.string(null, 42); select dbms_pipe.create_pipe(null); select plunit.assert_not_equals(1,2,3); -- -- lexer text -- SELECT pos, token, class, mod FROM plvlex.tokens('select * from a.b.c join d on x=y', true, true); orafce-VERSION_3_9_0/sql/orafce2.sql000066400000000000000000000002631362147214200171750ustar00rootroot00000000000000-- 2) fails and throws error: 'ERROR: could not determine polymorphic type -- because input has type "unknown"' select decode('2012-01-01', '2012-01-01', 23, '2012-01-02', 24); orafce-VERSION_3_9_0/sql/varchar2.sql000066400000000000000000000041241362147214200173640ustar00rootroot00000000000000\set VERBOSITY terse SET client_encoding = utf8; -- -- test type modifier related rules -- -- ERROR (typmod >= 1) CREATE TABLE foo (a VARCHAR2(0)); -- ERROR (number of typmods = 1) CREATE TABLE foo (a VARCHAR2(10, 1)); -- OK CREATE TABLE foo (a VARCHAR(5000)); -- cleanup DROP TABLE foo; -- OK CREATE TABLE foo (a VARCHAR2(5)); CREATE INDEX ON foo(a); -- -- test that no value longer than maxlen is allowed -- -- ERROR (length > 5) INSERT INTO foo VALUES ('abcdef'); -- ERROR (length > 5); -- VARCHAR2 does not truncate blank spaces on implicit coercion INSERT INTO foo VALUES ('abcde '); -- OK INSERT INTO foo VALUES ('abcde'); -- OK INSERT INTO foo VALUES ('abcdef'::VARCHAR2(5)); -- OK INSERT INTO foo VALUES ('abcde '::VARCHAR2(5)); --OK INSERT INTO foo VALUES ('abc'::VARCHAR2(5)); -- -- test whitespace semantics on comparison -- -- equal SELECT 'abcde '::VARCHAR2(10) = 'abcde '::VARCHAR2(10); -- not equal SELECT 'abcde '::VARCHAR2(10) = 'abcde '::VARCHAR2(10); -- -- test string functions created for varchar2 -- -- substrb(varchar2, int, int) SELECT substrb('ABCありがとう'::VARCHAR2, 7, 6); -- returns 'f' (emtpy string is not NULL) SELECT substrb('ABCありがとう'::VARCHAR2, 7, 0) IS NULL; -- If the starting position is zero or less, then return from the start -- of the string adjusting the length to be consistent with the "negative start" -- per SQL. SELECT substrb('ABCありがとう'::VARCHAR2, 0, 4); -- substrb(varchar2, int) SELECT substrb('ABCありがとう', 5); -- strposb(varchar2, varchar2) SELECT strposb('ABCありがとう', 'りが'); -- returns 1 (start of the source string) SELECT strposb('ABCありがとう', ''); -- returns 0 SELECT strposb('ABCありがとう', 'XX'); -- returns 't' SELECT strposb('ABCありがとう', NULL) IS NULL; -- lengthb(varchar2) SELECT lengthb('ABCありがとう'); -- returns 0 SELECT lengthb(''); -- returs 't' SELECT lengthb(NULL) IS NULL; -- null safe concat (disabled by default) SELECT NULL || 'hello'::varchar2 || NULL; SET orafce.varchar2_null_safe_concat TO true; SELECT NULL || 'hello'::varchar2 || NULL; orafce-VERSION_3_9_0/sqlparse.c000066400000000000000000001452111362147214200163350ustar00rootroot00000000000000/* A Bison parser, made by GNU Bison 3.4.1. */ /* Bison implementation for Yacc-like parsers in C Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2019 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work under terms of your choice, so long as that work isn't itself a parser generator using the skeleton or a modified version thereof as a parser skeleton. Alternatively, if you modify or redistribute the parser skeleton itself, you may (at your option) remove this special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ /* C LALR(1) parser skeleton written by Richard Stallman, by simplifying the original so-called "semantic" parser. */ /* All symbols defined below should begin with yy or YY, to avoid infringing on user name space. This should be done even for local variables, as they might otherwise be expanded by user macros. There are some unavoidable exceptions within include files to define necessary library symbols; they are noted "INFRINGES ON USER NAME SPACE" below. */ /* Undocumented macros, especially those whose name start with YY_, are private implementation details. Do not rely on them. */ /* Identify Bison output. */ #define YYBISON 1 /* Bison version. */ #define YYBISON_VERSION "3.4.1" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" /* Pure parsers. */ #define YYPURE 0 /* Push parsers. */ #define YYPUSH 0 /* Pull parsers. */ #define YYPULL 1 /* Substitute the variable and function names. */ #define yyparse orafce_sql_yyparse #define yylex orafce_sql_yylex #define yyerror orafce_sql_yyerror #define yydebug orafce_sql_yydebug #define yynerrs orafce_sql_yynerrs #define yylval orafce_sql_yylval #define yychar orafce_sql_yychar #define yylloc orafce_sql_yylloc /* First part of user prologue. */ #line 8 "sqlparse.y" #define YYDEBUG 1 #define YYLLOC_DEFAULT(Current, Rhs, N) \ do { \ if (N) \ (Current) = (Rhs)[1]; \ else \ (Current) = (Rhs)[0]; \ } while (0) #include "postgres.h" #include "orafce.h" #include "plvlex.h" #include "nodes/pg_list.h" #define MOVE_TO_S(src,dest,col) dest->col = src.col ? pstrdup(src.col) : NULL #define MOVE_TO(src,dest,col) dest->col = src.col #define FILL_NODE(src,dest) \ MOVE_TO_S(src,dest,str), \ MOVE_TO(src,dest,keycode), \ MOVE_TO(src,dest,lloc), \ MOVE_TO_S(src,dest,sep), \ MOVE_TO(src,dest,modificator) static orafce_lexnode *__node; #define CREATE_NODE(src,type) \ ( \ __node = (orafce_lexnode*) palloc(sizeof(orafce_lexnode)), \ __node->typenode = X_##type, \ __node->classname = #type, \ FILL_NODE(src,__node), \ __node) extern int yylex(void); /* defined as fdate_yylex in fdatescan.l */ static char *scanbuf; static int scanbuflen; void orafce_sql_yyerror(List **result, const char *message); #define YYMALLOC malloc /* XXX: should use palloc? */ #define YYFREE free /* XXX: should use pfree? */ #line 130 "sqlparse.c" # ifndef YY_NULLPTR # if defined __cplusplus # if 201103L <= __cplusplus # define YY_NULLPTR nullptr # else # define YY_NULLPTR 0 # endif # else # define YY_NULLPTR ((void*)0) # endif # endif /* Enabling verbose error messages. */ #ifdef YYERROR_VERBOSE # undef YYERROR_VERBOSE # define YYERROR_VERBOSE 1 #else # define YYERROR_VERBOSE 0 #endif /* Use api.header.include to #include this header instead of duplicating it here. */ #ifndef YY_ORAFCE_SQL_YY_SQLPARSE_H_INCLUDED # define YY_ORAFCE_SQL_YY_SQLPARSE_H_INCLUDED /* Debug traces. */ #ifndef YYDEBUG # define YYDEBUG 0 #endif #if YYDEBUG extern int orafce_sql_yydebug; #endif /* Token type. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE enum yytokentype { X_IDENT = 258, X_NCONST = 259, X_SCONST = 260, X_OP = 261, X_PARAM = 262, X_COMMENT = 263, X_WHITESPACE = 264, X_KEYWORD = 265, X_OTHERS = 266, X_TYPECAST = 267 }; #endif /* Value type. */ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED union YYSTYPE { #line 63 "sqlparse.y" int ival; orafce_lexnode *node; List *list; struct { char *str; int keycode; int lloc; char *sep; char *modificator; } val; #line 200 "sqlparse.c" }; typedef union YYSTYPE YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define YYSTYPE_IS_DECLARED 1 #endif /* Location type. */ #if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED typedef struct YYLTYPE YYLTYPE; struct YYLTYPE { int first_line; int first_column; int last_line; int last_column; }; # define YYLTYPE_IS_DECLARED 1 # define YYLTYPE_IS_TRIVIAL 1 #endif extern YYSTYPE orafce_sql_yylval; extern YYLTYPE orafce_sql_yylloc; int orafce_sql_yyparse (List **result); #endif /* !YY_ORAFCE_SQL_YY_SQLPARSE_H_INCLUDED */ #ifdef short # undef short #endif #ifdef YYTYPE_UINT8 typedef YYTYPE_UINT8 yytype_uint8; #else typedef unsigned char yytype_uint8; #endif #ifdef YYTYPE_INT8 typedef YYTYPE_INT8 yytype_int8; #else typedef signed char yytype_int8; #endif #ifdef YYTYPE_UINT16 typedef YYTYPE_UINT16 yytype_uint16; #else typedef unsigned short yytype_uint16; #endif #ifdef YYTYPE_INT16 typedef YYTYPE_INT16 yytype_int16; #else typedef short yytype_int16; #endif #ifndef YYSIZE_T # ifdef __SIZE_TYPE__ # define YYSIZE_T __SIZE_TYPE__ # elif defined size_t # define YYSIZE_T size_t # elif ! defined YYSIZE_T # include /* INFRINGES ON USER NAME SPACE */ # define YYSIZE_T size_t # else # define YYSIZE_T unsigned # endif #endif #define YYSIZE_MAXIMUM ((YYSIZE_T) -1) #ifndef YY_ # if defined YYENABLE_NLS && YYENABLE_NLS # if ENABLE_NLS # include /* INFRINGES ON USER NAME SPACE */ # define YY_(Msgid) dgettext ("bison-runtime", Msgid) # endif # endif # ifndef YY_ # define YY_(Msgid) Msgid # endif #endif #ifndef YY_ATTRIBUTE # if (defined __GNUC__ \ && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__))) \ || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C # define YY_ATTRIBUTE(Spec) __attribute__(Spec) # else # define YY_ATTRIBUTE(Spec) /* empty */ # endif #endif #ifndef YY_ATTRIBUTE_PURE # define YY_ATTRIBUTE_PURE YY_ATTRIBUTE ((__pure__)) #endif #ifndef YY_ATTRIBUTE_UNUSED # define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__)) #endif /* Suppress unused-variable warnings by "using" E. */ #if ! defined lint || defined __GNUC__ # define YYUSE(E) ((void) (E)) #else # define YYUSE(E) /* empty */ #endif #if defined __GNUC__ && ! defined __ICC && 407 <= __GNUC__ * 100 + __GNUC_MINOR__ /* Suppress an incorrect diagnostic about yylval being uninitialized. */ # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\ _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") # define YY_IGNORE_MAYBE_UNINITIALIZED_END \ _Pragma ("GCC diagnostic pop") #else # define YY_INITIAL_VALUE(Value) Value #endif #ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN # define YY_IGNORE_MAYBE_UNINITIALIZED_END #endif #ifndef YY_INITIAL_VALUE # define YY_INITIAL_VALUE(Value) /* Nothing. */ #endif #define YY_ASSERT(E) ((void) (0 && (E))) #if ! defined yyoverflow || YYERROR_VERBOSE /* The parser invokes alloca or malloc; define the necessary symbols. */ # ifdef YYSTACK_USE_ALLOCA # if YYSTACK_USE_ALLOCA # ifdef __GNUC__ # define YYSTACK_ALLOC __builtin_alloca # elif defined __BUILTIN_VA_ARG_INCR # include /* INFRINGES ON USER NAME SPACE */ # elif defined _AIX # define YYSTACK_ALLOC __alloca # elif defined _MSC_VER # include /* INFRINGES ON USER NAME SPACE */ # define alloca _alloca # else # define YYSTACK_ALLOC alloca # if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS # include /* INFRINGES ON USER NAME SPACE */ /* Use EXIT_SUCCESS as a witness for stdlib.h. */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif # endif # endif # endif # endif # ifdef YYSTACK_ALLOC /* Pacify GCC's 'empty if-body' warning. */ # define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) # ifndef YYSTACK_ALLOC_MAXIMUM /* The OS might guarantee only one guard page at the bottom of the stack, and a page size can be as small as 4096 bytes. So we cannot safely invoke alloca (N) if N exceeds 4096. Use a slightly smaller number to allow for a few compiler-allocated temporary stack slots. */ # define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ # endif # else # define YYSTACK_ALLOC YYMALLOC # define YYSTACK_FREE YYFREE # ifndef YYSTACK_ALLOC_MAXIMUM # define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM # endif # if (defined __cplusplus && ! defined EXIT_SUCCESS \ && ! ((defined YYMALLOC || defined malloc) \ && (defined YYFREE || defined free))) # include /* INFRINGES ON USER NAME SPACE */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif # endif # ifndef YYMALLOC # define YYMALLOC malloc # if ! defined malloc && ! defined EXIT_SUCCESS void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ # endif # endif # ifndef YYFREE # define YYFREE free # if ! defined free && ! defined EXIT_SUCCESS void free (void *); /* INFRINGES ON USER NAME SPACE */ # endif # endif # endif #endif /* ! defined yyoverflow || YYERROR_VERBOSE */ #if (! defined yyoverflow \ && (! defined __cplusplus \ || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \ && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) /* A type that is properly aligned for any stack member. */ union yyalloc { yytype_int16 yyss_alloc; YYSTYPE yyvs_alloc; YYLTYPE yyls_alloc; }; /* The size of the maximum gap between one aligned stack and the next. */ # define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) /* The size of an array large to enough to hold all stacks, each with N elements. */ # define YYSTACK_BYTES(N) \ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \ + 2 * YYSTACK_GAP_MAXIMUM) # define YYCOPY_NEEDED 1 /* Relocate STACK from its old location to the new one. The local variables YYSIZE and YYSTACKSIZE give the old and new number of elements in the stack, and YYPTR gives the new location of the stack. Advance YYPTR to a properly aligned location for the next stack. */ # define YYSTACK_RELOCATE(Stack_alloc, Stack) \ do \ { \ YYSIZE_T yynewbytes; \ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ Stack = &yyptr->Stack_alloc; \ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ yyptr += yynewbytes / sizeof (*yyptr); \ } \ while (0) #endif #if defined YYCOPY_NEEDED && YYCOPY_NEEDED /* Copy COUNT objects from SRC to DST. The source and destination do not overlap. */ # ifndef YYCOPY # if defined __GNUC__ && 1 < __GNUC__ # define YYCOPY(Dst, Src, Count) \ __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src))) # else # define YYCOPY(Dst, Src, Count) \ do \ { \ YYSIZE_T yyi; \ for (yyi = 0; yyi < (Count); yyi++) \ (Dst)[yyi] = (Src)[yyi]; \ } \ while (0) # endif # endif #endif /* !YYCOPY_NEEDED */ /* YYFINAL -- State number of the termination state. */ #define YYFINAL 13 /* YYLAST -- Last index in YYTABLE. */ #define YYLAST 10 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 13 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 4 /* YYNRULES -- Number of rules. */ #define YYNRULES 13 /* YYNSTATES -- Number of states. */ #define YYNSTATES 15 #define YYUNDEFTOK 2 #define YYMAXUTOK 267 /* YYTRANSLATE(TOKEN-NUM) -- Symbol number corresponding to TOKEN-NUM as returned by yylex, with out-of-bounds checking. */ #define YYTRANSLATE(YYX) \ ((unsigned) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) /* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM as returned by yylex. */ static const yytype_uint8 yytranslate[] = { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }; #if YYDEBUG /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_uint8 yyrline[] = { 0, 91, 91, 95, 96, 100, 101, 102, 103, 104, 105, 106, 107, 108 }; #endif #if YYDEBUG || YYERROR_VERBOSE || 0 /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. First, the terminals, then, starting at YYNTOKENS, nonterminals. */ static const char *const yytname[] = { "$end", "error", "$undefined", "X_IDENT", "X_NCONST", "X_SCONST", "X_OP", "X_PARAM", "X_COMMENT", "X_WHITESPACE", "X_KEYWORD", "X_OTHERS", "X_TYPECAST", "$accept", "root", "elements", "anyelement", YY_NULLPTR }; #endif # ifdef YYPRINT /* YYTOKNUM[NUM] -- (External) token number corresponding to the (internal) symbol number NUM (which must be that of a token). */ static const yytype_uint16 yytoknum[] = { 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267 }; # endif #define YYPACT_NINF -4 #define yypact_value_is_default(Yystate) \ (!!((Yystate) == (-4))) #define YYTABLE_NINF -1 #define yytable_value_is_error(Yytable_value) \ 0 /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ static const yytype_int8 yypact[] = { -3, -4, -4, -4, -4, -4, -4, -4, -4, -4, 9, -3, -4, -4, -4 }; /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. Performed when YYTABLE does not specify something else to do. Zero means the default is an error. */ static const yytype_uint8 yydefact[] = { 0, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0, 2, 3, 1, 4 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int8 yypgoto[] = { -4, -4, -4, -1 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int8 yydefgoto[] = { -1, 10, 11, 12 }; /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule whose number is the opposite. If YYTABLE_NINF, syntax error. */ static const yytype_uint8 yytable[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 13, 14 }; static const yytype_uint8 yycheck[] = { 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, 11 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing symbol of state STATE-NUM. */ static const yytype_uint8 yystos[] = { 0, 3, 4, 5, 6, 7, 8, 9, 10, 11, 14, 15, 16, 0, 16 }; /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const yytype_uint8 yyr1[] = { 0, 13, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16 }; /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ static const yytype_uint8 yyr2[] = { 0, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; #define yyerrok (yyerrstatus = 0) #define yyclearin (yychar = YYEMPTY) #define YYEMPTY (-2) #define YYEOF 0 #define YYACCEPT goto yyacceptlab #define YYABORT goto yyabortlab #define YYERROR goto yyerrorlab #define YYRECOVERING() (!!yyerrstatus) #define YYBACKUP(Token, Value) \ do \ if (yychar == YYEMPTY) \ { \ yychar = (Token); \ yylval = (Value); \ YYPOPSTACK (yylen); \ yystate = *yyssp; \ goto yybackup; \ } \ else \ { \ yyerror (result, YY_("syntax error: cannot back up")); \ YYERROR; \ } \ while (0) /* Error token number */ #define YYTERROR 1 #define YYERRCODE 256 /* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. If N is 0, then set CURRENT to the empty location which ends the previous symbol: RHS[0] (always defined). */ #ifndef YYLLOC_DEFAULT # define YYLLOC_DEFAULT(Current, Rhs, N) \ do \ if (N) \ { \ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ } \ else \ { \ (Current).first_line = (Current).last_line = \ YYRHSLOC (Rhs, 0).last_line; \ (Current).first_column = (Current).last_column = \ YYRHSLOC (Rhs, 0).last_column; \ } \ while (0) #endif #define YYRHSLOC(Rhs, K) ((Rhs)[K]) /* Enable debugging if requested. */ #if YYDEBUG # ifndef YYFPRINTF # include /* INFRINGES ON USER NAME SPACE */ # define YYFPRINTF fprintf # endif # define YYDPRINTF(Args) \ do { \ if (yydebug) \ YYFPRINTF Args; \ } while (0) /* YY_LOCATION_PRINT -- Print the location on the stream. This macro was not mandated originally: define only if we know we won't break user code: when these are the locations we know. */ #ifndef YY_LOCATION_PRINT # if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL /* Print *YYLOCP on YYO. Private, do not rely on its existence. */ YY_ATTRIBUTE_UNUSED static int yy_location_print_ (FILE *yyo, YYLTYPE const * const yylocp) { int res = 0; int end_col = 0 != yylocp->last_column ? yylocp->last_column - 1 : 0; if (0 <= yylocp->first_line) { res += YYFPRINTF (yyo, "%d", yylocp->first_line); if (0 <= yylocp->first_column) res += YYFPRINTF (yyo, ".%d", yylocp->first_column); } if (0 <= yylocp->last_line) { if (yylocp->first_line < yylocp->last_line) { res += YYFPRINTF (yyo, "-%d", yylocp->last_line); if (0 <= end_col) res += YYFPRINTF (yyo, ".%d", end_col); } else if (0 <= end_col && yylocp->first_column < end_col) res += YYFPRINTF (yyo, "-%d", end_col); } return res; } # define YY_LOCATION_PRINT(File, Loc) \ yy_location_print_ (File, &(Loc)) # else # define YY_LOCATION_PRINT(File, Loc) ((void) 0) # endif #endif # define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ do { \ if (yydebug) \ { \ YYFPRINTF (stderr, "%s ", Title); \ yy_symbol_print (stderr, \ Type, Value, Location, result); \ YYFPRINTF (stderr, "\n"); \ } \ } while (0) /*-----------------------------------. | Print this symbol's value on YYO. | `-----------------------------------*/ static void yy_symbol_value_print (FILE *yyo, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, List **result) { FILE *yyoutput = yyo; YYUSE (yyoutput); YYUSE (yylocationp); YYUSE (result); if (!yyvaluep) return; # ifdef YYPRINT if (yytype < YYNTOKENS) YYPRINT (yyo, yytoknum[yytype], *yyvaluep); # endif YYUSE (yytype); } /*---------------------------. | Print this symbol on YYO. | `---------------------------*/ static void yy_symbol_print (FILE *yyo, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, List **result) { YYFPRINTF (yyo, "%s %s (", yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]); YY_LOCATION_PRINT (yyo, *yylocationp); YYFPRINTF (yyo, ": "); yy_symbol_value_print (yyo, yytype, yyvaluep, yylocationp, result); YYFPRINTF (yyo, ")"); } /*------------------------------------------------------------------. | yy_stack_print -- Print the state stack from its BOTTOM up to its | | TOP (included). | `------------------------------------------------------------------*/ static void yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) { YYFPRINTF (stderr, "Stack now"); for (; yybottom <= yytop; yybottom++) { int yybot = *yybottom; YYFPRINTF (stderr, " %d", yybot); } YYFPRINTF (stderr, "\n"); } # define YY_STACK_PRINT(Bottom, Top) \ do { \ if (yydebug) \ yy_stack_print ((Bottom), (Top)); \ } while (0) /*------------------------------------------------. | Report that the YYRULE is going to be reduced. | `------------------------------------------------*/ static void yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule, List **result) { unsigned long yylno = yyrline[yyrule]; int yynrhs = yyr2[yyrule]; int yyi; YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", yyrule - 1, yylno); /* The symbols being reduced. */ for (yyi = 0; yyi < yynrhs; yyi++) { YYFPRINTF (stderr, " $%d = ", yyi + 1); yy_symbol_print (stderr, yystos[yyssp[yyi + 1 - yynrhs]], &yyvsp[(yyi + 1) - (yynrhs)] , &(yylsp[(yyi + 1) - (yynrhs)]) , result); YYFPRINTF (stderr, "\n"); } } # define YY_REDUCE_PRINT(Rule) \ do { \ if (yydebug) \ yy_reduce_print (yyssp, yyvsp, yylsp, Rule, result); \ } while (0) /* Nonzero means print parse trace. It is left uninitialized so that multiple parsers can coexist. */ int yydebug; #else /* !YYDEBUG */ # define YYDPRINTF(Args) # define YY_SYMBOL_PRINT(Title, Type, Value, Location) # define YY_STACK_PRINT(Bottom, Top) # define YY_REDUCE_PRINT(Rule) #endif /* !YYDEBUG */ /* YYINITDEPTH -- initial size of the parser's stacks. */ #ifndef YYINITDEPTH # define YYINITDEPTH 200 #endif /* YYMAXDEPTH -- maximum size the stacks can grow to (effective only if the built-in stack extension method is used). Do not make this value too large; the results are undefined if YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) evaluated with infinite-precision integer arithmetic. */ #ifndef YYMAXDEPTH # define YYMAXDEPTH 10000 #endif #if YYERROR_VERBOSE # ifndef yystrlen # if defined __GLIBC__ && defined _STRING_H # define yystrlen strlen # else /* Return the length of YYSTR. */ static YYSIZE_T yystrlen (const char *yystr) { YYSIZE_T yylen; for (yylen = 0; yystr[yylen]; yylen++) continue; return yylen; } # endif # endif # ifndef yystpcpy # if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE # define yystpcpy stpcpy # else /* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in YYDEST. */ static char * yystpcpy (char *yydest, const char *yysrc) { char *yyd = yydest; const char *yys = yysrc; while ((*yyd++ = *yys++) != '\0') continue; return yyd - 1; } # endif # endif # ifndef yytnamerr /* Copy to YYRES the contents of YYSTR after stripping away unnecessary quotes and backslashes, so that it's suitable for yyerror. The heuristic is that double-quoting is unnecessary unless the string contains an apostrophe, a comma, or backslash (other than backslash-backslash). YYSTR is taken from yytname. If YYRES is null, do not copy; instead, return the length of what the result would have been. */ static YYSIZE_T yytnamerr (char *yyres, const char *yystr) { if (*yystr == '"') { YYSIZE_T yyn = 0; char const *yyp = yystr; for (;;) switch (*++yyp) { case '\'': case ',': goto do_not_strip_quotes; case '\\': if (*++yyp != '\\') goto do_not_strip_quotes; else goto append; append: default: if (yyres) yyres[yyn] = *yyp; yyn++; break; case '"': if (yyres) yyres[yyn] = '\0'; return yyn; } do_not_strip_quotes: ; } if (! yyres) return yystrlen (yystr); return (YYSIZE_T) (yystpcpy (yyres, yystr) - yyres); } # endif /* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message about the unexpected token YYTOKEN for the state stack whose top is YYSSP. Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is not large enough to hold the message. In that case, also set *YYMSG_ALLOC to the required number of bytes. Return 2 if the required number of bytes is too large to store. */ static int yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, yytype_int16 *yyssp, int yytoken) { YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]); YYSIZE_T yysize = yysize0; enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; /* Internationalized format string. */ const char *yyformat = YY_NULLPTR; /* Arguments of yyformat. */ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; /* Number of reported tokens (one for the "unexpected", one per "expected"). */ int yycount = 0; /* There are many possibilities here to consider: - If this state is a consistent state with a default action, then the only way this function was invoked is if the default action is an error action. In that case, don't check for expected tokens because there are none. - The only way there can be no lookahead present (in yychar) is if this state is a consistent state with a default action. Thus, detecting the absence of a lookahead is sufficient to determine that there is no unexpected or expected token to report. In that case, just report a simple "syntax error". - Don't assume there isn't a lookahead just because this state is a consistent state with a default action. There might have been a previous inconsistent state, consistent state with a non-default action, or user semantic action that manipulated yychar. - Of course, the expected token list depends on states to have correct lookahead information, and it depends on the parser not to perform extra reductions after fetching a lookahead from the scanner and before detecting a syntax error. Thus, state merging (from LALR or IELR) and default reductions corrupt the expected token list. However, the list is correct for canonical LR with one exception: it will still contain any token that will not be accepted due to an error action in a later state. */ if (yytoken != YYEMPTY) { int yyn = yypact[*yyssp]; yyarg[yycount++] = yytname[yytoken]; if (!yypact_value_is_default (yyn)) { /* Start YYX at -YYN if negative to avoid negative indexes in YYCHECK. In other words, skip the first -YYN actions for this state because they are default actions. */ int yyxbegin = yyn < 0 ? -yyn : 0; /* Stay within bounds of both yycheck and yytname. */ int yychecklim = YYLAST - yyn + 1; int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; int yyx; for (yyx = yyxbegin; yyx < yyxend; ++yyx) if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR && !yytable_value_is_error (yytable[yyx + yyn])) { if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) { yycount = 1; yysize = yysize0; break; } yyarg[yycount++] = yytname[yyx]; { YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]); if (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM) yysize = yysize1; else return 2; } } } } switch (yycount) { # define YYCASE_(N, S) \ case N: \ yyformat = S; \ break default: /* Avoid compiler warnings. */ YYCASE_(0, YY_("syntax error")); YYCASE_(1, YY_("syntax error, unexpected %s")); YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); # undef YYCASE_ } { YYSIZE_T yysize1 = yysize + yystrlen (yyformat); if (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM) yysize = yysize1; else return 2; } if (*yymsg_alloc < yysize) { *yymsg_alloc = 2 * yysize; if (! (yysize <= *yymsg_alloc && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; return 1; } /* Avoid sprintf, as that infringes on the user's name space. Don't have undefined behavior even if the translation produced a string with the wrong number of "%s"s. */ { char *yyp = *yymsg; int yyi = 0; while ((*yyp = *yyformat) != '\0') if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) { yyp += yytnamerr (yyp, yyarg[yyi++]); yyformat += 2; } else { yyp++; yyformat++; } } return 0; } #endif /* YYERROR_VERBOSE */ /*-----------------------------------------------. | Release the memory associated to this symbol. | `-----------------------------------------------*/ static void yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, YYLTYPE *yylocationp, List **result) { YYUSE (yyvaluep); YYUSE (yylocationp); YYUSE (result); if (!yymsg) yymsg = "Deleting"; YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN YYUSE (yytype); YY_IGNORE_MAYBE_UNINITIALIZED_END } /* The lookahead symbol. */ int yychar; /* The semantic value of the lookahead symbol. */ YYSTYPE yylval; /* Location data for the lookahead symbol. */ YYLTYPE yylloc # if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL = { 1, 1, 1, 1 } # endif ; /* Number of syntax errors so far. */ int yynerrs; /*----------. | yyparse. | `----------*/ int yyparse (List **result) { int yystate; /* Number of tokens to shift before error messages enabled. */ int yyerrstatus; /* The stacks and their tools: 'yyss': related to states. 'yyvs': related to semantic values. 'yyls': related to locations. Refer to the stacks through separate pointers, to allow yyoverflow to reallocate them elsewhere. */ /* The state stack. */ yytype_int16 yyssa[YYINITDEPTH]; yytype_int16 *yyss; yytype_int16 *yyssp; /* The semantic value stack. */ YYSTYPE yyvsa[YYINITDEPTH]; YYSTYPE *yyvs; YYSTYPE *yyvsp; /* The location stack. */ YYLTYPE yylsa[YYINITDEPTH]; YYLTYPE *yyls; YYLTYPE *yylsp; /* The locations where the error started and ended. */ YYLTYPE yyerror_range[3]; YYSIZE_T yystacksize; int yyn; int yyresult; /* Lookahead token as an internal (translated) token number. */ int yytoken = 0; /* The variables used to return semantic value and location from the action routines. */ YYSTYPE yyval; YYLTYPE yyloc; #if YYERROR_VERBOSE /* Buffer for error messages, and its allocated size. */ char yymsgbuf[128]; char *yymsg = yymsgbuf; YYSIZE_T yymsg_alloc = sizeof yymsgbuf; #endif #define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N), yylsp -= (N)) /* The number of symbols on the RHS of the reduced rule. Keep to zero when no symbol should be popped. */ int yylen = 0; yyssp = yyss = yyssa; yyvsp = yyvs = yyvsa; yylsp = yyls = yylsa; yystacksize = YYINITDEPTH; YYDPRINTF ((stderr, "Starting parse\n")); yystate = 0; yyerrstatus = 0; yynerrs = 0; yychar = YYEMPTY; /* Cause a token to be read. */ yylsp[0] = yylloc; goto yysetstate; /*------------------------------------------------------------. | yynewstate -- push a new state, which is found in yystate. | `------------------------------------------------------------*/ yynewstate: /* In all cases, when you get here, the value and location stacks have just been pushed. So pushing a state here evens the stacks. */ yyssp++; /*--------------------------------------------------------------------. | yynewstate -- set current state (the top of the stack) to yystate. | `--------------------------------------------------------------------*/ yysetstate: YYDPRINTF ((stderr, "Entering state %d\n", yystate)); YY_ASSERT (0 <= yystate && yystate < YYNSTATES); *yyssp = (yytype_int16) yystate; if (yyss + yystacksize - 1 <= yyssp) #if !defined yyoverflow && !defined YYSTACK_RELOCATE goto yyexhaustedlab; #else { /* Get the current used size of the three stacks, in elements. */ YYSIZE_T yysize = (YYSIZE_T) (yyssp - yyss + 1); # if defined yyoverflow { /* Give user a chance to reallocate the stack. Use copies of these so that the &'s don't force the real ones into memory. */ YYSTYPE *yyvs1 = yyvs; yytype_int16 *yyss1 = yyss; YYLTYPE *yyls1 = yyls; /* Each stack pointer address is followed by the size of the data in use in that stack, in bytes. This used to be a conditional around just the two extra args, but that might be undefined if yyoverflow is a macro. */ yyoverflow (YY_("memory exhausted"), &yyss1, yysize * sizeof (*yyssp), &yyvs1, yysize * sizeof (*yyvsp), &yyls1, yysize * sizeof (*yylsp), &yystacksize); yyss = yyss1; yyvs = yyvs1; yyls = yyls1; } # else /* defined YYSTACK_RELOCATE */ /* Extend the stack our own way. */ if (YYMAXDEPTH <= yystacksize) goto yyexhaustedlab; yystacksize *= 2; if (YYMAXDEPTH < yystacksize) yystacksize = YYMAXDEPTH; { yytype_int16 *yyss1 = yyss; union yyalloc *yyptr = (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); if (! yyptr) goto yyexhaustedlab; YYSTACK_RELOCATE (yyss_alloc, yyss); YYSTACK_RELOCATE (yyvs_alloc, yyvs); YYSTACK_RELOCATE (yyls_alloc, yyls); # undef YYSTACK_RELOCATE if (yyss1 != yyssa) YYSTACK_FREE (yyss1); } # endif yyssp = yyss + yysize - 1; yyvsp = yyvs + yysize - 1; yylsp = yyls + yysize - 1; YYDPRINTF ((stderr, "Stack size increased to %lu\n", (unsigned long) yystacksize)); if (yyss + yystacksize - 1 <= yyssp) YYABORT; } #endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */ if (yystate == YYFINAL) YYACCEPT; goto yybackup; /*-----------. | yybackup. | `-----------*/ yybackup: /* Do appropriate processing given the current state. Read a lookahead token if we need one and don't already have one. */ /* First try to decide what to do without reference to lookahead token. */ yyn = yypact[yystate]; if (yypact_value_is_default (yyn)) goto yydefault; /* Not known => get a lookahead token if don't already have one. */ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ if (yychar == YYEMPTY) { YYDPRINTF ((stderr, "Reading a token: ")); yychar = yylex (); } if (yychar <= YYEOF) { yychar = yytoken = YYEOF; YYDPRINTF ((stderr, "Now at end of input.\n")); } else { yytoken = YYTRANSLATE (yychar); YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); } /* If the proper action on seeing token YYTOKEN is to reduce or to detect an error, take that action. */ yyn += yytoken; if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) goto yydefault; yyn = yytable[yyn]; if (yyn <= 0) { if (yytable_value_is_error (yyn)) goto yyerrlab; yyn = -yyn; goto yyreduce; } /* Count tokens shifted since error; after three, turn off error status. */ if (yyerrstatus) yyerrstatus--; /* Shift the lookahead token. */ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); /* Discard the shifted token. */ yychar = YYEMPTY; yystate = yyn; YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END *++yylsp = yylloc; goto yynewstate; /*-----------------------------------------------------------. | yydefault -- do the default action for the current state. | `-----------------------------------------------------------*/ yydefault: yyn = yydefact[yystate]; if (yyn == 0) goto yyerrlab; goto yyreduce; /*-----------------------------. | yyreduce -- do a reduction. | `-----------------------------*/ yyreduce: /* yyn is the number of a rule to reduce with. */ yylen = yyr2[yyn]; /* If YYLEN is nonzero, implement the default value of the action: '$$ = $1'. Otherwise, the following line sets YYVAL to garbage. This behavior is undocumented and Bison users should not rely upon it. Assigning to YYVAL unconditionally makes the parser a bit smaller, and it avoids a GCC warning that YYVAL may be used uninitialized. */ yyval = yyvsp[1-yylen]; /* Default location. */ YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen); yyerror_range[1] = yyloc; YY_REDUCE_PRINT (yyn); switch (yyn) { case 2: #line 91 "sqlparse.y" { *((void**)result) = (yyvsp[0].list); } #line 1405 "sqlparse.c" break; case 3: #line 95 "sqlparse.y" { (yyval.list) = list_make1((yyvsp[0].node));} #line 1411 "sqlparse.c" break; case 4: #line 96 "sqlparse.y" { (yyval.list) = lappend((yyvsp[-1].list), (yyvsp[0].node));} #line 1417 "sqlparse.c" break; case 5: #line 100 "sqlparse.y" { (yyval.node) = (orafce_lexnode*) CREATE_NODE((yyvsp[0].val), IDENT); } #line 1423 "sqlparse.c" break; case 6: #line 101 "sqlparse.y" { (yyval.node) = (orafce_lexnode*) CREATE_NODE((yyvsp[0].val), NCONST); } #line 1429 "sqlparse.c" break; case 7: #line 102 "sqlparse.y" { (yyval.node) = (orafce_lexnode*) CREATE_NODE((yyvsp[0].val), SCONST); } #line 1435 "sqlparse.c" break; case 8: #line 103 "sqlparse.y" { (yyval.node) = (orafce_lexnode*) CREATE_NODE((yyvsp[0].val), OP); } #line 1441 "sqlparse.c" break; case 9: #line 104 "sqlparse.y" { (yyval.node) = (orafce_lexnode*) CREATE_NODE((yyvsp[0].val), PARAM); } #line 1447 "sqlparse.c" break; case 10: #line 105 "sqlparse.y" { (yyval.node) = (orafce_lexnode*) CREATE_NODE((yyvsp[0].val), COMMENT); } #line 1453 "sqlparse.c" break; case 11: #line 106 "sqlparse.y" { (yyval.node) = (orafce_lexnode*) CREATE_NODE((yyvsp[0].val), WHITESPACE); } #line 1459 "sqlparse.c" break; case 12: #line 107 "sqlparse.y" { (yyval.node) = (orafce_lexnode*) CREATE_NODE((yyvsp[0].val), KEYWORD); } #line 1465 "sqlparse.c" break; case 13: #line 108 "sqlparse.y" { (yyval.node) = (orafce_lexnode*) CREATE_NODE((yyvsp[0].val), OTHERS); } #line 1471 "sqlparse.c" break; #line 1475 "sqlparse.c" default: break; } /* User semantic actions sometimes alter yychar, and that requires that yytoken be updated with the new translation. We take the approach of translating immediately before every use of yytoken. One alternative is translating here after every semantic action, but that translation would be missed if the semantic action invokes YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an incorrect destructor might then be invoked immediately. In the case of YYERROR or YYBACKUP, subsequent parser actions might lead to an incorrect destructor call or verbose syntax error message before the lookahead is translated. */ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); YYPOPSTACK (yylen); yylen = 0; YY_STACK_PRINT (yyss, yyssp); *++yyvsp = yyval; *++yylsp = yyloc; /* Now 'shift' the result of the reduction. Determine what state that goes to, based on the state we popped back to and the rule number reduced by. */ { const int yylhs = yyr1[yyn] - YYNTOKENS; const int yyi = yypgoto[yylhs] + *yyssp; yystate = (0 <= yyi && yyi <= YYLAST && yycheck[yyi] == *yyssp ? yytable[yyi] : yydefgoto[yylhs]); } goto yynewstate; /*--------------------------------------. | yyerrlab -- here on detecting error. | `--------------------------------------*/ yyerrlab: /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); /* If not already recovering from an error, report this error. */ if (!yyerrstatus) { ++yynerrs; #if ! YYERROR_VERBOSE yyerror (result, YY_("syntax error")); #else # define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ yyssp, yytoken) { char const *yymsgp = YY_("syntax error"); int yysyntax_error_status; yysyntax_error_status = YYSYNTAX_ERROR; if (yysyntax_error_status == 0) yymsgp = yymsg; else if (yysyntax_error_status == 1) { if (yymsg != yymsgbuf) YYSTACK_FREE (yymsg); yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); if (!yymsg) { yymsg = yymsgbuf; yymsg_alloc = sizeof yymsgbuf; yysyntax_error_status = 2; } else { yysyntax_error_status = YYSYNTAX_ERROR; yymsgp = yymsg; } } yyerror (result, yymsgp); if (yysyntax_error_status == 2) goto yyexhaustedlab; } # undef YYSYNTAX_ERROR #endif } yyerror_range[1] = yylloc; if (yyerrstatus == 3) { /* If just tried and failed to reuse lookahead token after an error, discard it. */ if (yychar <= YYEOF) { /* Return failure if at end of input. */ if (yychar == YYEOF) YYABORT; } else { yydestruct ("Error: discarding", yytoken, &yylval, &yylloc, result); yychar = YYEMPTY; } } /* Else will try to reuse lookahead token after shifting the error token. */ goto yyerrlab1; /*---------------------------------------------------. | yyerrorlab -- error raised explicitly by YYERROR. | `---------------------------------------------------*/ yyerrorlab: /* Pacify compilers when the user code never invokes YYERROR and the label yyerrorlab therefore never appears in user code. */ if (0) YYERROR; /* Do not reclaim the symbols of the rule whose action triggered this YYERROR. */ YYPOPSTACK (yylen); yylen = 0; YY_STACK_PRINT (yyss, yyssp); yystate = *yyssp; goto yyerrlab1; /*-------------------------------------------------------------. | yyerrlab1 -- common code for both syntax error and YYERROR. | `-------------------------------------------------------------*/ yyerrlab1: yyerrstatus = 3; /* Each real token shifted decrements this. */ for (;;) { yyn = yypact[yystate]; if (!yypact_value_is_default (yyn)) { yyn += YYTERROR; if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) { yyn = yytable[yyn]; if (0 < yyn) break; } } /* Pop the current state because it cannot handle the error token. */ if (yyssp == yyss) YYABORT; yyerror_range[1] = *yylsp; yydestruct ("Error: popping", yystos[yystate], yyvsp, yylsp, result); YYPOPSTACK (1); yystate = *yyssp; YY_STACK_PRINT (yyss, yyssp); } YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END yyerror_range[2] = yylloc; /* Using YYLLOC is tempting, but would change the location of the lookahead. YYLOC is available though. */ YYLLOC_DEFAULT (yyloc, yyerror_range, 2); *++yylsp = yyloc; /* Shift the error token. */ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); yystate = yyn; goto yynewstate; /*-------------------------------------. | yyacceptlab -- YYACCEPT comes here. | `-------------------------------------*/ yyacceptlab: yyresult = 0; goto yyreturn; /*-----------------------------------. | yyabortlab -- YYABORT comes here. | `-----------------------------------*/ yyabortlab: yyresult = 1; goto yyreturn; #if !defined yyoverflow || YYERROR_VERBOSE /*-------------------------------------------------. | yyexhaustedlab -- memory exhaustion comes here. | `-------------------------------------------------*/ yyexhaustedlab: yyerror (result, YY_("memory exhausted")); yyresult = 2; /* Fall through. */ #endif /*-----------------------------------------------------. | yyreturn -- parsing is finished, return the result. | `-----------------------------------------------------*/ yyreturn: if (yychar != YYEMPTY) { /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = YYTRANSLATE (yychar); yydestruct ("Cleanup: discarding lookahead", yytoken, &yylval, &yylloc, result); } /* Do not reclaim the symbols of the rule whose action triggered this YYABORT or YYACCEPT. */ YYPOPSTACK (yylen); YY_STACK_PRINT (yyss, yyssp); while (yyssp != yyss) { yydestruct ("Cleanup: popping", yystos[*yyssp], yyvsp, yylsp, result); YYPOPSTACK (1); } #ifndef yyoverflow if (yyss != yyssa) YYSTACK_FREE (yyss); #endif #if YYERROR_VERBOSE if (yymsg != yymsgbuf) YYSTACK_FREE (yymsg); #endif return yyresult; } #line 110 "sqlparse.y" #undef YYLTYPE #include "sqlscan.c" orafce-VERSION_3_9_0/sqlparse.h000066400000000000000000000056521362147214200163460ustar00rootroot00000000000000/* A Bison parser, made by GNU Bison 3.4.1. */ /* Bison interface for Yacc-like parsers in C Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2019 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work under terms of your choice, so long as that work isn't itself a parser generator using the skeleton or a modified version thereof as a parser skeleton. Alternatively, if you modify or redistribute the parser skeleton itself, you may (at your option) remove this special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ /* Undocumented macros, especially those whose name start with YY_, are private implementation details. Do not rely on them. */ #ifndef YY_ORAFCE_SQL_YY_SQLPARSE_H_INCLUDED # define YY_ORAFCE_SQL_YY_SQLPARSE_H_INCLUDED /* Debug traces. */ #ifndef YYDEBUG # define YYDEBUG 0 #endif #if YYDEBUG extern int orafce_sql_yydebug; #endif /* Token type. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE enum yytokentype { X_IDENT = 258, X_NCONST = 259, X_SCONST = 260, X_OP = 261, X_PARAM = 262, X_COMMENT = 263, X_WHITESPACE = 264, X_KEYWORD = 265, X_OTHERS = 266, X_TYPECAST = 267 }; #endif /* Value type. */ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED union YYSTYPE { #line 63 "sqlparse.y" int ival; orafce_lexnode *node; List *list; struct { char *str; int keycode; int lloc; char *sep; char *modificator; } val; #line 84 "sqlparse.h" }; typedef union YYSTYPE YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define YYSTYPE_IS_DECLARED 1 #endif /* Location type. */ #if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED typedef struct YYLTYPE YYLTYPE; struct YYLTYPE { int first_line; int first_column; int last_line; int last_column; }; # define YYLTYPE_IS_DECLARED 1 # define YYLTYPE_IS_TRIVIAL 1 #endif extern YYSTYPE orafce_sql_yylval; extern YYLTYPE orafce_sql_yylloc; int orafce_sql_yyparse (List **result); #endif /* !YY_ORAFCE_SQL_YY_SQLPARSE_H_INCLUDED */ orafce-VERSION_3_9_0/sqlparse.y000066400000000000000000000046701362147214200163660ustar00rootroot00000000000000/* * %define api.prefix {orafce_sql_yy} is not compileable on old bison 2.4 * so I am using obsolete but still working option. */ %name-prefix "orafce_sql_yy" %{ #define YYDEBUG 1 #define YYLLOC_DEFAULT(Current, Rhs, N) \ do { \ if (N) \ (Current) = (Rhs)[1]; \ else \ (Current) = (Rhs)[0]; \ } while (0) #include "postgres.h" #include "orafce.h" #include "plvlex.h" #include "nodes/pg_list.h" #define MOVE_TO_S(src,dest,col) dest->col = src.col ? pstrdup(src.col) : NULL #define MOVE_TO(src,dest,col) dest->col = src.col #define FILL_NODE(src,dest) \ MOVE_TO_S(src,dest,str), \ MOVE_TO(src,dest,keycode), \ MOVE_TO(src,dest,lloc), \ MOVE_TO_S(src,dest,sep), \ MOVE_TO(src,dest,modificator) static orafce_lexnode *__node; #define CREATE_NODE(src,type) \ ( \ __node = (orafce_lexnode*) palloc(sizeof(orafce_lexnode)), \ __node->typenode = X_##type, \ __node->classname = #type, \ FILL_NODE(src,__node), \ __node) extern int yylex(void); /* defined as fdate_yylex in fdatescan.l */ static char *scanbuf; static int scanbuflen; void orafce_sql_yyerror(List **result, const char *message); #define YYMALLOC malloc /* XXX: should use palloc? */ #define YYFREE free /* XXX: should use pfree? */ %} %locations %parse-param {List **result} %union { int ival; orafce_lexnode *node; List *list; struct { char *str; int keycode; int lloc; char *sep; char *modificator; } val; } /* BISON Declarations */ %token X_IDENT X_NCONST X_SCONST X_OP X_PARAM X_COMMENT X_WHITESPACE X_KEYWORD X_OTHERS X_TYPECAST %type elements %type anyelement %type root %start root /* Grammar follows */ %% root: elements { *((void**)result) = $1; } ; elements: anyelement { $$ = list_make1($1);} | elements anyelement { $$ = lappend($1, $2);} ; anyelement: X_IDENT { $$ = (orafce_lexnode*) CREATE_NODE($1, IDENT); } | X_NCONST { $$ = (orafce_lexnode*) CREATE_NODE($1, NCONST); } | X_SCONST { $$ = (orafce_lexnode*) CREATE_NODE($1, SCONST); } | X_OP { $$ = (orafce_lexnode*) CREATE_NODE($1, OP); } | X_PARAM { $$ = (orafce_lexnode*) CREATE_NODE($1, PARAM); } | X_COMMENT { $$ = (orafce_lexnode*) CREATE_NODE($1, COMMENT); } | X_WHITESPACE { $$ = (orafce_lexnode*) CREATE_NODE($1, WHITESPACE); } | X_KEYWORD { $$ = (orafce_lexnode*) CREATE_NODE($1, KEYWORD); } | X_OTHERS { $$ = (orafce_lexnode*) CREATE_NODE($1, OTHERS); } ; %% #undef YYLTYPE #include "sqlscan.c" orafce-VERSION_3_9_0/sqlscan.c000066400000000000000000002600301362147214200161440ustar00rootroot00000000000000#line 1 "sqlscan.c" #line 3 "sqlscan.c" #define YY_INT_ALIGNED short int /* A lexical scanner generated by flex */ #define yy_create_buffer orafce_sql_yy_create_buffer #define yy_delete_buffer orafce_sql_yy_delete_buffer #define yy_scan_buffer orafce_sql_yy_scan_buffer #define yy_scan_string orafce_sql_yy_scan_string #define yy_scan_bytes orafce_sql_yy_scan_bytes #define yy_init_buffer orafce_sql_yy_init_buffer #define yy_flush_buffer orafce_sql_yy_flush_buffer #define yy_load_buffer_state orafce_sql_yy_load_buffer_state #define yy_switch_to_buffer orafce_sql_yy_switch_to_buffer #define yypush_buffer_state orafce_sql_yypush_buffer_state #define yypop_buffer_state orafce_sql_yypop_buffer_state #define yyensure_buffer_stack orafce_sql_yyensure_buffer_stack #define yy_flex_debug orafce_sql_yy_flex_debug #define yyin orafce_sql_yyin #define yyleng orafce_sql_yyleng #define yylex orafce_sql_yylex #define yylineno orafce_sql_yylineno #define yyout orafce_sql_yyout #define yyrestart orafce_sql_yyrestart #define yytext orafce_sql_yytext #define yywrap orafce_sql_yywrap #define yyalloc orafce_sql_yyalloc #define yyrealloc orafce_sql_yyrealloc #define yyfree orafce_sql_yyfree #define FLEX_SCANNER #define YY_FLEX_MAJOR_VERSION 2 #define YY_FLEX_MINOR_VERSION 6 #define YY_FLEX_SUBMINOR_VERSION 4 #if YY_FLEX_SUBMINOR_VERSION > 0 #define FLEX_BETA #endif #ifdef yy_create_buffer #define orafce_sql_yy_create_buffer_ALREADY_DEFINED #else #define yy_create_buffer orafce_sql_yy_create_buffer #endif #ifdef yy_delete_buffer #define orafce_sql_yy_delete_buffer_ALREADY_DEFINED #else #define yy_delete_buffer orafce_sql_yy_delete_buffer #endif #ifdef yy_scan_buffer #define orafce_sql_yy_scan_buffer_ALREADY_DEFINED #else #define yy_scan_buffer orafce_sql_yy_scan_buffer #endif #ifdef yy_scan_string #define orafce_sql_yy_scan_string_ALREADY_DEFINED #else #define yy_scan_string orafce_sql_yy_scan_string #endif #ifdef yy_scan_bytes #define orafce_sql_yy_scan_bytes_ALREADY_DEFINED #else #define yy_scan_bytes orafce_sql_yy_scan_bytes #endif #ifdef yy_init_buffer #define orafce_sql_yy_init_buffer_ALREADY_DEFINED #else #define yy_init_buffer orafce_sql_yy_init_buffer #endif #ifdef yy_flush_buffer #define orafce_sql_yy_flush_buffer_ALREADY_DEFINED #else #define yy_flush_buffer orafce_sql_yy_flush_buffer #endif #ifdef yy_load_buffer_state #define orafce_sql_yy_load_buffer_state_ALREADY_DEFINED #else #define yy_load_buffer_state orafce_sql_yy_load_buffer_state #endif #ifdef yy_switch_to_buffer #define orafce_sql_yy_switch_to_buffer_ALREADY_DEFINED #else #define yy_switch_to_buffer orafce_sql_yy_switch_to_buffer #endif #ifdef yypush_buffer_state #define orafce_sql_yypush_buffer_state_ALREADY_DEFINED #else #define yypush_buffer_state orafce_sql_yypush_buffer_state #endif #ifdef yypop_buffer_state #define orafce_sql_yypop_buffer_state_ALREADY_DEFINED #else #define yypop_buffer_state orafce_sql_yypop_buffer_state #endif #ifdef yyensure_buffer_stack #define orafce_sql_yyensure_buffer_stack_ALREADY_DEFINED #else #define yyensure_buffer_stack orafce_sql_yyensure_buffer_stack #endif #ifdef yylex #define orafce_sql_yylex_ALREADY_DEFINED #else #define yylex orafce_sql_yylex #endif #ifdef yyrestart #define orafce_sql_yyrestart_ALREADY_DEFINED #else #define yyrestart orafce_sql_yyrestart #endif #ifdef yylex_init #define orafce_sql_yylex_init_ALREADY_DEFINED #else #define yylex_init orafce_sql_yylex_init #endif #ifdef yylex_init_extra #define orafce_sql_yylex_init_extra_ALREADY_DEFINED #else #define yylex_init_extra orafce_sql_yylex_init_extra #endif #ifdef yylex_destroy #define orafce_sql_yylex_destroy_ALREADY_DEFINED #else #define yylex_destroy orafce_sql_yylex_destroy #endif #ifdef yyget_debug #define orafce_sql_yyget_debug_ALREADY_DEFINED #else #define yyget_debug orafce_sql_yyget_debug #endif #ifdef yyset_debug #define orafce_sql_yyset_debug_ALREADY_DEFINED #else #define yyset_debug orafce_sql_yyset_debug #endif #ifdef yyget_extra #define orafce_sql_yyget_extra_ALREADY_DEFINED #else #define yyget_extra orafce_sql_yyget_extra #endif #ifdef yyset_extra #define orafce_sql_yyset_extra_ALREADY_DEFINED #else #define yyset_extra orafce_sql_yyset_extra #endif #ifdef yyget_in #define orafce_sql_yyget_in_ALREADY_DEFINED #else #define yyget_in orafce_sql_yyget_in #endif #ifdef yyset_in #define orafce_sql_yyset_in_ALREADY_DEFINED #else #define yyset_in orafce_sql_yyset_in #endif #ifdef yyget_out #define orafce_sql_yyget_out_ALREADY_DEFINED #else #define yyget_out orafce_sql_yyget_out #endif #ifdef yyset_out #define orafce_sql_yyset_out_ALREADY_DEFINED #else #define yyset_out orafce_sql_yyset_out #endif #ifdef yyget_leng #define orafce_sql_yyget_leng_ALREADY_DEFINED #else #define yyget_leng orafce_sql_yyget_leng #endif #ifdef yyget_text #define orafce_sql_yyget_text_ALREADY_DEFINED #else #define yyget_text orafce_sql_yyget_text #endif #ifdef yyget_lineno #define orafce_sql_yyget_lineno_ALREADY_DEFINED #else #define yyget_lineno orafce_sql_yyget_lineno #endif #ifdef yyset_lineno #define orafce_sql_yyset_lineno_ALREADY_DEFINED #else #define yyset_lineno orafce_sql_yyset_lineno #endif #ifdef yywrap #define orafce_sql_yywrap_ALREADY_DEFINED #else #define yywrap orafce_sql_yywrap #endif #ifdef yyalloc #define orafce_sql_yyalloc_ALREADY_DEFINED #else #define yyalloc orafce_sql_yyalloc #endif #ifdef yyrealloc #define orafce_sql_yyrealloc_ALREADY_DEFINED #else #define yyrealloc orafce_sql_yyrealloc #endif #ifdef yyfree #define orafce_sql_yyfree_ALREADY_DEFINED #else #define yyfree orafce_sql_yyfree #endif #ifdef yytext #define orafce_sql_yytext_ALREADY_DEFINED #else #define yytext orafce_sql_yytext #endif #ifdef yyleng #define orafce_sql_yyleng_ALREADY_DEFINED #else #define yyleng orafce_sql_yyleng #endif #ifdef yyin #define orafce_sql_yyin_ALREADY_DEFINED #else #define yyin orafce_sql_yyin #endif #ifdef yyout #define orafce_sql_yyout_ALREADY_DEFINED #else #define yyout orafce_sql_yyout #endif #ifdef yy_flex_debug #define orafce_sql_yy_flex_debug_ALREADY_DEFINED #else #define yy_flex_debug orafce_sql_yy_flex_debug #endif #ifdef yylineno #define orafce_sql_yylineno_ALREADY_DEFINED #else #define yylineno orafce_sql_yylineno #endif /* First, we deal with platform-specific or compiler-specific issues. */ /* begin standard C headers. */ #include #include #include #include /* end standard C headers. */ /* flex integer type definitions */ #ifndef FLEXINT_H #define FLEXINT_H /* C99 systems have . Non-C99 systems may or may not. */ #if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, * if you want the limit (max/min) macros for int types. */ #ifndef __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS 1 #endif #include typedef int8_t flex_int8_t; typedef uint8_t flex_uint8_t; typedef int16_t flex_int16_t; typedef uint16_t flex_uint16_t; typedef int32_t flex_int32_t; typedef uint32_t flex_uint32_t; #else typedef signed char flex_int8_t; typedef short int flex_int16_t; typedef int flex_int32_t; typedef unsigned char flex_uint8_t; typedef unsigned short int flex_uint16_t; typedef unsigned int flex_uint32_t; /* Limits of integral types. */ #ifndef INT8_MIN #define INT8_MIN (-128) #endif #ifndef INT16_MIN #define INT16_MIN (-32767-1) #endif #ifndef INT32_MIN #define INT32_MIN (-2147483647-1) #endif #ifndef INT8_MAX #define INT8_MAX (127) #endif #ifndef INT16_MAX #define INT16_MAX (32767) #endif #ifndef INT32_MAX #define INT32_MAX (2147483647) #endif #ifndef UINT8_MAX #define UINT8_MAX (255U) #endif #ifndef UINT16_MAX #define UINT16_MAX (65535U) #endif #ifndef UINT32_MAX #define UINT32_MAX (4294967295U) #endif #ifndef SIZE_MAX #define SIZE_MAX (~(size_t)0) #endif #endif /* ! C99 */ #endif /* ! FLEXINT_H */ /* begin standard C++ headers. */ /* TODO: this is always defined, so inline it */ #define yyconst const #if defined(__GNUC__) && __GNUC__ >= 3 #define yynoreturn __attribute__((__noreturn__)) #else #define yynoreturn #endif /* Returned upon end-of-file. */ #define YY_NULL 0 /* Promotes a possibly negative, possibly signed char to an * integer in range [0..255] for use as an array index. */ #define YY_SC_TO_UI(c) ((YY_CHAR) (c)) /* Enter a start condition. This macro really ought to take a parameter, * but we do it the disgusting crufty way forced on us by the ()-less * definition of BEGIN. */ #define BEGIN (yy_start) = 1 + 2 * /* Translate the current start state into a value that can be later handed * to BEGIN to return to the state. The YYSTATE alias is for lex * compatibility. */ #define YY_START (((yy_start) - 1) / 2) #define YYSTATE YY_START /* Action number for EOF rule of a given start state. */ #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) /* Special action meaning "start processing a new file". */ #define YY_NEW_FILE yyrestart( yyin ) #define YY_END_OF_BUFFER_CHAR 0 /* Size of default input buffer. */ #ifndef YY_BUF_SIZE #ifdef __ia64__ /* On IA-64, the buffer size is 16k, not 8k. * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. * Ditto for the __ia64__ case accordingly. */ #define YY_BUF_SIZE 32768 #else #define YY_BUF_SIZE 16384 #endif /* __ia64__ */ #endif /* The state buf must be large enough to hold one state per character in the main buffer. */ #define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) #ifndef YY_TYPEDEF_YY_BUFFER_STATE #define YY_TYPEDEF_YY_BUFFER_STATE typedef struct yy_buffer_state *YY_BUFFER_STATE; #endif #ifndef YY_TYPEDEF_YY_SIZE_T #define YY_TYPEDEF_YY_SIZE_T typedef size_t yy_size_t; #endif extern int yyleng; extern FILE *yyin, *yyout; #define EOB_ACT_CONTINUE_SCAN 0 #define EOB_ACT_END_OF_FILE 1 #define EOB_ACT_LAST_MATCH 2 #define YY_LESS_LINENO(n) #define YY_LINENO_REWIND_TO(ptr) /* Return all but the first "n" matched characters back to the input stream. */ #define yyless(n) \ do \ { \ /* Undo effects of setting up yytext. */ \ int yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ *yy_cp = (yy_hold_char); \ YY_RESTORE_YY_MORE_OFFSET \ (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ YY_DO_BEFORE_ACTION; /* set up yytext again */ \ } \ while ( 0 ) #define unput(c) yyunput( c, (yytext_ptr) ) #ifndef YY_STRUCT_YY_BUFFER_STATE #define YY_STRUCT_YY_BUFFER_STATE struct yy_buffer_state { FILE *yy_input_file; char *yy_ch_buf; /* input buffer */ char *yy_buf_pos; /* current position in input buffer */ /* Size of input buffer in bytes, not including room for EOB * characters. */ int yy_buf_size; /* Number of characters read into yy_ch_buf, not including EOB * characters. */ int yy_n_chars; /* Whether we "own" the buffer - i.e., we know we created it, * and can realloc() it to grow it, and should free() it to * delete it. */ int yy_is_our_buffer; /* Whether this is an "interactive" input source; if so, and * if we're using stdio for input, then we want to use getc() * instead of fread(), to make sure we stop fetching input after * each newline. */ int yy_is_interactive; /* Whether we're considered to be at the beginning of a line. * If so, '^' rules will be active on the next match, otherwise * not. */ int yy_at_bol; int yy_bs_lineno; /**< The line count. */ int yy_bs_column; /**< The column count. */ /* Whether to try to fill the input buffer when we reach the * end of it. */ int yy_fill_buffer; int yy_buffer_status; #define YY_BUFFER_NEW 0 #define YY_BUFFER_NORMAL 1 /* When an EOF's been seen but there's still some text to process * then we mark the buffer as YY_EOF_PENDING, to indicate that we * shouldn't try reading from the input source any more. We might * still have a bunch of tokens to match, though, because of * possible backing-up. * * When we actually see the EOF, we change the status to "new" * (via yyrestart()), so that the user can continue scanning by * just pointing yyin at a new input file. */ #define YY_BUFFER_EOF_PENDING 2 }; #endif /* !YY_STRUCT_YY_BUFFER_STATE */ /* Stack of input buffers. */ static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ static YY_BUFFER_STATE * yy_buffer_stack = NULL; /**< Stack as an array. */ /* We provide macros for accessing buffer states in case in the * future we want to put the buffer states in a more general * "scanner state". * * Returns the top of the stack, or NULL. */ #define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ : NULL) /* Same as previous macro, but useful when we know that the buffer stack is not * NULL or when we need an lvalue. For internal use only. */ #define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] /* yy_hold_char holds the character lost when yytext is formed. */ static char yy_hold_char; static int yy_n_chars; /* number of characters read into yy_ch_buf */ int yyleng; /* Points to current character in buffer. */ static char *yy_c_buf_p = NULL; static int yy_init = 0; /* whether we need to initialize */ static int yy_start = 0; /* start state number */ /* Flag which is used to allow yywrap()'s to do buffer switches * instead of setting up a fresh yyin. A bit of a hack ... */ static int yy_did_buffer_switch_on_eof; void yyrestart ( FILE *input_file ); void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer ); YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size ); void yy_delete_buffer ( YY_BUFFER_STATE b ); void yy_flush_buffer ( YY_BUFFER_STATE b ); void yypush_buffer_state ( YY_BUFFER_STATE new_buffer ); void yypop_buffer_state ( void ); static void yyensure_buffer_stack ( void ); static void yy_load_buffer_state ( void ); static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file ); #define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER ) YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size ); YY_BUFFER_STATE yy_scan_string ( const char *yy_str ); YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len ); void *yyalloc ( yy_size_t ); void *yyrealloc ( void *, yy_size_t ); void yyfree ( void * ); #define yy_new_buffer yy_create_buffer #define yy_set_interactive(is_interactive) \ { \ if ( ! YY_CURRENT_BUFFER ){ \ yyensure_buffer_stack (); \ YY_CURRENT_BUFFER_LVALUE = \ yy_create_buffer( yyin, YY_BUF_SIZE ); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ } #define yy_set_bol(at_bol) \ { \ if ( ! YY_CURRENT_BUFFER ){\ yyensure_buffer_stack (); \ YY_CURRENT_BUFFER_LVALUE = \ yy_create_buffer( yyin, YY_BUF_SIZE ); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ } #define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) /* Begin user sect3 */ #define orafce_sql_yywrap() (/*CONSTCOND*/1) #define YY_SKIP_YYWRAP typedef flex_uint8_t YY_CHAR; FILE *yyin = NULL, *yyout = NULL; typedef int yy_state_type; extern int yylineno; int yylineno = 1; extern char *yytext; #ifdef yytext_ptr #undef yytext_ptr #endif #define yytext_ptr yytext static yy_state_type yy_get_previous_state ( void ); static yy_state_type yy_try_NUL_trans ( yy_state_type current_state ); static int yy_get_next_buffer ( void ); static void yynoreturn yy_fatal_error ( const char* msg ); /* Done after the current pattern has been matched and before the * corresponding action - sets up yytext. */ #define YY_DO_BEFORE_ACTION \ (yytext_ptr) = yy_bp; \ yyleng = (int) (yy_cp - yy_bp); \ (yy_hold_char) = *yy_cp; \ *yy_cp = '\0'; \ (yy_c_buf_p) = yy_cp; #define YY_NUM_RULES 53 #define YY_END_OF_BUFFER 54 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info { flex_int32_t yy_verify; flex_int32_t yy_nxt; }; static const flex_int16_t yy_accept[155] = { 0, 0, 0, 13, 13, 0, 0, 0, 0, 12, 12, 0, 0, 0, 0, 0, 0, 54, 52, 1, 1, 44, 38, 52, 43, 20, 43, 43, 43, 43, 46, 43, 51, 51, 51, 51, 51, 13, 10, 6, 6, 7, 7, 41, 39, 12, 17, 26, 26, 22, 31, 25, 22, 35, 35, 37, 1, 44, 32, 45, 33, 2, 47, 3, 47, 46, 49, 42, 51, 9, 21, 19, 16, 13, 10, 10, 11, 6, 8, 5, 4, 41, 40, 12, 17, 17, 18, 26, 22, 22, 24, 23, 27, 28, 27, 25, 35, 34, 36, 33, 2, 2, 3, 47, 50, 48, 10, 15, 11, 0, 4, 17, 14, 18, 0, 22, 30, 23, 0, 28, 29, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } ; static const YY_CHAR yy_ec[256] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 2, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 5, 6, 5, 7, 8, 5, 9, 10, 10, 11, 12, 10, 13, 14, 15, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 18, 10, 8, 8, 8, 5, 5, 19, 20, 19, 19, 21, 19, 22, 22, 22, 22, 22, 22, 22, 23, 22, 22, 22, 22, 22, 22, 22, 22, 22, 24, 22, 22, 10, 25, 10, 8, 22, 5, 19, 20, 19, 19, 21, 19, 22, 22, 22, 22, 22, 22, 22, 23, 22, 22, 22, 22, 22, 22, 22, 22, 22, 26, 22, 22, 1, 5, 1, 5, 1, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22 } ; static const YY_CHAR yy_meta[27] = { 0, 1, 2, 3, 3, 4, 5, 6, 4, 7, 1, 8, 4, 9, 1, 8, 10, 10, 1, 11, 11, 11, 12, 12, 12, 13, 12 } ; static const flex_int16_t yy_base[193] = { 0, 0, 0, 201, 200, 22, 33, 202, 201, 197, 196, 33, 40, 195, 190, 25, 44, 198, 711, 50, 53, 0, 711, 43, 0, 711, 711, 184, 23, 185, 52, 177, 0, 185, 184, 183, 178, 0, 72, 0, 0, 52, 175, 0, 179, 0, 84, 0, 0, 96, 45, 0, 0, 0, 0, 177, 75, 0, 711, 64, 176, 105, 73, 0, 75, 0, 109, 711, 0, 711, 711, 711, 711, 0, 0, 93, 169, 0, 92, 711, 0, 0, 711, 0, 0, 95, 116, 0, 110, 102, 711, 101, 711, 96, 0, 0, 0, 711, 94, 88, 0, 122, 0, 107, 66, 115, 127, 711, 80, 139, 0, 135, 711, 71, 151, 136, 711, 59, 163, 54, 0, 57, 135, 175, 187, 137, 199, 153, 211, 223, 138, 235, 155, 247, 259, 159, 271, 711, 711, 157, 160, 0, 49, 283, 159, 161, 0, 18, 295, 177, 162, 0, 16, 307, 711, 320, 333, 346, 359, 372, 385, 398, 408, 412, 419, 431, 444, 457, 470, 483, 495, 508, 521, 529, 536, 548, 558, 566, 572, 580, 588, 588, 594, 606, 619, 632, 636, 647, 659, 668, 680, 689, 701 } ; static const flex_int16_t yy_def[193] = { 0, 154, 1, 155, 155, 156, 156, 157, 157, 158, 158, 159, 159, 160, 160, 161, 161, 154, 154, 154, 154, 162, 154, 163, 162, 154, 154, 162, 154, 162, 154, 154, 164, 164, 164, 164, 164, 165, 154, 166, 166, 154, 154, 167, 154, 168, 154, 169, 169, 154, 170, 171, 49, 172, 172, 173, 154, 162, 154, 154, 174, 175, 154, 176, 154, 30, 154, 154, 164, 154, 154, 154, 154, 165, 38, 177, 154, 166, 154, 154, 178, 167, 154, 168, 46, 179, 154, 169, 49, 180, 154, 154, 154, 154, 181, 171, 172, 154, 182, 174, 175, 175, 176, 154, 154, 154, 177, 154, 154, 183, 178, 179, 154, 154, 184, 180, 154, 154, 185, 154, 186, 182, 187, 183, 183, 188, 183, 189, 184, 184, 190, 184, 191, 185, 185, 192, 185, 154, 154, 187, 188, 140, 154, 183, 189, 190, 145, 154, 184, 191, 192, 150, 154, 185, 0, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154 } ; static const flex_int16_t yy_nxt[738] = { 0, 18, 19, 20, 19, 21, 22, 23, 24, 25, 26, 24, 24, 27, 28, 29, 30, 30, 31, 32, 33, 34, 32, 35, 36, 18, 36, 40, 54, 132, 40, 127, 55, 41, 40, 40, 48, 42, 40, 62, 62, 40, 49, 48, 41, 40, 40, 54, 42, 49, 58, 55, 56, 56, 56, 56, 56, 56, 50, 59, 59, 93, 122, 78, 97, 50, 64, 79, 65, 65, 137, 94, 132, 66, 74, 75, 75, 56, 56, 56, 59, 59, 105, 105, 127, 76, 84, 85, 85, 62, 62, 103, 103, 122, 66, 58, 66, 86, 88, 89, 89, 97, 107, 78, 112, 90, 108, 79, 113, 91, 101, 116, 119, 101, 118, 117, 101, 101, 101, 154, 101, 104, 104, 103, 103, 105, 105, 101, 66, 114, 101, 105, 105, 101, 101, 101, 107, 101, 140, 140, 108, 124, 125, 125, 112, 116, 107, 112, 113, 117, 142, 147, 126, 129, 130, 130, 145, 145, 150, 150, 140, 140, 145, 145, 131, 134, 135, 135, 116, 107, 112, 116, 152, 142, 147, 152, 136, 124, 125, 125, 150, 150, 109, 58, 97, 82, 80, 72, 126, 124, 125, 125, 71, 70, 69, 67, 63, 61, 154, 52, 126, 124, 125, 125, 52, 46, 46, 44, 44, 38, 38, 154, 143, 129, 130, 130, 154, 154, 154, 154, 154, 154, 154, 154, 131, 129, 130, 130, 154, 154, 154, 154, 154, 154, 154, 154, 131, 129, 130, 130, 154, 154, 154, 154, 154, 154, 154, 154, 148, 134, 135, 135, 154, 154, 154, 154, 154, 154, 154, 154, 136, 134, 135, 135, 154, 154, 154, 154, 154, 154, 154, 154, 136, 134, 135, 135, 154, 154, 154, 154, 154, 154, 154, 154, 153, 124, 125, 125, 154, 154, 154, 154, 154, 154, 154, 154, 143, 129, 130, 130, 154, 154, 154, 154, 154, 154, 154, 154, 148, 134, 135, 135, 154, 154, 154, 154, 154, 154, 154, 154, 153, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 57, 154, 154, 154, 57, 57, 60, 154, 154, 154, 60, 60, 60, 68, 154, 154, 154, 68, 68, 68, 73, 73, 73, 73, 73, 73, 154, 73, 73, 73, 73, 73, 73, 77, 77, 77, 77, 77, 77, 77, 154, 77, 77, 77, 77, 77, 81, 81, 81, 81, 154, 81, 81, 81, 81, 81, 81, 81, 81, 83, 83, 83, 83, 83, 83, 154, 83, 83, 83, 83, 83, 83, 87, 87, 87, 87, 87, 87, 154, 87, 87, 87, 87, 87, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 95, 95, 95, 95, 95, 95, 154, 95, 95, 95, 95, 95, 95, 96, 96, 96, 96, 96, 154, 96, 96, 96, 96, 96, 96, 96, 98, 154, 154, 154, 154, 98, 98, 99, 154, 154, 154, 99, 99, 99, 100, 100, 154, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 102, 154, 154, 154, 102, 102, 106, 106, 154, 154, 154, 106, 154, 106, 110, 154, 154, 154, 110, 110, 111, 111, 154, 154, 154, 111, 154, 111, 115, 115, 154, 154, 154, 115, 154, 115, 120, 120, 121, 154, 154, 154, 121, 121, 121, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 138, 138, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 141, 141, 154, 154, 154, 141, 154, 141, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 146, 146, 154, 154, 154, 146, 154, 146, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 151, 151, 154, 154, 154, 151, 154, 151, 17, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154 } ; static const flex_int16_t yy_chk[738] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 15, 152, 5, 147, 15, 5, 5, 5, 11, 5, 6, 28, 28, 6, 11, 12, 6, 6, 6, 16, 6, 12, 23, 16, 19, 19, 19, 20, 20, 20, 11, 23, 23, 50, 142, 41, 121, 12, 30, 41, 30, 30, 119, 50, 117, 30, 38, 38, 38, 56, 56, 56, 59, 59, 104, 104, 113, 38, 46, 46, 46, 62, 62, 64, 64, 108, 62, 99, 64, 46, 49, 49, 49, 98, 75, 78, 85, 49, 75, 78, 85, 49, 61, 89, 93, 61, 91, 89, 61, 61, 61, 88, 61, 66, 66, 103, 103, 66, 66, 101, 103, 86, 101, 105, 105, 101, 101, 101, 106, 101, 122, 122, 106, 109, 109, 109, 111, 115, 125, 130, 111, 115, 125, 130, 109, 114, 114, 114, 127, 127, 132, 132, 139, 139, 144, 144, 114, 118, 118, 118, 135, 140, 145, 150, 135, 140, 145, 150, 118, 123, 123, 123, 149, 149, 76, 60, 55, 44, 42, 36, 123, 124, 124, 124, 35, 34, 33, 31, 29, 27, 17, 14, 124, 126, 126, 126, 13, 10, 9, 8, 7, 4, 3, 0, 126, 128, 128, 128, 0, 0, 0, 0, 0, 0, 0, 0, 128, 129, 129, 129, 0, 0, 0, 0, 0, 0, 0, 0, 129, 131, 131, 131, 0, 0, 0, 0, 0, 0, 0, 0, 131, 133, 133, 133, 0, 0, 0, 0, 0, 0, 0, 0, 133, 134, 134, 134, 0, 0, 0, 0, 0, 0, 0, 0, 134, 136, 136, 136, 0, 0, 0, 0, 0, 0, 0, 0, 136, 143, 143, 143, 0, 0, 0, 0, 0, 0, 0, 0, 143, 148, 148, 148, 0, 0, 0, 0, 0, 0, 0, 0, 148, 153, 153, 153, 0, 0, 0, 0, 0, 0, 0, 0, 153, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 162, 0, 0, 0, 162, 162, 163, 0, 0, 0, 163, 163, 163, 164, 0, 0, 0, 164, 164, 164, 165, 165, 165, 165, 165, 165, 0, 165, 165, 165, 165, 165, 165, 166, 166, 166, 166, 166, 166, 166, 0, 166, 166, 166, 166, 166, 167, 167, 167, 167, 0, 167, 167, 167, 167, 167, 167, 167, 167, 168, 168, 168, 168, 168, 168, 0, 168, 168, 168, 168, 168, 168, 169, 169, 169, 169, 169, 169, 0, 169, 169, 169, 169, 169, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 171, 171, 171, 171, 171, 171, 0, 171, 171, 171, 171, 171, 171, 172, 172, 172, 172, 172, 0, 172, 172, 172, 172, 172, 172, 172, 173, 0, 0, 0, 0, 173, 173, 174, 0, 0, 0, 174, 174, 174, 175, 175, 0, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 176, 0, 0, 0, 176, 176, 177, 177, 0, 0, 0, 177, 0, 177, 178, 0, 0, 0, 178, 178, 179, 179, 0, 0, 0, 179, 0, 179, 180, 180, 0, 0, 0, 180, 0, 180, 181, 181, 182, 0, 0, 0, 182, 182, 182, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 186, 186, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 188, 188, 0, 0, 0, 188, 0, 188, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 190, 190, 0, 0, 0, 190, 0, 190, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 192, 192, 0, 0, 0, 192, 0, 192, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154 } ; static yy_state_type yy_last_accepting_state; static char *yy_last_accepting_cpos; extern int yy_flex_debug; int yy_flex_debug = 0; /* The intent behind this definition is that it'll catch * any uses of REJECT which flex missed. */ #define REJECT reject_used_but_not_detected #define yymore() yymore_used_but_not_detected #define YY_MORE_ADJ 0 #define YY_RESTORE_YY_MORE_OFFSET char *yytext; #line 1 "sqlscan.l" #line 2 "sqlscan.l" /* ** A scanner for EMP-style numeric ranges */ #include "postgres.h" #include "parser/gramparse.h" /* Not needed now that this file is compiled as part of gram.y */ /* #include "parser/parse.h" */ #include "parser/scansup.h" #include "mb/pg_wchar.h" #include "parse_keyword.h" /* Avoid exit() on fatal scanner errors (a bit ugly -- see yy_fatal_error) */ #undef fprintf #define fprintf(file, fmt, msg) fprintf_to_ereport(fmt, msg) static void fprintf_to_ereport(const char *fmt, const char *msg) { ereport(ERROR, (errmsg_internal("%s", msg))); } static int xcdepth = 0; /* depth of nesting in slash-star comments */ static char *dolqstart; /* current $foo$ quote start string */ static bool extended_string = false; /* No reason to constrain amount of data slurped */ #define YY_READ_BUF_SIZE 16777216 /* Handles to the buffer that the lexer uses internally */ static YY_BUFFER_STATE scanbufhandle; #define SET_YYLLOC() (orafce_sql_yylval.val.lloc = yytext - scanbuf) /* Handles to the buffer that the lexer uses internally */ static char *scanbuf; /* flex 2.5.4 doesn't bother with a decl for this */ int orafce_sql_yylex(void); void orafce_sql_scanner_init(const char *str); void orafce_sql_scanner_finish(void); /* * literalbuf is used to accumulate literal values when multiple rules * are needed to parse a single literal. Call startlit to reset buffer * to empty, addlit to add text. Note that the buffer is palloc'd and * starts life afresh on every parse cycle. */ static char *literalbuf; /* expandable buffer */ static int literallen; /* actual current length */ static int literalalloc; /* current allocated buffer size */ #define startlit() (literalbuf[0] = '\0', literallen = 0) static void addlit(char *ytext, int yleng); static void addlitchar(unsigned char ychar); static char *litbufdup(void); static int lexer_errposition(void); /* * Each call to yylex must set yylloc to the location of the found token * (expressed as a byte offset from the start of the input text). * When we parse a token that requires multiple lexer rules to process, * this should be done in the first such rule, else yylloc will point * into the middle of the token. */ /* Handles to the buffer that the lexer uses internally */ static char *scanbuf; static unsigned char unescape_single_char(unsigned char c); #ifndef _pg_mbstrlen_with_len #define _pg_mbstrlen_with_len(buf,loc) pg_mbstrlen_with_len(buf,loc) #endif #line 1007 "sqlscan.c" #define YY_NO_INPUT 1 /* * OK, here is a short description of lex/flex rules behavior. * The longest pattern which matches an input string is always chosen. * For equal-length patterns, the first occurring in the rules list is chosen. * INITIAL is the starting state, to which all non-conditional rules apply. * Exclusive states change parsing rules while the state is active. When in * an exclusive state, only those rules defined for that state apply. * * We use exclusive states for quoted strings, extended comments, * and to eliminate parsing troubles for numeric strings. * Exclusive states: * bit string literal * extended C-style comments * delimited identifiers (double-quoted identifiers) * hexadecimal numeric string * standard quoted strings * extended quoted strings (support backslash escape sequences) * $foo$ quoted strings */ /* * In order to make the world safe for Windows and Mac clients as well as * Unix ones, we accept either \n or \r as a newline. A DOS-style \r\n * sequence will be seen as two successive newlines, but that doesn't cause * any problems. Comments that start with -- and extend to the next * newline are treated as equivalent to a single whitespace character. * * NOTE a fine point: if there is no newline following --, we will absorb * everything to the end of the input as a comment. This is correct. Older * versions of Postgres failed to recognize -- as a comment if the input * did not end with a newline. * * XXX perhaps \f (formfeed) should be treated as a newline as well? * * XXX if you change the set of whitespace characters, fix scanner_isspace() * to agree, and see also the plpgsql lexer. */ /* * SQL requires at least one newline in the whitespace separating * string literals that are to be concatenated. Silly, but who are we * to argue? Note that {whitespace_with_newline} should not have * after * it, whereas {whitespace} should generally have a * after it... */ /* * To ensure that {quotecontinue} can be scanned without having to back up * if the full pattern isn't matched, we include trailing whitespace in * {quotestop}. This matches all cases where {quotecontinue} fails to match, * except for {quote} followed by whitespace and just one "-" (not two, * which would start a {comment}). To cover that we have {quotefail}. * The actions for {quotestop} and {quotefail} must throw back characters * beyond the quote proper. */ /* Bit string * It is tempting to scan the string for only those characters * which are allowed. However, this leads to silently swallowed * characters if illegal characters are included in the string. * For example, if xbinside is [01] then B'ABCD' is interpreted * as a zero-length string, and the ABCD' is lost! * Better to pass the string forward and let the input routines * validate the contents. */ /* Hexadecimal number */ /* National character */ /* Quoted string that allows backslash escapes */ /* Extended quote * xqdouble implements embedded quote, '''' */ /* $foo$ style quotes ("dollar quoting") * The quoted string starts with $foo$ where "foo" is an optional string * in the form of an identifier, except that it may not contain "$", * and extends to the first occurrence of an identical string. * There is *no* processing of the quoted text. * * {dolqfailed} is an error rule to avoid scanner backup when {dolqdelim} * fails to match its trailing "$". */ /* Double quote * Allows embedded spaces and other special characters into identifiers. */ /* C-style comments * * The "extended comment" syntax closely resembles allowable operator syntax. * The tricky part here is to get lex to recognize a string starting with * slash-star as a comment, when interpreting it as an operator would produce * a longer match --- remember lex will prefer a longer match! Also, if we * have something like plus-slash-star, lex will think this is a 3-character * operator whereas we want to see it as a + operator and a comment start. * The solution is two-fold: * 1. append {op_chars}* to xcstart so that it matches as much text as * {operator} would. Then the tie-breaker (first matching rule of same * length) ensures xcstart wins. We put back the extra stuff with yyless() * in case it contains a star-slash that should terminate the comment. * 2. In the operator rule, check for slash-star within the operator, and * if found throw it back with yyless(). This handles the plus-slash-star * problem. * Dash-dash comments have similar interactions with the operator rule. */ /* * "self" is the set of chars that should be returned as single-character * tokens. "op_chars" is the set of chars that can make up "Op" tokens, * which can be one or more characters long (but if a single-char token * appears in the "self" set, it is not to be returned as an Op). Note * that the sets overlap, but each has some chars that are not in the other. * * If you change either set, adjust the character lists appearing in the * rule for "operator"! */ /* we no longer allow unary minus in numbers. * instead we pass it separately to parser. there it gets * coerced via doNegate() -- Leon aug 20 1999 * * {realfail1} and {realfail2} are added to prevent the need for scanner * backup when the {real} rule fails to match completely. */ /* * Dollar quoted strings are totally opaque, and no escaping is done on them. * Other quoted strings must allow some special characters such as single-quote * and newline. * Embedded single-quotes are implemented both in the SQL standard * style of two adjacent single quotes "''" and in the Postgres/Java style * of escaped-quote "\'". * Other embedded escaped characters are matched explicitly and the leading * backslash is dropped from the string. * Note that xcstart must appear before operator, as explained above! * Also whitespace (comment) must appear before operator. */ #line 1135 "sqlscan.c" #define INITIAL 0 #define xb 1 #define xc 2 #define xd 3 #define xh 4 #define xe 5 #define xq 6 #define xdolq 7 #ifndef YY_NO_UNISTD_H /* Special case for "unistd.h", since it is non-ANSI. We include it way * down here because we want the user's section 1 to have been scanned first. * The user has a chance to override it with an option. */ #include #endif #ifndef YY_EXTRA_TYPE #define YY_EXTRA_TYPE void * #endif static int yy_init_globals ( void ); /* Accessor methods to globals. These are made visible to non-reentrant scanners for convenience. */ int yylex_destroy ( void ); int yyget_debug ( void ); void yyset_debug ( int debug_flag ); YY_EXTRA_TYPE yyget_extra ( void ); void yyset_extra ( YY_EXTRA_TYPE user_defined ); FILE *yyget_in ( void ); void yyset_in ( FILE * _in_str ); FILE *yyget_out ( void ); void yyset_out ( FILE * _out_str ); int yyget_leng ( void ); char *yyget_text ( void ); int yyget_lineno ( void ); void yyset_lineno ( int _line_number ); /* Macros after this point can all be overridden by user definitions in * section 1. */ #ifndef YY_SKIP_YYWRAP #ifdef __cplusplus extern "C" int yywrap ( void ); #else extern int yywrap ( void ); #endif #endif #ifndef YY_NO_UNPUT #endif #ifndef yytext_ptr static void yy_flex_strncpy ( char *, const char *, int ); #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen ( const char * ); #endif #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput ( void ); #else static int input ( void ); #endif #endif /* Amount of stuff to slurp up with each read. */ #ifndef YY_READ_BUF_SIZE #ifdef __ia64__ /* On IA-64, the buffer size is 16k, not 8k */ #define YY_READ_BUF_SIZE 16384 #else #define YY_READ_BUF_SIZE 8192 #endif /* __ia64__ */ #endif /* Copy whatever the last rule matched to the standard output. */ #ifndef ECHO /* This used to be an fputs(), but since the string might contain NUL's, * we now use fwrite(). */ #define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0) #endif /* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, * is returned in "result". */ #ifndef YY_INPUT #define YY_INPUT(buf,result,max_size) \ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ { \ int c = '*'; \ int n; \ for ( n = 0; n < max_size && \ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ buf[n] = (char) c; \ if ( c == '\n' ) \ buf[n++] = (char) c; \ if ( c == EOF && ferror( yyin ) ) \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ result = n; \ } \ else \ { \ errno=0; \ while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \ { \ if( errno != EINTR) \ { \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ break; \ } \ errno=0; \ clearerr(yyin); \ } \ }\ \ #endif /* No semi-colon after return; correct usage is to write "yyterminate();" - * we don't want an extra ';' after the "return" because that will cause * some compilers to complain about unreachable statements. */ #ifndef yyterminate #define yyterminate() return YY_NULL #endif /* Number of entries by which start-condition stack grows. */ #ifndef YY_START_STACK_INCR #define YY_START_STACK_INCR 25 #endif /* Report a fatal error. */ #ifndef YY_FATAL_ERROR #define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) #endif /* end tables serialization structures and prototypes */ /* Default declaration of generated scanner - a define so the user can * easily add parameters. */ #ifndef YY_DECL #define YY_DECL_IS_OURS 1 extern int yylex (void); #define YY_DECL int yylex (void) #endif /* !YY_DECL */ /* Code executed at the beginning of each rule, after yytext and yyleng * have been set up. */ #ifndef YY_USER_ACTION #define YY_USER_ACTION #endif /* Code executed at the end of each rule. */ #ifndef YY_BREAK #define YY_BREAK /*LINTED*/break; #endif #define YY_RULE_SETUP \ YY_USER_ACTION /** The main scanner function which does all the work. */ YY_DECL { yy_state_type yy_current_state; char *yy_cp, *yy_bp; int yy_act; if ( !(yy_init) ) { (yy_init) = 1; #ifdef YY_USER_INIT YY_USER_INIT; #endif if ( ! (yy_start) ) (yy_start) = 1; /* first start state */ if ( ! yyin ) yyin = stdin; if ( ! yyout ) yyout = stdout; if ( ! YY_CURRENT_BUFFER ) { yyensure_buffer_stack (); YY_CURRENT_BUFFER_LVALUE = yy_create_buffer( yyin, YY_BUF_SIZE ); } yy_load_buffer_state( ); } { #line 308 "sqlscan.l" #line 1360 "sqlscan.c" while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ { yy_cp = (yy_c_buf_p); /* Support of yytext. */ *yy_cp = (yy_hold_char); /* yy_bp points to the position in yy_ch_buf of the start of * the current run. */ yy_bp = yy_cp; yy_current_state = (yy_start); yy_match: do { YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ; if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 155 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; ++yy_cp; } while ( yy_current_state != 154 ); yy_cp = (yy_last_accepting_cpos); yy_current_state = (yy_last_accepting_state); yy_find_action: yy_act = yy_accept[yy_current_state]; YY_DO_BEFORE_ACTION; do_action: /* This label is used only to access EOF actions. */ switch ( yy_act ) { /* beginning of action switch */ case 0: /* must back up */ /* undo the effects of YY_DO_BEFORE_ACTION */ *yy_cp = (yy_hold_char); yy_cp = (yy_last_accepting_cpos); yy_current_state = (yy_last_accepting_state); goto yy_find_action; case 1: /* rule 1 can match eol */ YY_RULE_SETUP #line 310 "sqlscan.l" { SET_YYLLOC(); yylval.val.str = yytext; yylval.val.modificator = NULL; yylval.val.keycode = -1; yylval.val.sep = NULL; return X_WHITESPACE; } YY_BREAK case 2: YY_RULE_SETUP #line 319 "sqlscan.l" { SET_YYLLOC(); yylval.val.str = yytext; yylval.val.modificator = "sc"; yylval.val.keycode = -1; yylval.val.sep = NULL; return X_COMMENT; } YY_BREAK case 3: YY_RULE_SETUP #line 329 "sqlscan.l" { /* Set location in case of syntax error in comment */ SET_YYLLOC(); xcdepth = 0; BEGIN(xc); /* Put back any characters past slash-star; see above */ startlit(); addlitchar('/'); addlitchar('*'); yyless(2); } YY_BREAK case 4: YY_RULE_SETUP #line 342 "sqlscan.l" { xcdepth++; /* Put back any characters past slash-star; see above */ addlitchar('/'); addlitchar('*'); yyless(2); } YY_BREAK case 5: YY_RULE_SETUP #line 351 "sqlscan.l" { if (xcdepth <= 0) { BEGIN(INITIAL); addlitchar('*'); addlitchar('/'); yylval.val.str = litbufdup(); yylval.val.modificator = "ec"; yylval.val.keycode = -1; yylval.val.sep = NULL; return X_COMMENT; } else { xcdepth--; addlitchar('*'); addlitchar('/'); } } YY_BREAK case 6: /* rule 6 can match eol */ YY_RULE_SETUP #line 373 "sqlscan.l" { addlit(yytext, yyleng); } YY_BREAK case 7: YY_RULE_SETUP #line 377 "sqlscan.l" { addlit(yytext, yyleng); } YY_BREAK case 8: YY_RULE_SETUP #line 381 "sqlscan.l" { addlit(yytext, yyleng); } YY_BREAK case YY_STATE_EOF(xc): #line 385 "sqlscan.l" { yylval.val.str = litbufdup(); yylval.val.modificator = "ecu"; yylval.val.keycode = -1; yylval.val.sep = NULL; return X_COMMENT; } YY_BREAK case 9: YY_RULE_SETUP #line 394 "sqlscan.l" { /* Binary bit type. * At some point we should simply pass the string * forward to the parser and label it there. * In the meantime, place a leading "b" on the string * to mark it for the input routine as a binary string. */ SET_YYLLOC(); BEGIN(xb); startlit(); addlitchar('b'); } YY_BREAK case 10: /* rule 10 can match eol */ #line 407 "sqlscan.l" case 11: /* rule 11 can match eol */ YY_RULE_SETUP #line 407 "sqlscan.l" { yyless(1); BEGIN(INITIAL); yylval.val.str = litbufdup(); yylval.val.modificator = "b"; yylval.val.keycode = -1; yylval.val.sep = NULL; return X_NCONST; } YY_BREAK case 12: /* rule 12 can match eol */ #line 417 "sqlscan.l" case 13: /* rule 13 can match eol */ YY_RULE_SETUP #line 417 "sqlscan.l" { addlit(yytext, yyleng); } YY_BREAK case 14: /* rule 14 can match eol */ #line 421 "sqlscan.l" case 15: /* rule 15 can match eol */ YY_RULE_SETUP #line 421 "sqlscan.l" { /* ignore */ } YY_BREAK case YY_STATE_EOF(xb): #line 424 "sqlscan.l" { yylval.val.str = litbufdup(); yylval.val.modificator = "bu"; yylval.val.keycode = -1; yylval.val.sep = NULL; return X_NCONST; } YY_BREAK case 16: YY_RULE_SETUP #line 432 "sqlscan.l" { /* Hexadecimal bit type. * At some point we should simply pass the string * forward to the parser and label it there. * In the meantime, place a leading "x" on the string * to mark it for the input routine as a hex string. */ SET_YYLLOC(); BEGIN(xh); startlit(); addlitchar('x'); } YY_BREAK case 17: /* rule 17 can match eol */ #line 445 "sqlscan.l" case 18: /* rule 18 can match eol */ YY_RULE_SETUP #line 445 "sqlscan.l" { yyless(1); BEGIN(INITIAL); yylval.val.str = litbufdup(); yylval.val.modificator = "x"; yylval.val.keycode = -1; yylval.val.sep = NULL; return X_NCONST; } YY_BREAK case YY_STATE_EOF(xh): #line 454 "sqlscan.l" { yylval.val.str = litbufdup(); yylval.val.modificator = "xu"; yylval.val.keycode = -1; yylval.val.sep = NULL; return X_NCONST; } YY_BREAK case 19: YY_RULE_SETUP #line 462 "sqlscan.l" { /* National character. * We will pass this along as a normal character string, * but preceded with an internally-generated "NCHAR". */ const char *keyword; int keycode; SET_YYLLOC(); yyless(1); /* eat only 'n' this time */ /* nchar had better be a keyword! */ keyword = orafce_scan_keyword("nchar", &keycode); Assert(keyword != NULL); yylval.val.str = (char*) keyword; yylval.val.keycode = keycode; yylval.val.modificator = NULL; yylval.val.sep = NULL; return X_KEYWORD; } YY_BREAK case 20: YY_RULE_SETUP #line 482 "sqlscan.l" { SET_YYLLOC(); BEGIN(xq); extended_string = false; startlit(); } YY_BREAK case 21: YY_RULE_SETUP #line 488 "sqlscan.l" { SET_YYLLOC(); BEGIN(xe); extended_string = true; startlit(); } YY_BREAK case 22: /* rule 22 can match eol */ #line 495 "sqlscan.l" case 23: /* rule 23 can match eol */ YY_RULE_SETUP #line 495 "sqlscan.l" { yyless(1); BEGIN(INITIAL); yylval.val.str = litbufdup(); yylval.val.modificator = extended_string ? "es" : "qs"; yylval.val.keycode = -1; yylval.val.sep = NULL; return X_SCONST; } YY_BREAK case 24: YY_RULE_SETUP #line 504 "sqlscan.l" { addlitchar('\''); } YY_BREAK case 25: /* rule 25 can match eol */ YY_RULE_SETUP #line 507 "sqlscan.l" { addlit(yytext, yyleng); } YY_BREAK case 26: /* rule 26 can match eol */ YY_RULE_SETUP #line 510 "sqlscan.l" { addlit(yytext, yyleng); } YY_BREAK case 27: /* rule 27 can match eol */ YY_RULE_SETUP #line 513 "sqlscan.l" { addlitchar(unescape_single_char(yytext[1])); } YY_BREAK case 28: YY_RULE_SETUP #line 516 "sqlscan.l" { unsigned char c = strtoul(yytext+1, NULL, 8); addlitchar(c); } YY_BREAK case 29: YY_RULE_SETUP #line 521 "sqlscan.l" { unsigned char c = strtoul(yytext+2, NULL, 16); addlitchar(c); } YY_BREAK case 30: /* rule 30 can match eol */ YY_RULE_SETUP #line 526 "sqlscan.l" { /* ignore */ } YY_BREAK case 31: YY_RULE_SETUP #line 529 "sqlscan.l" { /* This is only needed for \ just before EOF */ addlitchar(yytext[0]); } YY_BREAK case YY_STATE_EOF(xq): case YY_STATE_EOF(xe): #line 533 "sqlscan.l" { yylval.val.str = litbufdup(); yylval.val.modificator = extended_string ? "esu" : "qsu"; yylval.val.keycode = -1; yylval.val.sep = NULL; return X_SCONST; } YY_BREAK case 32: YY_RULE_SETUP #line 541 "sqlscan.l" { SET_YYLLOC(); dolqstart = pstrdup(yytext); BEGIN(xdolq); startlit(); } YY_BREAK case 33: YY_RULE_SETUP #line 547 "sqlscan.l" { /* throw back all but the initial "$" */ yyless(1); /* and treat it as {other} */ yylval.val.str = yytext; yylval.val.modificator = "dolqf"; yylval.val.keycode = -1; yylval.val.sep = NULL; return X_OTHERS; } YY_BREAK case 34: YY_RULE_SETUP #line 557 "sqlscan.l" { if (strcmp(yytext, dolqstart) == 0) { yylval.val.sep = dolqstart; yylval.val.modificator = "dolq"; BEGIN(INITIAL); yylval.val.str = litbufdup(); yylval.val.keycode = -1; return X_SCONST; } else { /* * When we fail to match $...$ to dolqstart, transfer * the $... part to the output, but put back the final * $ for rescanning. Consider $delim$...$junk$delim$ */ addlit(yytext, yyleng-1); yyless(yyleng-1); } } YY_BREAK case 35: /* rule 35 can match eol */ YY_RULE_SETUP #line 578 "sqlscan.l" { addlit(yytext, yyleng); } YY_BREAK case 36: YY_RULE_SETUP #line 581 "sqlscan.l" { addlit(yytext, yyleng); } YY_BREAK case 37: YY_RULE_SETUP #line 584 "sqlscan.l" { /* This is only needed for inside the quoted text */ addlitchar(yytext[0]); } YY_BREAK case YY_STATE_EOF(xdolq): #line 588 "sqlscan.l" { yylval.val.sep = dolqstart; yylval.val.modificator = "dolqu"; yylval.val.str = litbufdup(); yylval.val.keycode = -1; yylval.val.sep = NULL; return X_SCONST; } YY_BREAK case 38: YY_RULE_SETUP #line 597 "sqlscan.l" { SET_YYLLOC(); BEGIN(xd); startlit(); } YY_BREAK case 39: YY_RULE_SETUP #line 602 "sqlscan.l" { char *ident; BEGIN(INITIAL); if (literallen == 0) yyerror(NULL, "zero-length delimited identifier"); ident = litbufdup(); if (literallen >= NAMEDATALEN) truncate_identifier(ident, literallen, true); yylval.val.modificator = "dq"; yylval.val.str = ident; yylval.val.keycode = -1; yylval.val.sep = NULL; return X_IDENT; } YY_BREAK case 40: YY_RULE_SETUP #line 617 "sqlscan.l" { addlitchar('"'); } YY_BREAK case 41: /* rule 41 can match eol */ YY_RULE_SETUP #line 620 "sqlscan.l" { addlit(yytext, yyleng); } YY_BREAK case YY_STATE_EOF(xd): #line 623 "sqlscan.l" { yylval.val.modificator = "dqu"; yylval.val.str = litbufdup(); yylval.val.keycode = -1; yylval.val.sep = NULL; return X_IDENT; } YY_BREAK case 42: YY_RULE_SETUP #line 630 "sqlscan.l" { SET_YYLLOC(); yylval.val.modificator = "typecast"; yylval.val.keycode = X_TYPECAST; yylval.val.sep = NULL; return X_OTHERS; } YY_BREAK case 43: YY_RULE_SETUP #line 638 "sqlscan.l" { SET_YYLLOC(); yylval.val.str = yytext; yylval.val.modificator = "self"; yylval.val.keycode = yytext[0]; yylval.val.sep = NULL; return X_OTHERS; } YY_BREAK case 44: YY_RULE_SETUP #line 647 "sqlscan.l" { /* * Check for embedded slash-star or dash-dash; those * are comment starts, so operator must stop there. * Note that slash-star or dash-dash at the first * character will match a prior rule, not this one. */ int nchars = yyleng; char *slashstar = strstr(yytext, "/*"); char *dashdash = strstr(yytext, "--"); if (slashstar && dashdash) { /* if both appear, take the first one */ if (slashstar > dashdash) slashstar = dashdash; } else if (!slashstar) slashstar = dashdash; if (slashstar) nchars = slashstar - yytext; /* * For SQL compatibility, '+' and '-' cannot be the * last char of a multi-char operator unless the operator * contains chars that are not in SQL operators. * The idea is to lex '=-' as two operators, but not * to forbid operator names like '?-' that could not be * sequences of SQL operators. */ while (nchars > 1 && (yytext[nchars-1] == '+' || yytext[nchars-1] == '-')) { int ic; for (ic = nchars-2; ic >= 0; ic--) { if (strchr("~!@#^&|`?%", yytext[ic])) break; } if (ic >= 0) break; /* found a char that makes it OK */ nchars--; /* else remove the +/-, and check again */ } SET_YYLLOC(); if (nchars < yyleng) { /* Strip the unwanted chars from the token */ yyless(nchars); /* * If what we have left is only one char, and it's * one of the characters matching "self", then * return it as a character token the same way * that the "self" rule would have. */ if (nchars == 1 && strchr(",()[].;:+-*/%^<>=", yytext[0])) { yylval.val.str = yytext; yylval.val.modificator = NULL; yylval.val.keycode = yytext[0]; yylval.val.sep = NULL; return X_OTHERS; } } /* * Complain if operator is too long. Unlike the case * for identifiers, we make this an error not a notice- * and-truncate, because the odds are we are looking at * a syntactic mistake anyway. */ if (nchars >= NAMEDATALEN) yyerror(NULL, "operator too long"); /* Convert "!=" operator to "<>" for compatibility */ yylval.val.modificator = NULL; if (strcmp(yytext, "!=") == 0) yylval.val.str = pstrdup("<>"); else yylval.val.str = pstrdup(yytext); yylval.val.keycode = -1; yylval.val.sep = NULL; return X_OP; } YY_BREAK case 45: YY_RULE_SETUP #line 736 "sqlscan.l" { SET_YYLLOC(); yylval.val.modificator = NULL; yylval.val.str = yytext; yylval.val.keycode = -1; yylval.val.sep = NULL; return X_PARAM; } YY_BREAK case 46: YY_RULE_SETUP #line 745 "sqlscan.l" { long val; char* endptr; SET_YYLLOC(); errno = 0; val = strtol(yytext, &endptr, 10); if (*endptr != '\0' || errno == ERANGE #ifdef HAVE_LONG_INT_64 /* if long > 32 bits, check for overflow of int4 */ || val != (long) ((int32) val) #endif ) { /* integer too large, treat it as a float */ yylval.val.str = pstrdup(yytext); yylval.val.modificator = "f"; yylval.val.keycode = -1; yylval.val.sep = NULL; return X_NCONST; } yylval.val.str = yytext; yylval.val.modificator = "i"; yylval.val.keycode = -1; yylval.val.sep = NULL; return X_NCONST; } YY_BREAK case 47: YY_RULE_SETUP #line 772 "sqlscan.l" { SET_YYLLOC(); yylval.val.str = pstrdup(yytext); yylval.val.modificator = "f"; yylval.val.keycode = -1; yylval.val.sep = NULL; return X_NCONST; } YY_BREAK case 48: YY_RULE_SETUP #line 780 "sqlscan.l" { SET_YYLLOC(); yylval.val.str = pstrdup(yytext); yylval.val.modificator = "f"; yylval.val.keycode = -1; yylval.val.sep = NULL; return X_NCONST; } YY_BREAK case 49: YY_RULE_SETUP #line 788 "sqlscan.l" { /* * throw back the [Ee], and treat as {decimal}. Note * that it is possible the input is actually {integer}, * but since this case will almost certainly lead to a * syntax error anyway, we don't bother to distinguish. */ yyless(yyleng-1); SET_YYLLOC(); yylval.val.str = pstrdup(yytext); yylval.val.modificator = "f"; yylval.val.keycode = -1; yylval.val.sep = NULL; return X_NCONST; } YY_BREAK case 50: YY_RULE_SETUP #line 803 "sqlscan.l" { /* throw back the [Ee][+-], and proceed as above */ yyless(yyleng-2); SET_YYLLOC(); yylval.val.str = pstrdup(yytext); yylval.val.modificator = "f"; yylval.val.keycode = -1; yylval.val.sep = NULL; return X_NCONST; } YY_BREAK case 51: YY_RULE_SETUP #line 815 "sqlscan.l" { char *ident; const char *keyword; int keycode; SET_YYLLOC(); /* nchar had better be a keyword! */ keyword = orafce_scan_keyword("nchar", &keycode); /* Is it a keyword? */ keyword = orafce_scan_keyword(yytext, &keycode); if (keyword != NULL) { yylval.val.str = (char*) keyword; yylval.val.keycode = keycode; yylval.val.modificator = NULL; yylval.val.sep = NULL; return X_KEYWORD; } /* * No. Convert the identifier to lower case, and truncate * if necessary. */ ident = downcase_truncate_identifier(yytext, yyleng, true); yylval.val.str = ident; yylval.val.modificator = NULL; yylval.val.keycode = -1; yylval.val.sep = NULL; return X_IDENT; } YY_BREAK case 52: YY_RULE_SETUP #line 848 "sqlscan.l" { SET_YYLLOC(); yylval.val.str = yytext; yylval.val.modificator = NULL; yylval.val.keycode = yytext[0]; yylval.val.sep = NULL; return X_OTHERS; } YY_BREAK case YY_STATE_EOF(INITIAL): #line 857 "sqlscan.l" { SET_YYLLOC(); yyterminate(); } YY_BREAK case 53: YY_RULE_SETUP #line 862 "sqlscan.l" YY_FATAL_ERROR( "flex scanner jammed" ); YY_BREAK #line 2179 "sqlscan.c" case YY_END_OF_BUFFER: { /* Amount of text matched not including the EOB char. */ int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; /* Undo the effects of YY_DO_BEFORE_ACTION. */ *yy_cp = (yy_hold_char); YY_RESTORE_YY_MORE_OFFSET if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) { /* We're scanning a new file or input source. It's * possible that this happened because the user * just pointed yyin at a new source and called * yylex(). If so, then we have to assure * consistency between YY_CURRENT_BUFFER and our * globals. Here is the right place to do so, because * this is the first action (other than possibly a * back-up) that will match for the new input source. */ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; } /* Note that here we test for yy_c_buf_p "<=" to the position * of the first EOB in the buffer, since yy_c_buf_p will * already have been incremented past the NUL character * (since all states make transitions on EOB to the * end-of-buffer state). Contrast this with the test * in input(). */ if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) { /* This was really a NUL. */ yy_state_type yy_next_state; (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( ); /* Okay, we're now positioned to make the NUL * transition. We couldn't have * yy_get_previous_state() go ahead and do it * for us because it doesn't know how to deal * with the possibility of jamming (and we don't * want to build jamming into it because then it * will run more slowly). */ yy_next_state = yy_try_NUL_trans( yy_current_state ); yy_bp = (yytext_ptr) + YY_MORE_ADJ; if ( yy_next_state ) { /* Consume the NUL. */ yy_cp = ++(yy_c_buf_p); yy_current_state = yy_next_state; goto yy_match; } else { yy_cp = (yy_last_accepting_cpos); yy_current_state = (yy_last_accepting_state); goto yy_find_action; } } else switch ( yy_get_next_buffer( ) ) { case EOB_ACT_END_OF_FILE: { (yy_did_buffer_switch_on_eof) = 0; if ( yywrap( ) ) { /* Note: because we've taken care in * yy_get_next_buffer() to have set up * yytext, we can now set up * yy_c_buf_p so that if some total * hoser (like flex itself) wants to * call the scanner after we return the * YY_NULL, it'll still work - another * YY_NULL will get returned. */ (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; yy_act = YY_STATE_EOF(YY_START); goto do_action; } else { if ( ! (yy_did_buffer_switch_on_eof) ) YY_NEW_FILE; } break; } case EOB_ACT_CONTINUE_SCAN: (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( ); yy_cp = (yy_c_buf_p); yy_bp = (yytext_ptr) + YY_MORE_ADJ; goto yy_match; case EOB_ACT_LAST_MATCH: (yy_c_buf_p) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; yy_current_state = yy_get_previous_state( ); yy_cp = (yy_c_buf_p); yy_bp = (yytext_ptr) + YY_MORE_ADJ; goto yy_find_action; } break; } default: YY_FATAL_ERROR( "fatal flex scanner internal error--no action found" ); } /* end of action switch */ } /* end of scanning one token */ } /* end of user's declarations */ } /* end of yylex */ /* yy_get_next_buffer - try to read in a new buffer * * Returns a code representing an action: * EOB_ACT_LAST_MATCH - * EOB_ACT_CONTINUE_SCAN - continue scanning from current position * EOB_ACT_END_OF_FILE - end of file */ static int yy_get_next_buffer (void) { char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; char *source = (yytext_ptr); int number_to_move, i; int ret_val; if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) YY_FATAL_ERROR( "fatal flex scanner internal error--end of buffer missed" ); if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) { /* Don't try to fill the buffer, so this is an EOF. */ if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) { /* We matched a single character, the EOB, so * treat this as a final EOF. */ return EOB_ACT_END_OF_FILE; } else { /* We matched some text prior to the EOB, first * process it. */ return EOB_ACT_LAST_MATCH; } } /* Try to read more data. */ /* First move last chars to start of buffer. */ number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr) - 1); for ( i = 0; i < number_to_move; ++i ) *(dest++) = *(source++); if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) /* don't do the read, it's not guaranteed to return an EOF, * just force an EOF */ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; else { int num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; while ( num_to_read <= 0 ) { /* Not enough room in the buffer - grow it. */ /* just a shorter name for the current buffer */ YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE; int yy_c_buf_p_offset = (int) ((yy_c_buf_p) - b->yy_ch_buf); if ( b->yy_is_our_buffer ) { int new_size = b->yy_buf_size * 2; if ( new_size <= 0 ) b->yy_buf_size += b->yy_buf_size / 8; else b->yy_buf_size *= 2; b->yy_ch_buf = (char *) /* Include room in for 2 EOB chars. */ yyrealloc( (void *) b->yy_ch_buf, (yy_size_t) (b->yy_buf_size + 2) ); } else /* Can't grow it, we don't own it. */ b->yy_ch_buf = NULL; if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "fatal error - scanner input buffer overflow" ); (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset]; num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; } if ( num_to_read > YY_READ_BUF_SIZE ) num_to_read = YY_READ_BUF_SIZE; /* Read in more data. */ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), (yy_n_chars), num_to_read ); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } if ( (yy_n_chars) == 0 ) { if ( number_to_move == YY_MORE_ADJ ) { ret_val = EOB_ACT_END_OF_FILE; yyrestart( yyin ); } else { ret_val = EOB_ACT_LAST_MATCH; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_EOF_PENDING; } } else ret_val = EOB_ACT_CONTINUE_SCAN; if (((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { /* Extend the array by 50%, plus the number we really need. */ int new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc( (void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size ); if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); /* "- 2" to take care of EOB's */ YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2); } (yy_n_chars) += number_to_move; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; return ret_val; } /* yy_get_previous_state - get the state just before the EOB char was reached */ static yy_state_type yy_get_previous_state (void) { yy_state_type yy_current_state; char *yy_cp; yy_current_state = (yy_start); for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) { YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 155 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; } return yy_current_state; } /* yy_try_NUL_trans - try to make a transition on the NUL character * * synopsis * next_state = yy_try_NUL_trans( current_state ); */ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) { int yy_is_jam; char *yy_cp = (yy_c_buf_p); YY_CHAR yy_c = 1; if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 155 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; yy_is_jam = (yy_current_state == 154); return yy_is_jam ? 0 : yy_current_state; } #ifndef YY_NO_UNPUT #endif #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput (void) #else static int input (void) #endif { int c; *(yy_c_buf_p) = (yy_hold_char); if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) { /* yy_c_buf_p now points to the character we want to return. * If this occurs *before* the EOB characters, then it's a * valid NUL; if not, then we've hit the end of the buffer. */ if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) /* This was really a NUL. */ *(yy_c_buf_p) = '\0'; else { /* need more input */ int offset = (int) ((yy_c_buf_p) - (yytext_ptr)); ++(yy_c_buf_p); switch ( yy_get_next_buffer( ) ) { case EOB_ACT_LAST_MATCH: /* This happens because yy_g_n_b() * sees that we've accumulated a * token and flags that we need to * try matching the token before * proceeding. But for input(), * there's no matching to consider. * So convert the EOB_ACT_LAST_MATCH * to EOB_ACT_END_OF_FILE. */ /* Reset buffer status. */ yyrestart( yyin ); /*FALLTHROUGH*/ case EOB_ACT_END_OF_FILE: { if ( yywrap( ) ) return 0; if ( ! (yy_did_buffer_switch_on_eof) ) YY_NEW_FILE; #ifdef __cplusplus return yyinput(); #else return input(); #endif } case EOB_ACT_CONTINUE_SCAN: (yy_c_buf_p) = (yytext_ptr) + offset; break; } } } c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */ *(yy_c_buf_p) = '\0'; /* preserve yytext */ (yy_hold_char) = *++(yy_c_buf_p); return c; } #endif /* ifndef YY_NO_INPUT */ /** Immediately switch to a different input stream. * @param input_file A readable stream. * * @note This function does not reset the start condition to @c INITIAL . */ void yyrestart (FILE * input_file ) { if ( ! YY_CURRENT_BUFFER ){ yyensure_buffer_stack (); YY_CURRENT_BUFFER_LVALUE = yy_create_buffer( yyin, YY_BUF_SIZE ); } yy_init_buffer( YY_CURRENT_BUFFER, input_file ); yy_load_buffer_state( ); } /** Switch to a different input buffer. * @param new_buffer The new input buffer. * */ void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ) { /* TODO. We should be able to replace this entire function body * with * yypop_buffer_state(); * yypush_buffer_state(new_buffer); */ yyensure_buffer_stack (); if ( YY_CURRENT_BUFFER == new_buffer ) return; if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *(yy_c_buf_p) = (yy_hold_char); YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } YY_CURRENT_BUFFER_LVALUE = new_buffer; yy_load_buffer_state( ); /* We don't actually know whether we did this switch during * EOF (yywrap()) processing, but the only time this flag * is looked at is after yywrap() is called, so it's safe * to go ahead and always set it. */ (yy_did_buffer_switch_on_eof) = 1; } static void yy_load_buffer_state (void) { (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; (yy_hold_char) = *(yy_c_buf_p); } /** Allocate and initialize an input buffer state. * @param file A readable stream. * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. * * @return the allocated buffer state. */ YY_BUFFER_STATE yy_create_buffer (FILE * file, int size ) { YY_BUFFER_STATE b; b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_buf_size = size; /* yy_ch_buf has to be 2 characters longer than the size given because * we need to put in 2 end-of-buffer characters. */ b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2) ); if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_is_our_buffer = 1; yy_init_buffer( b, file ); return b; } /** Destroy the buffer. * @param b a buffer created with yy_create_buffer() * */ void yy_delete_buffer (YY_BUFFER_STATE b ) { if ( ! b ) return; if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; if ( b->yy_is_our_buffer ) yyfree( (void *) b->yy_ch_buf ); yyfree( (void *) b ); } /* Initializes or reinitializes a buffer. * This function is sometimes called more than once on the same buffer, * such as during a yyrestart() or at EOF. */ static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file ) { int oerrno = errno; yy_flush_buffer( b ); b->yy_input_file = file; b->yy_fill_buffer = 1; /* If b is the current buffer, then yy_init_buffer was _probably_ * called from yyrestart() or through yy_get_next_buffer. * In that case, we don't want to reset the lineno or column. */ if (b != YY_CURRENT_BUFFER){ b->yy_bs_lineno = 1; b->yy_bs_column = 0; } b->yy_is_interactive = 0; errno = oerrno; } /** Discard all buffered characters. On the next scan, YY_INPUT will be called. * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. * */ void yy_flush_buffer (YY_BUFFER_STATE b ) { if ( ! b ) return; b->yy_n_chars = 0; /* We always need two end-of-buffer characters. The first causes * a transition to the end-of-buffer state. The second causes * a jam in that state. */ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; b->yy_buf_pos = &b->yy_ch_buf[0]; b->yy_at_bol = 1; b->yy_buffer_status = YY_BUFFER_NEW; if ( b == YY_CURRENT_BUFFER ) yy_load_buffer_state( ); } /** Pushes the new state onto the stack. The new state becomes * the current state. This function will allocate the stack * if necessary. * @param new_buffer The new state. * */ void yypush_buffer_state (YY_BUFFER_STATE new_buffer ) { if (new_buffer == NULL) return; yyensure_buffer_stack(); /* This block is copied from yy_switch_to_buffer. */ if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *(yy_c_buf_p) = (yy_hold_char); YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } /* Only push if top exists. Otherwise, replace top. */ if (YY_CURRENT_BUFFER) (yy_buffer_stack_top)++; YY_CURRENT_BUFFER_LVALUE = new_buffer; /* copied from yy_switch_to_buffer. */ yy_load_buffer_state( ); (yy_did_buffer_switch_on_eof) = 1; } /** Removes and deletes the top of the stack, if present. * The next element becomes the new top. * */ void yypop_buffer_state (void) { if (!YY_CURRENT_BUFFER) return; yy_delete_buffer(YY_CURRENT_BUFFER ); YY_CURRENT_BUFFER_LVALUE = NULL; if ((yy_buffer_stack_top) > 0) --(yy_buffer_stack_top); if (YY_CURRENT_BUFFER) { yy_load_buffer_state( ); (yy_did_buffer_switch_on_eof) = 1; } } /* Allocates the stack if it does not exist. * Guarantees space for at least one push. */ static void yyensure_buffer_stack (void) { yy_size_t num_to_alloc; if (!(yy_buffer_stack)) { /* First allocation is just for 2 elements, since we don't know if this * scanner will even need a stack. We use 2 instead of 1 to avoid an * immediate realloc on the next call. */ num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */ (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc (num_to_alloc * sizeof(struct yy_buffer_state*) ); if ( ! (yy_buffer_stack) ) YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); (yy_buffer_stack_max) = num_to_alloc; (yy_buffer_stack_top) = 0; return; } if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ /* Increase the buffer to prepare for a possible push. */ yy_size_t grow_size = 8 /* arbitrary grow size */; num_to_alloc = (yy_buffer_stack_max) + grow_size; (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc ((yy_buffer_stack), num_to_alloc * sizeof(struct yy_buffer_state*) ); if ( ! (yy_buffer_stack) ) YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); /* zero only the new slots.*/ memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); (yy_buffer_stack_max) = num_to_alloc; } } /** Setup the input buffer state to scan directly from a user-specified character buffer. * @param base the character buffer * @param size the size in bytes of the character buffer * * @return the newly allocated buffer state object. */ YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size ) { YY_BUFFER_STATE b; if ( size < 2 || base[size-2] != YY_END_OF_BUFFER_CHAR || base[size-1] != YY_END_OF_BUFFER_CHAR ) /* They forgot to leave room for the EOB's. */ return NULL; b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); b->yy_buf_size = (int) (size - 2); /* "- 2" to take care of EOB's */ b->yy_buf_pos = b->yy_ch_buf = base; b->yy_is_our_buffer = 0; b->yy_input_file = NULL; b->yy_n_chars = b->yy_buf_size; b->yy_is_interactive = 0; b->yy_at_bol = 1; b->yy_fill_buffer = 0; b->yy_buffer_status = YY_BUFFER_NEW; yy_switch_to_buffer( b ); return b; } /** Setup the input buffer state to scan a string. The next call to yylex() will * scan from a @e copy of @a str. * @param yystr a NUL-terminated string to scan * * @return the newly allocated buffer state object. * @note If you want to scan bytes that may contain NUL values, then use * yy_scan_bytes() instead. */ YY_BUFFER_STATE yy_scan_string (const char * yystr ) { return yy_scan_bytes( yystr, (int) strlen(yystr) ); } /** Setup the input buffer state to scan the given bytes. The next call to yylex() will * scan from a @e copy of @a bytes. * @param yybytes the byte buffer to scan * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. * * @return the newly allocated buffer state object. */ YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, int _yybytes_len ) { YY_BUFFER_STATE b; char *buf; yy_size_t n; int i; /* Get memory for full buffer, including space for trailing EOB's. */ n = (yy_size_t) (_yybytes_len + 2); buf = (char *) yyalloc( n ); if ( ! buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); for ( i = 0; i < _yybytes_len; ++i ) buf[i] = yybytes[i]; buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; b = yy_scan_buffer( buf, n ); if ( ! b ) YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); /* It's okay to grow etc. this buffer, and we should throw it * away when we're done. */ b->yy_is_our_buffer = 1; return b; } #ifndef YY_EXIT_FAILURE #define YY_EXIT_FAILURE 2 #endif static void yynoreturn yy_fatal_error (const char* msg ) { fprintf( stderr, "%s\n", msg ); exit( YY_EXIT_FAILURE ); } /* Redefine yyless() so it works in section 3 code. */ #undef yyless #define yyless(n) \ do \ { \ /* Undo effects of setting up yytext. */ \ int yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ yytext[yyleng] = (yy_hold_char); \ (yy_c_buf_p) = yytext + yyless_macro_arg; \ (yy_hold_char) = *(yy_c_buf_p); \ *(yy_c_buf_p) = '\0'; \ yyleng = yyless_macro_arg; \ } \ while ( 0 ) /* Accessor methods (get/set functions) to struct members. */ /** Get the current line number. * */ int yyget_lineno (void) { return yylineno; } /** Get the input stream. * */ FILE *yyget_in (void) { return yyin; } /** Get the output stream. * */ FILE *yyget_out (void) { return yyout; } /** Get the length of the current token. * */ int yyget_leng (void) { return yyleng; } /** Get the current token. * */ char *yyget_text (void) { return yytext; } /** Set the current line number. * @param _line_number line number * */ void yyset_lineno (int _line_number ) { yylineno = _line_number; } /** Set the input stream. This does not discard the current * input buffer. * @param _in_str A readable stream. * * @see yy_switch_to_buffer */ void yyset_in (FILE * _in_str ) { yyin = _in_str ; } void yyset_out (FILE * _out_str ) { yyout = _out_str ; } int yyget_debug (void) { return yy_flex_debug; } void yyset_debug (int _bdebug ) { yy_flex_debug = _bdebug ; } static int yy_init_globals (void) { /* Initialization is the same as for the non-reentrant scanner. * This function is called from yylex_destroy(), so don't allocate here. */ (yy_buffer_stack) = NULL; (yy_buffer_stack_top) = 0; (yy_buffer_stack_max) = 0; (yy_c_buf_p) = NULL; (yy_init) = 0; (yy_start) = 0; /* Defined in main.c */ #ifdef YY_STDINIT yyin = stdin; yyout = stdout; #else yyin = NULL; yyout = NULL; #endif /* For future reference: Set errno on error, since we are called by * yylex_init() */ return 0; } /* yylex_destroy is for both reentrant and non-reentrant scanners. */ int yylex_destroy (void) { /* Pop the buffer stack, destroying each element. */ while(YY_CURRENT_BUFFER){ yy_delete_buffer( YY_CURRENT_BUFFER ); YY_CURRENT_BUFFER_LVALUE = NULL; yypop_buffer_state(); } /* Destroy the stack itself. */ yyfree((yy_buffer_stack) ); (yy_buffer_stack) = NULL; /* Reset the globals. This is important in a non-reentrant scanner so the next time * yylex() is called, initialization will occur. */ yy_init_globals( ); return 0; } /* * Internal utility routines. */ #ifndef yytext_ptr static void yy_flex_strncpy (char* s1, const char * s2, int n ) { int i; for ( i = 0; i < n; ++i ) s1[i] = s2[i]; } #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen (const char * s ) { int n; for ( n = 0; s[n]; ++n ) ; return n; } #endif void *yyalloc (yy_size_t size ) { return malloc(size); } void *yyrealloc (void * ptr, yy_size_t size ) { /* The cast to (char *) in the following accommodates both * implementations that use char* generic pointers, and those * that use void* generic pointers. It works with the latter * because both ANSI C and C++ allow castless assignment from * any pointer type to void*, and deal with argument conversions * as though doing an assignment. */ return realloc(ptr, size); } void yyfree (void * ptr ) { free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ } #define YYTABLES_NAME "yytables" #line 862 "sqlscan.l" /* * lexer_errposition * Report a lexical-analysis-time cursor position, if possible. * * This is expected to be used within an ereport() call. The return value * is a dummy (always 0, in fact). * * Note that this can only be used for messages from the lexer itself, * since it depends on scanbuf to still be valid. */ static int lexer_errposition(void) { int pos; /* Convert byte offset to character number */ pos = _pg_mbstrlen_with_len(scanbuf, orafce_sql_yylval.val.lloc) + 1; /* And pass it to the ereport mechanism */ return errposition(pos); } /* * yyerror * Report a lexer or grammar error. * * The message's cursor position identifies the most recently lexed token. * This is OK for syntax error messages from the Bison parser, because Bison * parsers report error as soon as the first unparsable token is reached. * Beware of using yyerror for other purposes, as the cursor position might * be misleading! */ void orafce_sql_yyerror(List **result, const char *message) { const char *loc = scanbuf + orafce_sql_yylval.val.lloc; if (*loc == YY_END_OF_BUFFER_CHAR) { ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("%s at end of input", _(message)), lexer_errposition())); } else { ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("%s at or near \"%s\"", _(message), loc), lexer_errposition())); } } /* * Called before any actual parsing is done */ void orafce_sql_scanner_init(const char *str) { Size slen = strlen(str); /* * Might be left over after ereport() */ if (YY_CURRENT_BUFFER) yy_delete_buffer(YY_CURRENT_BUFFER); /* * Make a scan buffer with special termination needed by flex. */ scanbuflen = slen; scanbuf = palloc(slen + 2); memcpy(scanbuf, str, slen); scanbuf[slen] = scanbuf[slen + 1] = YY_END_OF_BUFFER_CHAR; scanbufhandle = yy_scan_buffer(scanbuf, slen + 2); /* initialize literal buffer to a reasonable but expansible size */ literalalloc = 128; literalbuf = (char *) palloc(literalalloc); startlit(); BEGIN(INITIAL); } /* * Called after parsing is done to clean up after fdate_scanner_init() */ void orafce_sql_scanner_finish(void) { yy_delete_buffer(scanbufhandle); pfree(scanbuf); } static void addlit(char *ytext, int yleng) { /* enlarge buffer if needed */ if ((literallen+yleng) >= literalalloc) { do { literalalloc *= 2; } while ((literallen+yleng) >= literalalloc); literalbuf = (char *) repalloc(literalbuf, literalalloc); } /* append new data, add trailing null */ memcpy(literalbuf+literallen, ytext, yleng); literallen += yleng; literalbuf[literallen] = '\0'; } static void addlitchar(unsigned char ychar) { /* enlarge buffer if needed */ if ((literallen+1) >= literalalloc) { literalalloc *= 2; literalbuf = (char *) repalloc(literalbuf, literalalloc); } /* append new data, add trailing null */ literalbuf[literallen] = ychar; literallen += 1; literalbuf[literallen] = '\0'; } /* * One might be tempted to write pstrdup(literalbuf) instead of this, * but for long literals this is much faster because the length is * already known. */ static char * litbufdup(void) { char *new; new = palloc(literallen + 1); memcpy(new, literalbuf, literallen+1); return new; } static unsigned char unescape_single_char(unsigned char c) { switch (c) { case 'b': return '\b'; case 'f': return '\f'; case 'n': return '\n'; case 'r': return '\r'; case 't': return '\t'; default: return c; } } orafce-VERSION_3_9_0/sqlscan.l000066400000000000000000000647071362147214200161720ustar00rootroot00000000000000%{ /* ** A scanner for EMP-style numeric ranges */ #include "postgres.h" #include "parser/gramparse.h" /* Not needed now that this file is compiled as part of gram.y */ /* #include "parser/parse.h" */ #include "parser/scansup.h" #include "mb/pg_wchar.h" #include "parse_keyword.h" /* Avoid exit() on fatal scanner errors (a bit ugly -- see yy_fatal_error) */ #undef fprintf #define fprintf(file, fmt, msg) fprintf_to_ereport(fmt, msg) static void fprintf_to_ereport(const char *fmt, const char *msg) { ereport(ERROR, (errmsg_internal("%s", msg))); } static int xcdepth = 0; /* depth of nesting in slash-star comments */ static char *dolqstart; /* current $foo$ quote start string */ static bool extended_string = false; /* No reason to constrain amount of data slurped */ #define YY_READ_BUF_SIZE 16777216 /* Handles to the buffer that the lexer uses internally */ static YY_BUFFER_STATE scanbufhandle; #define SET_YYLLOC() (orafce_sql_yylval.val.lloc = yytext - scanbuf) /* Handles to the buffer that the lexer uses internally */ static char *scanbuf; /* flex 2.5.4 doesn't bother with a decl for this */ int orafce_sql_yylex(void); void orafce_sql_scanner_init(const char *str); void orafce_sql_scanner_finish(void); /* * literalbuf is used to accumulate literal values when multiple rules * are needed to parse a single literal. Call startlit to reset buffer * to empty, addlit to add text. Note that the buffer is palloc'd and * starts life afresh on every parse cycle. */ static char *literalbuf; /* expandable buffer */ static int literallen; /* actual current length */ static int literalalloc; /* current allocated buffer size */ #define startlit() (literalbuf[0] = '\0', literallen = 0) static void addlit(char *ytext, int yleng); static void addlitchar(unsigned char ychar); static char *litbufdup(void); static int lexer_errposition(void); /* * Each call to yylex must set yylloc to the location of the found token * (expressed as a byte offset from the start of the input text). * When we parse a token that requires multiple lexer rules to process, * this should be done in the first such rule, else yylloc will point * into the middle of the token. */ /* Handles to the buffer that the lexer uses internally */ static char *scanbuf; static unsigned char unescape_single_char(unsigned char c); #ifndef _pg_mbstrlen_with_len #define _pg_mbstrlen_with_len(buf,loc) pg_mbstrlen_with_len(buf,loc) #endif %} %option 8bit %option never-interactive %option nodefault %option noinput %option nounput %option noyywrap %option prefix="orafce_sql_yy" /* * OK, here is a short description of lex/flex rules behavior. * The longest pattern which matches an input string is always chosen. * For equal-length patterns, the first occurring in the rules list is chosen. * INITIAL is the starting state, to which all non-conditional rules apply. * Exclusive states change parsing rules while the state is active. When in * an exclusive state, only those rules defined for that state apply. * * We use exclusive states for quoted strings, extended comments, * and to eliminate parsing troubles for numeric strings. * Exclusive states: * bit string literal * extended C-style comments * delimited identifiers (double-quoted identifiers) * hexadecimal numeric string * standard quoted strings * extended quoted strings (support backslash escape sequences) * $foo$ quoted strings */ %x xb %x xc %x xd %x xh %x xe %x xq %x xdolq /* * In order to make the world safe for Windows and Mac clients as well as * Unix ones, we accept either \n or \r as a newline. A DOS-style \r\n * sequence will be seen as two successive newlines, but that doesn't cause * any problems. Comments that start with -- and extend to the next * newline are treated as equivalent to a single whitespace character. * * NOTE a fine point: if there is no newline following --, we will absorb * everything to the end of the input as a comment. This is correct. Older * versions of Postgres failed to recognize -- as a comment if the input * did not end with a newline. * * XXX perhaps \f (formfeed) should be treated as a newline as well? * * XXX if you change the set of whitespace characters, fix scanner_isspace() * to agree, and see also the plpgsql lexer. */ space [ \t\n\r\f] horiz_space [ \t\f] newline [\n\r] non_newline [^\n\r] comment ("--"{non_newline}*) whitespace {space}+ /* * SQL requires at least one newline in the whitespace separating * string literals that are to be concatenated. Silly, but who are we * to argue? Note that {whitespace_with_newline} should not have * after * it, whereas {whitespace} should generally have a * after it... */ special_whitespace ({space}+|{comment}{newline}) horiz_whitespace ({horiz_space}|{comment}) whitespace_with_newline ({horiz_whitespace}*{newline}{special_whitespace}*) /* * To ensure that {quotecontinue} can be scanned without having to back up * if the full pattern isn't matched, we include trailing whitespace in * {quotestop}. This matches all cases where {quotecontinue} fails to match, * except for {quote} followed by whitespace and just one "-" (not two, * which would start a {comment}). To cover that we have {quotefail}. * The actions for {quotestop} and {quotefail} must throw back characters * beyond the quote proper. */ quote ' quotestop {quote}{whitespace}* quotecontinue {quote}{whitespace_with_newline}{quote} quotefail {quote}{whitespace}*"-" /* Bit string * It is tempting to scan the string for only those characters * which are allowed. However, this leads to silently swallowed * characters if illegal characters are included in the string. * For example, if xbinside is [01] then B'ABCD' is interpreted * as a zero-length string, and the ABCD' is lost! * Better to pass the string forward and let the input routines * validate the contents. */ xbstart [bB]{quote} xbinside [^']* /* Hexadecimal number */ xhstart [xX]{quote} xhinside [^']* /* National character */ xnstart [nN]{quote} /* Quoted string that allows backslash escapes */ xestart [eE]{quote} xeinside [^\\']+ xeescape [\\][^0-7] xeoctesc [\\][0-7]{1,3} xehexesc [\\]x[0-9A-Fa-f]{1,2} /* Extended quote * xqdouble implements embedded quote, '''' */ xqstart {quote} xqdouble {quote}{quote} xqinside [^']+ /* $foo$ style quotes ("dollar quoting") * The quoted string starts with $foo$ where "foo" is an optional string * in the form of an identifier, except that it may not contain "$", * and extends to the first occurrence of an identical string. * There is *no* processing of the quoted text. * * {dolqfailed} is an error rule to avoid scanner backup when {dolqdelim} * fails to match its trailing "$". */ dolq_start [A-Za-z\200-\377_] dolq_cont [A-Za-z\200-\377_0-9] dolqdelim \$({dolq_start}{dolq_cont}*)?\$ dolqfailed \${dolq_start}{dolq_cont}* dolqinside [^$]+ /* Double quote * Allows embedded spaces and other special characters into identifiers. */ dquote \" xdstart {dquote} xdstop {dquote} xddouble {dquote}{dquote} xdinside [^"]+ /* C-style comments * * The "extended comment" syntax closely resembles allowable operator syntax. * The tricky part here is to get lex to recognize a string starting with * slash-star as a comment, when interpreting it as an operator would produce * a longer match --- remember lex will prefer a longer match! Also, if we * have something like plus-slash-star, lex will think this is a 3-character * operator whereas we want to see it as a + operator and a comment start. * The solution is two-fold: * 1. append {op_chars}* to xcstart so that it matches as much text as * {operator} would. Then the tie-breaker (first matching rule of same * length) ensures xcstart wins. We put back the extra stuff with yyless() * in case it contains a star-slash that should terminate the comment. * 2. In the operator rule, check for slash-star within the operator, and * if found throw it back with yyless(). This handles the plus-slash-star * problem. * Dash-dash comments have similar interactions with the operator rule. */ xcstart \/\*{op_chars}* xcstop \*+\/ xcinside [^*/]+ digit [0-9] ident_start [A-Za-z\200-\377_] ident_cont [A-Za-z\200-\377_0-9\$] identifier {ident_start}{ident_cont}* typecast "::" /* * "self" is the set of chars that should be returned as single-character * tokens. "op_chars" is the set of chars that can make up "Op" tokens, * which can be one or more characters long (but if a single-char token * appears in the "self" set, it is not to be returned as an Op). Note * that the sets overlap, but each has some chars that are not in the other. * * If you change either set, adjust the character lists appearing in the * rule for "operator"! */ self [,()\[\].;\:\+\-\*\/\%\^\<\>\=] op_chars [\~\!\@\#\^\&\|\`\?\+\-\*\/\%\<\>\=] operator {op_chars}+ /* we no longer allow unary minus in numbers. * instead we pass it separately to parser. there it gets * coerced via doNegate() -- Leon aug 20 1999 * * {realfail1} and {realfail2} are added to prevent the need for scanner * backup when the {real} rule fails to match completely. */ integer {digit}+ decimal (({digit}*\.{digit}+)|({digit}+\.{digit}*)) real ({integer}|{decimal})[Ee][-+]?{digit}+ realfail1 ({integer}|{decimal})[Ee] realfail2 ({integer}|{decimal})[Ee][-+] param \${integer} other . /* * Dollar quoted strings are totally opaque, and no escaping is done on them. * Other quoted strings must allow some special characters such as single-quote * and newline. * Embedded single-quotes are implemented both in the SQL standard * style of two adjacent single quotes "''" and in the Postgres/Java style * of escaped-quote "\'". * Other embedded escaped characters are matched explicitly and the leading * backslash is dropped from the string. * Note that xcstart must appear before operator, as explained above! * Also whitespace (comment) must appear before operator. */ %% {whitespace} { SET_YYLLOC(); yylval.val.str = yytext; yylval.val.modificator = NULL; yylval.val.keycode = -1; yylval.val.sep = NULL; return X_WHITESPACE; } {comment} { SET_YYLLOC(); yylval.val.str = yytext; yylval.val.modificator = "sc"; yylval.val.keycode = -1; yylval.val.sep = NULL; return X_COMMENT; } {xcstart} { /* Set location in case of syntax error in comment */ SET_YYLLOC(); xcdepth = 0; BEGIN(xc); /* Put back any characters past slash-star; see above */ startlit(); addlitchar('/'); addlitchar('*'); yyless(2); } {xcstart} { xcdepth++; /* Put back any characters past slash-star; see above */ addlitchar('/'); addlitchar('*'); yyless(2); } {xcstop} { if (xcdepth <= 0) { BEGIN(INITIAL); addlitchar('*'); addlitchar('/'); yylval.val.str = litbufdup(); yylval.val.modificator = "ec"; yylval.val.keycode = -1; yylval.val.sep = NULL; return X_COMMENT; } else { xcdepth--; addlitchar('*'); addlitchar('/'); } } {xcinside} { addlit(yytext, yyleng); } {op_chars} { addlit(yytext, yyleng); } \*+ { addlit(yytext, yyleng); } <> { yylval.val.str = litbufdup(); yylval.val.modificator = "ecu"; yylval.val.keycode = -1; yylval.val.sep = NULL; return X_COMMENT; } {xbstart} { /* Binary bit type. * At some point we should simply pass the string * forward to the parser and label it there. * In the meantime, place a leading "b" on the string * to mark it for the input routine as a binary string. */ SET_YYLLOC(); BEGIN(xb); startlit(); addlitchar('b'); } {quotestop} | {quotefail} { yyless(1); BEGIN(INITIAL); yylval.val.str = litbufdup(); yylval.val.modificator = "b"; yylval.val.keycode = -1; yylval.val.sep = NULL; return X_NCONST; } {xhinside} | {xbinside} { addlit(yytext, yyleng); } {quotecontinue} | {quotecontinue} { /* ignore */ } <> { yylval.val.str = litbufdup(); yylval.val.modificator = "bu"; yylval.val.keycode = -1; yylval.val.sep = NULL; return X_NCONST; } {xhstart} { /* Hexadecimal bit type. * At some point we should simply pass the string * forward to the parser and label it there. * In the meantime, place a leading "x" on the string * to mark it for the input routine as a hex string. */ SET_YYLLOC(); BEGIN(xh); startlit(); addlitchar('x'); } {quotestop} | {quotefail} { yyless(1); BEGIN(INITIAL); yylval.val.str = litbufdup(); yylval.val.modificator = "x"; yylval.val.keycode = -1; yylval.val.sep = NULL; return X_NCONST; } <> { yylval.val.str = litbufdup(); yylval.val.modificator = "xu"; yylval.val.keycode = -1; yylval.val.sep = NULL; return X_NCONST; } {xnstart} { /* National character. * We will pass this along as a normal character string, * but preceded with an internally-generated "NCHAR". */ const char *keyword; int keycode; SET_YYLLOC(); yyless(1); /* eat only 'n' this time */ /* nchar had better be a keyword! */ keyword = orafce_scan_keyword("nchar", &keycode); Assert(keyword != NULL); yylval.val.str = (char*) keyword; yylval.val.keycode = keycode; yylval.val.modificator = NULL; yylval.val.sep = NULL; return X_KEYWORD; } {xqstart} { SET_YYLLOC(); BEGIN(xq); extended_string = false; startlit(); } {xestart} { SET_YYLLOC(); BEGIN(xe); extended_string = true; startlit(); } {quotestop} | {quotefail} { yyless(1); BEGIN(INITIAL); yylval.val.str = litbufdup(); yylval.val.modificator = extended_string ? "es" : "qs"; yylval.val.keycode = -1; yylval.val.sep = NULL; return X_SCONST; } {xqdouble} { addlitchar('\''); } {xqinside} { addlit(yytext, yyleng); } {xeinside} { addlit(yytext, yyleng); } {xeescape} { addlitchar(unescape_single_char(yytext[1])); } {xeoctesc} { unsigned char c = strtoul(yytext+1, NULL, 8); addlitchar(c); } {xehexesc} { unsigned char c = strtoul(yytext+2, NULL, 16); addlitchar(c); } {quotecontinue} { /* ignore */ } . { /* This is only needed for \ just before EOF */ addlitchar(yytext[0]); } <> { yylval.val.str = litbufdup(); yylval.val.modificator = extended_string ? "esu" : "qsu"; yylval.val.keycode = -1; yylval.val.sep = NULL; return X_SCONST; } {dolqdelim} { SET_YYLLOC(); dolqstart = pstrdup(yytext); BEGIN(xdolq); startlit(); } {dolqfailed} { /* throw back all but the initial "$" */ yyless(1); /* and treat it as {other} */ yylval.val.str = yytext; yylval.val.modificator = "dolqf"; yylval.val.keycode = -1; yylval.val.sep = NULL; return X_OTHERS; } {dolqdelim} { if (strcmp(yytext, dolqstart) == 0) { yylval.val.sep = dolqstart; yylval.val.modificator = "dolq"; BEGIN(INITIAL); yylval.val.str = litbufdup(); yylval.val.keycode = -1; return X_SCONST; } else { /* * When we fail to match $...$ to dolqstart, transfer * the $... part to the output, but put back the final * $ for rescanning. Consider $delim$...$junk$delim$ */ addlit(yytext, yyleng-1); yyless(yyleng-1); } } {dolqinside} { addlit(yytext, yyleng); } {dolqfailed} { addlit(yytext, yyleng); } . { /* This is only needed for inside the quoted text */ addlitchar(yytext[0]); } <> { yylval.val.sep = dolqstart; yylval.val.modificator = "dolqu"; yylval.val.str = litbufdup(); yylval.val.keycode = -1; yylval.val.sep = NULL; return X_SCONST; } {xdstart} { SET_YYLLOC(); BEGIN(xd); startlit(); } {xdstop} { char *ident; BEGIN(INITIAL); if (literallen == 0) yyerror(NULL, "zero-length delimited identifier"); ident = litbufdup(); if (literallen >= NAMEDATALEN) truncate_identifier(ident, literallen, true); yylval.val.modificator = "dq"; yylval.val.str = ident; yylval.val.keycode = -1; yylval.val.sep = NULL; return X_IDENT; } {xddouble} { addlitchar('"'); } {xdinside} { addlit(yytext, yyleng); } <> { yylval.val.modificator = "dqu"; yylval.val.str = litbufdup(); yylval.val.keycode = -1; yylval.val.sep = NULL; return X_IDENT; } {typecast} { SET_YYLLOC(); yylval.val.modificator = "typecast"; yylval.val.keycode = X_TYPECAST; yylval.val.sep = NULL; return X_OTHERS; } {self} { SET_YYLLOC(); yylval.val.str = yytext; yylval.val.modificator = "self"; yylval.val.keycode = yytext[0]; yylval.val.sep = NULL; return X_OTHERS; } {operator} { /* * Check for embedded slash-star or dash-dash; those * are comment starts, so operator must stop there. * Note that slash-star or dash-dash at the first * character will match a prior rule, not this one. */ int nchars = yyleng; char *slashstar = strstr(yytext, "/*"); char *dashdash = strstr(yytext, "--"); if (slashstar && dashdash) { /* if both appear, take the first one */ if (slashstar > dashdash) slashstar = dashdash; } else if (!slashstar) slashstar = dashdash; if (slashstar) nchars = slashstar - yytext; /* * For SQL compatibility, '+' and '-' cannot be the * last char of a multi-char operator unless the operator * contains chars that are not in SQL operators. * The idea is to lex '=-' as two operators, but not * to forbid operator names like '?-' that could not be * sequences of SQL operators. */ while (nchars > 1 && (yytext[nchars-1] == '+' || yytext[nchars-1] == '-')) { int ic; for (ic = nchars-2; ic >= 0; ic--) { if (strchr("~!@#^&|`?%", yytext[ic])) break; } if (ic >= 0) break; /* found a char that makes it OK */ nchars--; /* else remove the +/-, and check again */ } SET_YYLLOC(); if (nchars < yyleng) { /* Strip the unwanted chars from the token */ yyless(nchars); /* * If what we have left is only one char, and it's * one of the characters matching "self", then * return it as a character token the same way * that the "self" rule would have. */ if (nchars == 1 && strchr(",()[].;:+-*/%^<>=", yytext[0])) { yylval.val.str = yytext; yylval.val.modificator = NULL; yylval.val.keycode = yytext[0]; yylval.val.sep = NULL; return X_OTHERS; } } /* * Complain if operator is too long. Unlike the case * for identifiers, we make this an error not a notice- * and-truncate, because the odds are we are looking at * a syntactic mistake anyway. */ if (nchars >= NAMEDATALEN) yyerror(NULL, "operator too long"); /* Convert "!=" operator to "<>" for compatibility */ yylval.val.modificator = NULL; if (strcmp(yytext, "!=") == 0) yylval.val.str = pstrdup("<>"); else yylval.val.str = pstrdup(yytext); yylval.val.keycode = -1; yylval.val.sep = NULL; return X_OP; } {param} { SET_YYLLOC(); yylval.val.modificator = NULL; yylval.val.str = yytext; yylval.val.keycode = -1; yylval.val.sep = NULL; return X_PARAM; } {integer} { long val; char* endptr; SET_YYLLOC(); errno = 0; val = strtol(yytext, &endptr, 10); if (*endptr != '\0' || errno == ERANGE #ifdef HAVE_LONG_INT_64 /* if long > 32 bits, check for overflow of int4 */ || val != (long) ((int32) val) #endif ) { /* integer too large, treat it as a float */ yylval.val.str = pstrdup(yytext); yylval.val.modificator = "f"; yylval.val.keycode = -1; yylval.val.sep = NULL; return X_NCONST; } yylval.val.str = yytext; yylval.val.modificator = "i"; yylval.val.keycode = -1; yylval.val.sep = NULL; return X_NCONST; } {decimal} { SET_YYLLOC(); yylval.val.str = pstrdup(yytext); yylval.val.modificator = "f"; yylval.val.keycode = -1; yylval.val.sep = NULL; return X_NCONST; } {real} { SET_YYLLOC(); yylval.val.str = pstrdup(yytext); yylval.val.modificator = "f"; yylval.val.keycode = -1; yylval.val.sep = NULL; return X_NCONST; } {realfail1} { /* * throw back the [Ee], and treat as {decimal}. Note * that it is possible the input is actually {integer}, * but since this case will almost certainly lead to a * syntax error anyway, we don't bother to distinguish. */ yyless(yyleng-1); SET_YYLLOC(); yylval.val.str = pstrdup(yytext); yylval.val.modificator = "f"; yylval.val.keycode = -1; yylval.val.sep = NULL; return X_NCONST; } {realfail2} { /* throw back the [Ee][+-], and proceed as above */ yyless(yyleng-2); SET_YYLLOC(); yylval.val.str = pstrdup(yytext); yylval.val.modificator = "f"; yylval.val.keycode = -1; yylval.val.sep = NULL; return X_NCONST; } {identifier} { char *ident; const char *keyword; int keycode; SET_YYLLOC(); /* nchar had better be a keyword! */ keyword = orafce_scan_keyword("nchar", &keycode); /* Is it a keyword? */ keyword = orafce_scan_keyword(yytext, &keycode); if (keyword != NULL) { yylval.val.str = (char*) keyword; yylval.val.keycode = keycode; yylval.val.modificator = NULL; yylval.val.sep = NULL; return X_KEYWORD; } /* * No. Convert the identifier to lower case, and truncate * if necessary. */ ident = downcase_truncate_identifier(yytext, yyleng, true); yylval.val.str = ident; yylval.val.modificator = NULL; yylval.val.keycode = -1; yylval.val.sep = NULL; return X_IDENT; } {other} { SET_YYLLOC(); yylval.val.str = yytext; yylval.val.modificator = NULL; yylval.val.keycode = yytext[0]; yylval.val.sep = NULL; return X_OTHERS; } <> { SET_YYLLOC(); yyterminate(); } %% /* * lexer_errposition * Report a lexical-analysis-time cursor position, if possible. * * This is expected to be used within an ereport() call. The return value * is a dummy (always 0, in fact). * * Note that this can only be used for messages from the lexer itself, * since it depends on scanbuf to still be valid. */ static int lexer_errposition(void) { int pos; /* Convert byte offset to character number */ pos = _pg_mbstrlen_with_len(scanbuf, orafce_sql_yylval.val.lloc) + 1; /* And pass it to the ereport mechanism */ return errposition(pos); } /* * yyerror * Report a lexer or grammar error. * * The message's cursor position identifies the most recently lexed token. * This is OK for syntax error messages from the Bison parser, because Bison * parsers report error as soon as the first unparsable token is reached. * Beware of using yyerror for other purposes, as the cursor position might * be misleading! */ void orafce_sql_yyerror(List **result, const char *message) { const char *loc = scanbuf + orafce_sql_yylval.val.lloc; if (*loc == YY_END_OF_BUFFER_CHAR) { ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("%s at end of input", _(message)), lexer_errposition())); } else { ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("%s at or near \"%s\"", _(message), loc), lexer_errposition())); } } /* * Called before any actual parsing is done */ void orafce_sql_scanner_init(const char *str) { Size slen = strlen(str); /* * Might be left over after ereport() */ if (YY_CURRENT_BUFFER) yy_delete_buffer(YY_CURRENT_BUFFER); /* * Make a scan buffer with special termination needed by flex. */ scanbuflen = slen; scanbuf = palloc(slen + 2); memcpy(scanbuf, str, slen); scanbuf[slen] = scanbuf[slen + 1] = YY_END_OF_BUFFER_CHAR; scanbufhandle = yy_scan_buffer(scanbuf, slen + 2); /* initialize literal buffer to a reasonable but expansible size */ literalalloc = 128; literalbuf = (char *) palloc(literalalloc); startlit(); BEGIN(INITIAL); } /* * Called after parsing is done to clean up after fdate_scanner_init() */ void orafce_sql_scanner_finish(void) { yy_delete_buffer(scanbufhandle); pfree(scanbuf); } static void addlit(char *ytext, int yleng) { /* enlarge buffer if needed */ if ((literallen+yleng) >= literalalloc) { do { literalalloc *= 2; } while ((literallen+yleng) >= literalalloc); literalbuf = (char *) repalloc(literalbuf, literalalloc); } /* append new data, add trailing null */ memcpy(literalbuf+literallen, ytext, yleng); literallen += yleng; literalbuf[literallen] = '\0'; } static void addlitchar(unsigned char ychar) { /* enlarge buffer if needed */ if ((literallen+1) >= literalalloc) { literalalloc *= 2; literalbuf = (char *) repalloc(literalbuf, literalalloc); } /* append new data, add trailing null */ literalbuf[literallen] = ychar; literallen += 1; literalbuf[literallen] = '\0'; } /* * One might be tempted to write pstrdup(literalbuf) instead of this, * but for long literals this is much faster because the length is * already known. */ static char * litbufdup(void) { char *new; new = palloc(literallen + 1); memcpy(new, literalbuf, literallen+1); return new; } static unsigned char unescape_single_char(unsigned char c) { switch (c) { case 'b': return '\b'; case 'f': return '\f'; case 'n': return '\n'; case 'r': return '\r'; case 't': return '\t'; default: return c; } } orafce-VERSION_3_9_0/utility.c000066400000000000000000000100111362147214200161730ustar00rootroot00000000000000/* This code implements one part of functonality of free available library PL/Vision. Please look www.quest.com Original author: Steven Feuerstein, 1996 - 2002 PostgreSQL implementation author: Pavel Stehule, 2006-2018 This module is under BSD Licence History: 1.0. first public version 22. September 2006 */ #include "postgres.h" #include "utils/builtins.h" #include "utils/numeric.h" #include "string.h" #include "stdlib.h" #include "utils/pg_locale.h" #include "mb/pg_wchar.h" #include "lib/stringinfo.h" #include "catalog/pg_type.h" #include "libpq/pqformat.h" #include "utils/array.h" #include "utils/memutils.h" #include "utils/lsyscache.h" #include "access/tupmacs.h" #include "orafce.h" #include "builtins.h" #include "utils/elog.h" PG_FUNCTION_INFO_V1(dbms_utility_format_call_stack0); PG_FUNCTION_INFO_V1(dbms_utility_format_call_stack1); static char* dbms_utility_format_call_stack(char mode) { MemoryContext oldcontext = CurrentMemoryContext; ErrorData *edata; ErrorContextCallback *econtext; StringInfo sinfo; errstart(ERROR, __FILE__, __LINE__, PG_FUNCNAME_MACRO, TEXTDOMAIN); MemoryContextSwitchTo(oldcontext); for (econtext = error_context_stack; econtext != NULL; econtext = econtext->previous) (*econtext->callback) (econtext->arg); edata = CopyErrorData(); FlushErrorState(); /* Now I wont to parse edata->context to more traditional format */ /* I am not sure about order */ sinfo = makeStringInfo(); switch (mode) { case 'o': appendStringInfoString(sinfo, "----- PL/pgSQL Call Stack -----\n"); appendStringInfoString(sinfo, " object line object\n"); appendStringInfoString(sinfo, " handle number name\n"); break; } if (edata->context) { char *start = edata->context; while (*start) { char *oname = "anonymous object"; char *line = ""; char *eol = strchr(start, '\n'); Oid fnoid = InvalidOid; /* first, solve multilines */ if (eol) *eol = '\0'; /* first know format */ if (strncmp(start, "PL/pgSQL function ",18) == 0) { char *p1, *p2; if ((p1 = strstr(start, "function \""))) { p1 += strlen("function \""); if ((p2 = strchr(p1, '"'))) { *p2++ = '\0'; oname = p1; start = p2; } } else if ((p1 = strstr(start, "function "))) { p1 += strlen("function "); if ((p2 = strchr(p1, ')'))) { char c = *++p2; *p2 = '\0'; oname = pstrdup(p1); fnoid = DatumGetObjectId(DirectFunctionCall1(regprocedurein, CStringGetDatum(oname))); *p2 = c; start = p2; } } if ((p1 = strstr(start, "line "))) { size_t p2i; char c; p1 += strlen("line "); p2i = strspn(p1, "0123456789"); /* safe separator */ c = p1[p2i]; p1[p2i] = '\0'; line = pstrdup(p1); p1[p2i] = c; } } switch (mode) { case 'o': appendStringInfo(sinfo, "%8x %5s function %s", (int)fnoid, line, oname); break; case 'p': appendStringInfo(sinfo, "%8d %5s function %s", (int)fnoid, line, oname); break; case 's': appendStringInfo(sinfo, "%d,%s,%s", (int)fnoid, line, oname); break; } if (eol) { start = eol + 1; appendStringInfoChar(sinfo, '\n'); } else break; } } return sinfo->data; } Datum dbms_utility_format_call_stack0(PG_FUNCTION_ARGS) { PG_RETURN_TEXT_P(cstring_to_text(dbms_utility_format_call_stack('o'))); } Datum dbms_utility_format_call_stack1(PG_FUNCTION_ARGS) { text *arg = PG_GETARG_TEXT_P(0); char mode; if ((1 != VARSIZE(arg) - VARHDRSZ)) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid parameter"), errdetail("Allowed only chars [ops]."))); mode = *VARDATA(arg); switch (mode) { case 'o': case 'p': case 's': break; default: ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid parameter"), errdetail("Allowed only chars [ops]."))); } PG_RETURN_TEXT_P(cstring_to_text(dbms_utility_format_call_stack(mode))); } orafce-VERSION_3_9_0/varchar2.c000066400000000000000000000131561362147214200162150ustar00rootroot00000000000000/*---------------------------------------------------------------------------- * * varchar2.c * VARCHAR2 type for PostgreSQL. * *---------------------------------------------------------------------------- */ #include "postgres.h" #include "access/hash.h" #include "access/tuptoaster.h" #include "libpq/pqformat.h" #include "nodes/nodeFuncs.h" #include "utils/array.h" #include "utils/builtins.h" #include "mb/pg_wchar.h" #include "fmgr.h" #include "orafce.h" #include "builtins.h" PG_FUNCTION_INFO_V1(varchar2in); PG_FUNCTION_INFO_V1(varchar2out); PG_FUNCTION_INFO_V1(varchar2); PG_FUNCTION_INFO_V1(varchar2recv); PG_FUNCTION_INFO_V1(orafce_concat2); PG_FUNCTION_INFO_V1(orafce_varchar_transform); bool orafce_varchar2_null_safe_concat = false; /* * varchar2_input -- common guts of varchar2in and varchar2recv * * s is the input text of length len (may not be null-terminated) * atttypmod is the typmod value to apply * * If the input string is too long, raise an error * * Uses the C string to text conversion function, which is only appropriate * if VarChar and text are equivalent types. */ static VarChar * varchar2_input(const char *s, size_t len, int32 atttypmod) { VarChar *result; /* input data */ size_t maxlen; maxlen = atttypmod - VARHDRSZ; /* * Perform the typmod check; error out if value too long for VARCHAR2 */ if (atttypmod >= (int32) VARHDRSZ && len > maxlen) if (len > maxlen) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("input value length is %zd; too long for type varchar2(%zd)", len , maxlen))); result = (VarChar *) cstring_to_text_with_len(s, len); return result; } /* * Converts a C string to VARCHAR2 internal representation. atttypmod * is the declared length of the type plus VARHDRSZ. */ Datum varchar2in(PG_FUNCTION_ARGS) { char *s = PG_GETARG_CSTRING(0); #ifdef NOT_USED Oid typelem = PG_GETARG_OID(1); #endif int32 atttypmod = PG_GETARG_INT32(2); VarChar *result; result = varchar2_input(s, strlen(s), atttypmod); PG_RETURN_VARCHAR_P(result); } /* * converts a VARCHAR2 value to a C string. * * Uses the text to C string conversion function, which is only appropriate * if VarChar and text are equivalent types. */ Datum varchar2out(PG_FUNCTION_ARGS) { Datum txt = PG_GETARG_DATUM(0); PG_RETURN_CSTRING(TextDatumGetCString(txt)); } /* * converts external binary format to varchar */ Datum varchar2recv(PG_FUNCTION_ARGS) { StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); #ifdef NOT_USED Oid typelem = PG_GETARG_OID(1); #endif int32 atttypmod = PG_GETARG_INT32(2); /* typmod of the receiving column */ VarChar *result; char *str; /* received data */ int nbytes; /* length in bytes of recived data */ str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes); result = varchar2_input(str, nbytes, atttypmod); pfree(str); PG_RETURN_VARCHAR_P(result); } /* * varchar2send -- convert varchar2 to binary value * * just use varcharsend() */ /* * varchar2_transform() * Flatten calls to varchar's length coercion function that set the new maximum * length >= the previous maximum length. We can ignore the isExplicit * argument, since that only affects truncation cases. * * just use varchar_transform() */ Datum orafce_varchar_transform(PG_FUNCTION_ARGS) { #if PG_VERSION_NUM < 120000 return varchar_transform(fcinfo); #else return varchar_support(fcinfo); #endif } /* * Converts a VARCHAR2 type to the specified size. * * maxlen is the typmod, ie, declared length plus VARHDRSZ bytes. * isExplicit is true if this is for an explicit cast to varchar2(N). * * Truncation rules: for an explicit cast, silently truncate to the given * length; for an implicit cast, raise error if length limit is exceeded */ Datum varchar2(PG_FUNCTION_ARGS) { VarChar *source = PG_GETARG_VARCHAR_PP(0); int32 typmod = PG_GETARG_INT32(1); bool isExplicit = PG_GETARG_BOOL(2); int32 len, maxlen; char *s_data; len = VARSIZE_ANY_EXHDR(source); s_data = VARDATA_ANY(source); maxlen = typmod - VARHDRSZ; /* No work if typmod is invalid or supplied data fits it already */ if (maxlen < 0 || len <= maxlen) PG_RETURN_VARCHAR_P(source); /* error out if value too long unless it's an explicit cast */ if (!isExplicit) { if (len > maxlen) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("input value length is %d; too long for type varchar2(%d)",len ,maxlen))); } PG_RETURN_VARCHAR_P((VarChar *) cstring_to_text_with_len(s_data,maxlen)); } /* * varchar2typmodin -- type modifier input function * * just use varchartypmodin() */ /* * varchar2typmodout -- type modifier output function * * just use varchartypmodout() */ /* * orafce_concat2 - null safe concat * * returns NULL instead empty string */ Datum orafce_concat2(PG_FUNCTION_ARGS) { text *arg1 = NULL, *arg2 = NULL, *result; int32 len1 = 0, len2 = 0, len; char *ptr; if (!PG_ARGISNULL(0)) { arg1 = PG_GETARG_TEXT_PP(0); len1 = VARSIZE_ANY_EXHDR(arg1); } if (!PG_ARGISNULL(1)) { arg2 = PG_GETARG_TEXT_PP(1); len2 = VARSIZE_ANY_EXHDR(arg2); } /* default behave should be compatible with Postgres */ if (!orafce_varchar2_null_safe_concat) { if (PG_ARGISNULL(0) || PG_ARGISNULL(1)) PG_RETURN_NULL(); } else { if (len1 == 0 && len2 == 0) PG_RETURN_NULL(); } /* hard work, we should to concat strings */ len = len1 + len2 + VARHDRSZ; result = (text *) palloc(len); SET_VARSIZE(result, len); ptr = VARDATA(result); if (len1 > 0) memcpy(ptr, VARDATA_ANY(arg1), len1); if (len2 > 0) memcpy(ptr + len1, VARDATA_ANY(arg2), len2); PG_RETURN_TEXT_P(result); }