pax_global_header00006660000000000000000000000064150175715300014516gustar00rootroot0000000000000052 comment=6d279e33524bda32e621b98143c15c2cb4a12501 orafce-VERSION_4_14_4/000077500000000000000000000000001501757153000144165ustar00rootroot00000000000000orafce-VERSION_4_14_4/.editorconfig000066400000000000000000000002671501757153000171000ustar00rootroot00000000000000root = true [*.{c,h,l,y,pl,pm}] indent_style = tab indent_size = tab tab_width = 4 [*.{sgml,xml}] indent_style = space indent_size = 1 [*.xsl] indent_style = space indent_size = 2 orafce-VERSION_4_14_4/.github/000077500000000000000000000000001501757153000157565ustar00rootroot00000000000000orafce-VERSION_4_14_4/.github/workflows/000077500000000000000000000000001501757153000200135ustar00rootroot00000000000000orafce-VERSION_4_14_4/.github/workflows/main.yml000066400000000000000000000005741501757153000214700ustar00rootroot00000000000000name: CI on: push: branches: - master - main pull_request: jobs: test: strategy: matrix: pg: [17, 16, 15, 14, 13] name: 🐘 PostgreSQL ${{ matrix.pg }} runs-on: ubuntu-latest container: pgxn/pgxn-tools steps: - run: pg-start ${{ matrix.pg }} flex bison - uses: actions/checkout@v2 - run: pg-build-test orafce-VERSION_4_14_4/.github/workflows/release.yml000066400000000000000000000007061501757153000221610ustar00rootroot00000000000000name: Release on: push: tags: [VERSION*] jobs: release: name: Release on PGXN runs-on: ubuntu-latest container: pgxn/pgxn-tools env: PGXN_USERNAME: ${{ secrets.PGXN_USERNAME }} PGXN_PASSWORD: ${{ secrets.PGXN_PASSWORD }} steps: - name: Check out the repo uses: actions/checkout@v4 - name: Bundle the Release id: bundle run: pgxn-bundle - name: Release on PGXN run: pgxn-release orafce-VERSION_4_14_4/.gitignore000077500000000000000000000001631501757153000164110ustar00rootroot00000000000000*.o *.a *.so *.so.* *.sdf *.opensdf *.suo *.*.user *.bc /.deps/ /orafce.sql /orafce.sql.in /results [Oo]bj/ [Bb]in/orafce-VERSION_4_14_4/.travis.yml000066400000000000000000000014651501757153000165350ustar00rootroot00000000000000# run the testsuite on travis-ci.org --- # run once for each of these env: - PGVERSION=9.5 - PGVERSION=9.6 - PGVERSION=10 - PGVERSION=11 - PGVERSION=12 - PGVERSION=13 language: C dist: xenial arch: - amd64 - ppc64le sudo: required before_install: - sudo apt-get update -qq install: # remove all existing clusters - sudo rm -rf /etc/postgresql /var/lib/postgresql # upgrade postgresql-common for new apt.postgresql.org.sh - sudo apt-get install -y postgresql-common - sudo /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh -p -v $PGVERSION -i - sudo apt-get install -y bison flex libicu-dev libssl-dev - sudo -u postgres createuser --superuser $USER script: - make - sudo make install - make installcheck - if test -s regression.diffs; then cat regression.diffs; fi orafce-VERSION_4_14_4/COPYRIGHT.orafce000066400000000000000000000013111501757153000171430ustar00rootroot000000000000000-clause license ("Zero Clause BSD") Copyright (C) 2008-2023 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_4_14_4/INSTALL.orafce000066400000000000000000000015521501757153000167100ustar00rootroot00000000000000Installation ============ 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.5 or later. orafce-VERSION_4_14_4/META.json000066400000000000000000000027301501757153000160410ustar00rootroot00000000000000{ "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": "4.14.4", "maintainer": [ "Pavel Stehule ", "Takahiro Itagaki " ], "license": { "PostgreSQL": "http://www.postgresql.org/about/licence" }, "prereqs": { "runtime": { "requires": { "plpgsql": 0, "PostgreSQL": "11.0.0" }, "recommends": { "PostgreSQL": "17.0.0" } } }, "provides": { "orafce": { "file": "sql/orafce.sql", "docfile": "README.orafce", "version": "4.14.4", "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_4_14_4/Makefile000066400000000000000000000056331501757153000160650ustar00rootroot00000000000000MODULE_big = orafce OBJS= regexp.o\ 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\ replace_empty_string.o\ math.o\ dbms_sql.o EXTENSION = orafce DATA = orafce--4.15.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\ orafce--3.9--3.10.sql\ orafce--3.10--3.11.sql\ orafce--3.11--3.12.sql\ orafce--3.12--3.13.sql\ orafce--3.13--3.14.sql\ orafce--3.14--3.15.sql\ orafce--3.15--3.16.sql\ orafce--3.16--3.17.sql\ orafce--3.17--3.18.sql\ orafce--3.18--3.19.sql\ orafce--3.19--3.20.sql\ orafce--3.20--3.21.sql\ orafce--3.21--3.22.sql\ orafce--3.22--3.23.sql\ orafce--3.23--3.24.sql\ orafce--3.24--3.25.sql\ orafce--3.25--4.0.sql\ orafce--4.0--4.1.sql\ orafce--4.1--4.2.sql\ orafce--4.2--4.3.sql\ orafce--4.3--4.4.sql\ orafce--4.4--4.5.sql\ orafce--4.5--4.6.sql\ orafce--4.6--4.7.sql\ orafce--4.7--4.8.sql\ orafce--4.8--4.9.sql\ orafce--4.9--4.10.sql\ orafce--4.10--4.11.sql\ orafce--4.11--4.12.sql\ orafce--4.12--4.13.sql\ orafce--4.13--4.14.sql\ orafce--4.14--4.15.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\ regexp_func\ dbms_sql #REGRESS_OPTS = --load-language=plpgsql --schedule=parallel_schedule --encoding=utf8 REGRESS_OPTS = --schedule=parallel_schedule --encoding=utf8 # override CFLAGS += -Wextra -Wimplicit-fallthrough=0 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_4_14_4/NEWS000066400000000000000000000057061501757153000151250ustar00rootroot00000000000000Orafce News - History of user-visible changes Copyright (C) 2008-2023 Orafce Global Development Group Version 4.12.0 - 30 Aug 2024 * fix (from Oracle's perspective) function to_date('', 'J') Version 4.11.0 - * new function oracle.sys_extract_date Version 4.6.0 - * emit signal by XactCallback instead deferred trigger, store not yet emmited events in transaction scope memory instead in temporary table. New solution strongly reduces delay (and CPU usage), but ensures visible changes to outside of transaction that emmited signal. Version 4.5.0 - 5 Aug 2023 * partial rewriting of dbms_pipe. Now, the synchronization is based on signals instead short sleeping. New method is significantly faster. Version 4.0.0 - 2 Nov 2022 * removed support for PostgreSQL 9.6 and 10 * merged orafce_sql project - implementation of dbms_sql package Version 3.24.0 - 31 Jul 2022 * fixed badly used plain TOAST strategy of types varchar2 and nvarchar2 Version 3.22.0 - 22 Jun 2022 * deuglification - move all objects from public and pg_catalog to oracle schema Version 3.14.0 - 22. Dec 2020 * conversion function unistr * bugfix - allows binary upgrade Version 3.13.4 - 31. May 2020 * enable utl_file on MS Version 3.12.0 - 18. May 2020 * trigger functions oracle.replace_empty_strings and oracle.replace_null_strings & remove support for 9.4 Version 3.11.0 - 30. Mar 2020 * named paths in utl_file package Version 3.9.0 - 14. Feb 2020 * 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_4_14_4/README.asciidoc000066400000000000000000001201641501757153000170570ustar00rootroot00000000000000= Orafce - Oracle's compatibility functions and packages Functions and operators that emulate a subset of functions and packages from the Oracle RDBMS. There is an associated Google group - https://groups.google.com/forum/?hl=en#!forum/orafce-general The Orafce is supported in https://aws.amazon.com/about-aws/whats-new/2018/03/amazon-aurora-with-postgresql-compatibility-supports-minor-version-9-6-6/?nc1=h_ls[AWS Aurora with PostgreSQL Compatibility] and also in https://azure.microsoft.com/en-gb/updates/the-orafce-extension-on-azure-database-for-postgresql-is-now-available/[Azure Database for PostgreSQL]. == Oracle functions and Oracle packages This module contains some useful functions that can help with porting Oracle application to PostgreSQL or that can be generally useful. Built-in Oracle date functions have been tested against Oracle 10 for conformance. Date ranges from 1960 to 2070 work correctly. Dates before 1582-10-05 with the 'J' format and before 1100-03-01 with other formats cannot be verified due to a bug in Oracle. All functions are fully compatibles with Oracle and respect all known format strings. Detailed descriptions can be found on the internet. Use keywords like : 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) numeric - 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 ---- * to_date(text, text) timestamp - will typecast input text with the specified format to timestamp. The GUC `orafce.orafce_emit_error_on_date_bug` is used to specify wether an error is reported when the date value hits the Oracle bug on dates. This bug appears with dates before `1582-10-05` when the `'J'` format is used (`'J2299159'`) and before `1100-03-01` with other formats. An error is reported by default, to disable this behavior `set orafce.orafce_emit_error_on_date_bug to off`. ---- SELECT oracle.to_date('112012', 'J'); ERROR: Dates before 1582-10-05 ('J2299159') cannot be verified due to a bug in Oracle. SELECT oracle.to_date('1003-03-15', 'yyyy-mm-dd'); ERROR: Dates before 1100-03-01 cannot be verified due to a bug in Oracle. SET orafce.oracle_compatibility_date_limit TO off; SELECT oracle.to_date('112012', 'J'); to_date ------------------------ 4407-07-30 00:00:00 BC (1 row) SELECT oracle.to_date('1003/03/15', 'yyyy/mm/dd'); to_date --------------------- 1003-03-15 00:00:00 (1 row) ---- == oracle.date data type This module contains 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..Saturday. + ----- 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.sys_extract_utc(timestamp with timezone) - Returns timestamp in utc timezone + ----- oracle.sys_extract_utc(current_timestamp) ----- * oracle.sys_extract_utc(oracle.date) - Returns timestamp in utc timezone, when time zone is not specified, session (current PostgreSQL) timezone is used + ----- oracle.sys_extract_utc(oracle.date '2005-05-24 11:21:12', 1) -> 2005-05-24 09:21:12 ----- * 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 functions like oracle.add_months,oracle.last_day,oracle.next_day,oracle.months_between are 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, it has been added in orafce. This table is in schema `oracle`. Usually you want allow unqualified access - so you should to add this schema to `search_path` configuration (like `search_path = 'oracle, pg_catalog, "$user", public'` in `postgresql.conf`). == Package dbms_output PostgreSQL sends information to the client via RAISE NOTICE. Oracle uses dbms_output.put_line(). This works differently from 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 programs to read from and write to any files that are accessible from server. Every session can open a maximum of ten files and max line size is 32K. This package contains following 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 formatted text into file * utl_file.tmpdir() - get path of temp directory Because PostgreSQL doesn't support call by reference, some functions are slightly 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 the package you have to set the utl_file.utl_file_dir table. It contains all allowed directories without ending symbol ('/' or '\'). On WinNT platform, the paths have to end with symbol '\' every time. Directory entries can be named (second column in table `utl_file.utl_file_dir`). The `location` parameter can be either the directory name or the dictionary path. The location is first interpreted and checked as a directory name. If not found (in 2nd column), then the location is interpreted and checked as a path. Functions from utl_file package (schema on Postgres) requires a access to table utl_file.utl_file_dir. This fact can be used to control what users can use these functions or not. Default setting is READ for PUBLIC. INSERT, UPDATE can do only privileged user (super user). So unprivileged user can use functions from this package, but cannot to change list of safe directories (content of utl_file.utl_file_dir table). The content of this table is visible for PUBLIC (or should be visible for users who uses functions from this package). == package dbms_sql This is implementation of Oracle's API of package DBMS_SQL It doesn't ensure full compatibility, but should to decrease a work necessary for successful migration. Attention: PostgreSQL architecture is different than Oracle's architecture. PL/pgSQL is executed in same context like SQL engine. Then is not any reason to use Oracle's patterns like bulk collect and iteration over collection in Postgres to get good performance. This code is designed to reduce work related to porting some applications from Oracle to Postgres, and it can work well. But there will not be any performance advantage aganst buildin PL/pgSQL statements. The emulation of Oracle's API has memory and CPU overhead, that can be significant on bigger data. === Functionality This extension implements subset of Oracle's dbms_sql interface. The goal of this extension is not a compatibility with Oracle, it is designed to reduce some work related migration Oracle's applications to Postgres. Some basic bulk DML functionality is supported: ---- do $$ declare c int; a int[]; b varchar[]; ca numeric[]; begin c := dbms_sql.open_cursor(); call dbms_sql.parse(c, 'insert into foo values(:a, :b, :c)'); a := ARRAY[1, 2, 3, 4, 5]; b := ARRAY['Ahoj', 'Nazdar', 'Bazar']; ca := ARRAY[3.14, 2.22, 3.8, 4]; call dbms_sql.bind_array(c, 'a', a, 2, 3); call dbms_sql.bind_array(c, 'b', b, 3, 4); call dbms_sql.bind_array(c, 'c', ca); raise notice 'inserted rows %d', dbms_sql.execute(c); end; $$; do $$ declare c int; a int[]; b varchar[]; ca numeric[]; begin c := dbms_sql.open_cursor(); call dbms_sql.parse(c, 'select i, ''Ahoj'' || i, i + 0.003 from generate_series(1, 35) g(i)'); call dbms_sql.define_array(c, 1, a, 10, 1); call dbms_sql.define_array(c, 2, b, 10, 1); call dbms_sql.define_array(c, 3, ca, 10, 1); perform dbms_sql.execute(c); while dbms_sql.fetch_rows(c) > 0 loop call dbms_sql.column_value(c, 1, a); call dbms_sql.column_value(c, 2, b); call dbms_sql.column_value(c, 3, ca); raise notice 'a = %', a; raise notice 'b = %', b; raise notice 'c = %', ca; end loop; call dbms_sql.close_cursor(c); end; $$; ---- There is function `dbms_sql.describe_columns_f`, that is like procedure `dbms_sql.describe_columns`. Attention, the type ids are related to PostgreSQL type system. The values are not converted to Oracle's numbers ---- do $$ declare c int; r record; d dbms_sql.desc_rec; begin c := dbms_sql.open_cursor(); call dbms_sql.parse(c, 'select * from pg_class'); r := dbms_sql.describe_columns(c); raise notice '%', r.col_cnt; foreach d in array r.desc_t loop raise notice '% %', d.col_name, d.col_type::regtype; end loop; call dbms_sql.close_cursor(c); end; $$; do $$ declare c int; n int; d dbms_sql.desc_rec; da dbms_sql.desc_rec[]; begin c := dbms_sql.open_cursor(); call dbms_sql.parse(c, 'select * from pg_class'); call dbms_sql.describe_columns(c, n, da); raise notice '%', n; foreach d in array da loop raise notice '% %', d.col_name, d.col_type::regtype; end loop; call dbms_sql.close_cursor(c); end; $$; ---- == Package dbms_pipe This package is an emulation of dbms_pipe Oracle package. It provides inter-session communication. 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 doesn'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 functions for working with business 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 the 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 characters. You can use negative num_in * plvstr.right(str text, n int) - Returns last num_in characters. You can use negative num_ni * plvstr.swap(str text, replace text, start int, length 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 * dbms_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 protects 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, greatest, least, bitand, nanvl, sinh, cosh, tanh, oracle.substr and oracle.mod. * 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 * oracle.listagg(str text [, separator text]) - aggregate values to list * oracle.wm_concat(str text) - aggregate values to comma separatated list * oracle.median(float4) - calculate a median * oracle.median(float8) - calculate a median * oracle.to_number(text) - converts a string to a number * oracle.to_number(numeric) - converts a string to a number * oracle.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 * oracle.greatest(anyelement, anyelement[]) - Oracle compatibility greatest, return NULL on NULL input * oracle.least(anyelement, anyelement[]) - Oracle compatibility least, return NULL on NULL input * oracle.mod(int, int) - Oracle compatibility mod, If the second parameter is zero, it returns the first parameter * oracle.remainder(int, int) - returns remainder of number divided by another number * oracle.remainder(numeric, numeric) - returns remainder of number divided by another number * oracle.sys_guid() - returns bytea - 16 bytes of global uniq id 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. Functions oracle.decode, oracle.greatest and oracle.least must always be prefixed by the schema name even if the oracle is before pg_catalog in the search_path because these functions are implemented inside PostgreSQL parser and analyzer. Without the schema name the internal functions will always be used. 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. The oracle.substr with three arguments can returns different result (null or empty string) in dependency to setting orafce.using_substring_zero_width_in_substr variable (oracle, warning_oracle, orafce, warning_orafce). This different result is returned only when third argument (substring_length) is zero. Default is warning_oracle, thats means raising warning and returning null. == oracle.sys_guid() function This functions returns global unique id. It calls specified functions from "uuid-ossp" extension, and then this function should be installed before function sys_guid is used. By default this function uses function uuid_generate_v1, but function uuid_generate_v1mc, uuid_generate_v4 can be used too (by setting orafce.sys_guid_source). oracle.sys_guid can use builin gen_random_uuid func too. In this case the extension "uuid-ossp" is not required. == 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 behaviour is very similar to Oracle. Attention: - when result is empty string, then result is NULL. This behaviour 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). It's 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 cannot support both BYTE and CHARACTER semantics for a given varchar type in the same database. We chose 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 == Triggers == Oracle doesn't make differences between NULL and empty string (when a value is used as text). For Postgres NULL and empty string are different values. For simplicity is good to ensure (in Postgres database) use only NULLs (and don't use empty strings) or use only empty strings (and don't use NULLs) for text type columns. Both variants has some advantages and disadvantages. This can be enusured with trigger functions: ---- oracle.replace_empty_strings([ 'on' | 'true' | 'warning' | 'error' ]) oracle.replace_null_strings([ 'on' | 'true' | 'warning' | 'error' ]) ---- Optional string argument is used as indicator so these functions should to raise warning (possibly error) when row was changed inside these functions. ---- CREATE TABLE test(id serial, name varchar, surname varchar); CREATE TRIGGER test_trg BEFORE INSERT OR UPDATE ON test FOR EACH ROW EXECUTE PROCEDURE oracle.replace_empty_strings(); INSERT INTO test(name, surname) VALUES('', 'Stehule'); -- name will be replaced by NULL ---- == 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: * Gabriele Bartolini (gbartolini) * Jeffrey Cohen (jcohen) * Giles Darold (darold) * Pavan Deolasee (pavanvd) * Peter Eisentraut (petere) * Beena Emerson (b-emerson) * Takahiro Itagaki (itagaki) * Zdenek Kotala (hlipa) * Amit Langote (amitlan) * Heikki Linnakangas (hlinnaka) * Fujii Masao * Marco Nenciarini (mnencia) * Vinayak Pokale * Gavin Sherry (swm) * Pavel Stehule (okbob) * Rahila Syed (rahila) orafce-VERSION_4_14_4/README.meson_msvc000066400000000000000000000014361501757153000174520ustar00rootroot00000000000000Build on Microsoft Windows with Microsoft Visual Studio and meson 1. Install - Microsft Visual Studio with C and C++ support - Meson - PostgreSQL 2. Run x64 Native Tools Command Prompt for VS 20xx (*** ensure x64 ***) 3. Set PATH set PATH=%PATH%;C:\Program Files\PostgreSQL\16\bin;C:\Program Files\Meson 4. execute in orafce directory (buildtype should be release or plain, attention - the release buildtype inject dependency on vc_redist.x64.exe) meson setup --wipe --buildtype release plain cd build ninja sudo ninja install (on linux) ninja test (on linux) # ninja bindist 5. tests on MSWIN requires installation DiffUtils from gnuwin32 set PATH=%PATH%;C:\Program Files (x86)\GnuWin32\bin set PGPORT= set PGUSER= set PGPASSWORD= ninja testorafce-VERSION_4_14_4/README.msvc000066400000000000000000000040251501757153000162460ustar00rootroot00000000000000Build on Microsoft Windows with Microsoft Visual Studio 1. For Postgres 12 and higher you need libicu headers 2. Orafce library is linked with runtime library - this library should to use same platform toolset like Postgres server. 3. Start empty project 4. Add existing items - *.c and *.h files except "sqlscan.c". This file is compiled as include of sqlparse.c and should not be compiled as separate c file! 5. In configuration manager choose configuration - "Release" and platform. Platform must be same like your Postgres server. 6. V project properties set Under "Configuration Properties" -> "General", set "Configuration Type" to "Dynamic Library (.dll)". Under "C/C++" -> "Preprocessor Directives", add the directive "WIN32" Under "C/C++" -> "Code Generation", set "Enable C++ Exceptions" to "No" "C/C++" -> "Code generation" -> "Runtime library" must be /MD Under "Advanced" set "Compile As" to "C Code" Under "Linker" -> "Manifest File", set "Generate Manifest" to "No" Under "Linker" -> "Input" -> "Additional Dependencies", add postgres.lib to the library list In the properties dialog, go to "Configuration Properties" -> "C/C++" -> "General", "Additional Include Directories" include\server\port\win32_msvc include\server\port\win32 include\server include Attention, there should be real paths to include files .. "include\server\port\win32_msvc" is in my case "C:\Program Files\PostgreSQL\13\include\server\port\win32_msvc". All four paths to include folders should be correct. PostgreSQL 10 and higher requires lib ICU include file. I had install libICU before, and then add to "Additional Include Directories" C:\Users\user\Documents\icu-59.1-vs2015\include You’ll also need to set the library path. Under "Linker"->"General", in Additional Library Directories. In my case that’s C:\Program Files\PostgreSQL\12\lib. set "Linker"->"General"->"Link Library Dependencies" to No. 7. Under "C/C++" -> "Advanced", Set "Disable Specific Warnings" to "4996" 8. make build orafce-VERSION_4_14_4/aggregate.c000066400000000000000000000172671501757153000165250ustar00rootroot00000000000000#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_4_14_4/alert.c000066400000000000000000000603101501757153000156710ustar00rootroot00000000000000#include "postgres.h" #include "access/xact.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 "storage/lwlock.h" #include "storage/proc.h" #include "storage/procarray.h" #include "utils/builtins.h" #include "utils/timestamp.h" #if PG_VERSION_NUM >= 140000 #include "utils/wait_event.h" #elif PG_VERSION_NUM >= 130000 #include "pgstat.h" #endif #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_waitany_maxwait); PG_FUNCTION_INFO_V1(dbms_alert_waitone_maxwait); #if PG_VERSION_NUM >= 130000 extern ConditionVariable *alert_cv; #endif typedef struct alert_signal_data { text *event; text *message; struct alert_signal_data *next; } alert_signal_data; static MemoryContext local_buf_cxt; static LocalTransactionId local_buf_lxid = InvalidTransactionId; static alert_signal_data *signals; #ifndef _GetCurrentTimestamp #define _GetCurrentTimestamp() GetCurrentTimestamp() #endif #ifndef GetNowFloat #ifdef HAVE_INT64_TIMESTAMP #define GetNowFloat() ((float8) _GetCurrentTimestamp() / 1000000.0) #else #define GetNowFloat() _GetCurrentTimestamp() #endif #endif /* in sec 1000 days */ #define MAXWAIT 86400000 #if PG_VERSION_NUM >= 170000 #define CURRENT_LXID (MyProc->vxid.lxid) #else #define CURRENT_LXID (MyProc->lxid) #endif static void unregister_event(int event_id, int sid); 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); /* * There are maximum 30 events and 255 collaborating sessions * */ static alert_lock *session_lock = NULL; #define NOT_FOUND -1 #define NOT_USED -1 /* * Compare text and cstr */ static int textcmpm(text *txt, char *str) { char *p; int len; len = VARSIZE(txt) - VARHDRSZ; p = VARDATA(txt); while (len-- && *p != '\0') { int retval; if (0 != (retval = *p++ - *str++)) return retval; } if (len > 0) return 1; if (*str != '\0') return -1; return 0; } /* * this function is called when we know so session with sid is not valid * anymore. */ static void purge_shared_alert_mem() { int i; LWLockAcquire(ProcArrayLock, LW_SHARED); for (i = 0; i < MAX_LOCKS; i++) { PGPROC *proc; if (locks[i].sid == NOT_USED) continue; proc = BackendPidGetProcWithLock(locks[i].pid); if (proc == NULL) { int j; int invalid_sid = locks[i].sid; for (j = 0; j < MAX_EVENTS; j++) { if (events[j].event_name != NULL) { find_and_remove_message_item(j, invalid_sid, false, true, true, NULL, NULL); unregister_event(j, invalid_sid); } } locks[i].sid = NOT_USED; } } LWLockRelease(ProcArrayLock); } /* * 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) { purge_shared_alert_mem(); for (i = 0; i < MAX_LOCKS; i++) { if (locks[i].sid == NOT_USED) { first_free = i; break; } } } if (first_free != NOT_FOUND) { locks[first_free].sid = sid; locks[first_free].echo = NULL; locks[first_free].pid = MyProcPid; 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 registration 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; ev = &events[event_id]; if (ev->receivers_number > 0) { int i; 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; 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; int _message_id; 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; 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) { int i,j,k; 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); 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)) { alert_event *ev; 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 cycle = 0; float8 endtime; float8 timeout = 2; WATCH_PRE(timeout, endtime, cycle); if (ora_lock_shmem(SHMEMMSGSZ, MAX_PIPES,MAX_EVENTS,MAX_LOCKS,false)) { alert_lock *alck; int i; 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); } } alck = find_lock(sid, false); if (alck) { /* After all events unregistration, an echo field should NULL */ Assert(alck->echo == NULL); alck->sid = NOT_USED; session_lock = NULL; } LWLockRelease(shmem_lockid); PG_RETURN_VOID(); } WATCH_POST(timeout, endtime, cycle); LOCK_ERROR(); PG_RETURN_VOID(); } /* * workhorse for dbms_alert_waitany and dbms_alert_waitany_maxwait */ static Datum _dbms_alert_waitany(int timeout, FunctionCallInfo fcinfo) { TupleDesc tupdesc; AttInMetadata *attinmeta; HeapTuple tuple; Datum result; char *str[3] = {NULL, NULL, "1"}; instr_time start_time; TupleDesc btupdesc; #if PG_VERSION_NUM < 130000 long cycle = 0; #endif INSTR_TIME_SET_CURRENT(start_time); for (;;) { 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); } if (timeout > 0) { instr_time cur_time; long cur_timeout; INSTR_TIME_SET_CURRENT(cur_time); INSTR_TIME_SUBTRACT(cur_time, start_time); cur_timeout = timeout * 1000L - (long) INSTR_TIME_GET_MILLISEC(cur_time); if (cur_timeout <= 0) break; #if PG_VERSION_NUM >= 130000 if (cur_timeout > 1000) cur_timeout = 1000; if (ConditionVariableTimedSleep(alert_cv, cur_timeout, PG_WAIT_EXTENSION)) { /* exit on timeout */ INSTR_TIME_SET_CURRENT(cur_time); INSTR_TIME_SUBTRACT(cur_time, start_time); cur_timeout = timeout * 1000L - (long) INSTR_TIME_GET_MILLISEC(cur_time); if (cur_timeout <= 0) break; } #else if (cycle++ % 10) CHECK_FOR_INTERRUPTS(); pg_usleep(10000L); /* exit on timeout */ INSTR_TIME_SET_CURRENT(cur_time); INSTR_TIME_SUBTRACT(cur_time, start_time); cur_timeout = timeout * 1000L - (long) INSTR_TIME_GET_MILLISEC(cur_time); if (cur_timeout <= 0) break; #endif } else break; } #if PG_VERSION_NUM >= 130000 ConditionVariableCancelSleep(); #endif 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.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) { int timeout; if (!PG_ARGISNULL(0)) { /* * cannot to change SQL API now, so use not well choosed * float. */ timeout = (int) PG_GETARG_FLOAT8(0); if (timeout < 0) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("negative timeout is not allowed"))); if (timeout > MAXWAIT) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("timeout is too large (maximum: %d)", MAXWAIT))); } else timeout = MAXWAIT; return _dbms_alert_waitany(timeout, fcinfo); } Datum dbms_alert_waitany_maxwait(PG_FUNCTION_ARGS) { return _dbms_alert_waitany(MAXWAIT, fcinfo); } /* * common part of dbms_alert_waitone and dbms_alert_waitone_maxwait */ static Datum _dbms_alert_waitone(text *name, int timeout, FunctionCallInfo fcinfo) { TupleDesc tupdesc; AttInMetadata *attinmeta; HeapTuple tuple; Datum result; int message_id; char *str[2] = {NULL,"1"}; char *event_name; instr_time start_time; TupleDesc btupdesc; #if PG_VERSION_NUM < 130000 long cycle = 0; #endif INSTR_TIME_SET_CURRENT(start_time); for (;;) { 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); } if (timeout > 0) { instr_time cur_time; long cur_timeout; INSTR_TIME_SET_CURRENT(cur_time); INSTR_TIME_SUBTRACT(cur_time, start_time); cur_timeout = timeout * 1000L - (long) INSTR_TIME_GET_MILLISEC(cur_time); if (cur_timeout <= 0) break; #if PG_VERSION_NUM >= 130000 if (cur_timeout > 1000) cur_timeout = 1000; if (ConditionVariableTimedSleep(alert_cv, cur_timeout, PG_WAIT_EXTENSION)) { /* exit on timeout */ INSTR_TIME_SET_CURRENT(cur_time); INSTR_TIME_SUBTRACT(cur_time, start_time); cur_timeout = timeout * 1000L - (long) INSTR_TIME_GET_MILLISEC(cur_time); if (cur_timeout <= 0) break; } #else if (cycle++ % 10) CHECK_FOR_INTERRUPTS(); pg_usleep(10000L); /* exit on timeout */ INSTR_TIME_SET_CURRENT(cur_time); INSTR_TIME_SUBTRACT(cur_time, start_time); cur_timeout = timeout * 1000L - (long) INSTR_TIME_GET_MILLISEC(cur_time); if (cur_timeout <= 0) break; #endif } else break; } #if PG_VERSION_NUM >= 130000 ConditionVariableCancelSleep(); #endif 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.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; int timeout; 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)) { /* * cannot to change SQL API now, so use not well choosed * float. */ timeout = (int) PG_GETARG_FLOAT8(1); if (timeout < 0) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("negative timeout is not allowed"))); if (timeout > MAXWAIT) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("timeout is too large (maximum: %d)", MAXWAIT))); } else timeout = MAXWAIT; name = PG_GETARG_TEXT_P(0); return _dbms_alert_waitone(name, timeout, fcinfo); } Datum dbms_alert_waitone_maxwait(PG_FUNCTION_ARGS) { text *name; if (PG_ARGISNULL(0)) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("event name is NULL"), errdetail("Eventname may not be NULL."))); name = PG_GETARG_TEXT_P(0); return _dbms_alert_waitone(name, MAXWAIT, fcinfo); } /* * * 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(); } void orafce_xact_cb(XactEvent event, void *arg) { if (event == XACT_EVENT_PRE_COMMIT) { /* * In this time we have valid MyProc->lxid, in ACT_EVENT_COMMIT is * MyProc->lxid already invalided. So we need to invalid pointer to * obsolete buffer here. */ if (local_buf_lxid != CURRENT_LXID) signals = NULL; } else if (event == XACT_EVENT_COMMIT && signals) { if (ora_lock_shmem(SHMEMMSGSZ, MAX_PIPES, MAX_EVENTS, MAX_LOCKS, false)) { alert_signal_data *signal = signals; while (signal) { create_message(signal->event, signal->message); signal = signal->next; } signals = NULL; LWLockRelease(shmem_lockid); #if PG_VERSION_NUM >= 130000 ConditionVariableBroadcast(alert_cv); #endif } } } static bool text_eq(const text *p1, const text *p2) { int len1, len2; Assert(p1 && p2); len1 = VARSIZE_ANY_EXHDR(p1); len2 = VARSIZE_ANY_EXHDR(p2); if (len1 == len2) { return memcmp(VARDATA_ANY(p1), VARDATA_ANY(p2), len1) == 0; } else return false; } /* * * 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.) * */ Datum dbms_alert_signal(PG_FUNCTION_ARGS) { text *event; text *message; alert_signal_data *new_signal; alert_signal_data *last_signal = NULL; MemoryContext oldcxt; if (PG_ARGISNULL(0)) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("event name is NULL"), errdetail("Eventname may not be NULL."))); event = PG_GETARG_TEXT_P(0); message = (!PG_ARGISNULL(1)) ? PG_GETARG_TEXT_P(1) : NULL; if (local_buf_lxid != CURRENT_LXID) { local_buf_cxt = AllocSetContextCreate(TopTransactionContext, "dbms_alert local buffer", ALLOCSET_START_SMALL_SIZES); local_buf_lxid = CURRENT_LXID; signals = NULL; last_signal = NULL; } if (signals) { alert_signal_data *s = signals; while (s) { last_signal = s; if (text_eq(s->event, event) == 0) { if (!message && !s->message) PG_RETURN_VOID(); if (message && s->message && text_eq(message, s->message) == 0) PG_RETURN_VOID(); } s = s->next; } } oldcxt = MemoryContextSwitchTo(local_buf_cxt); new_signal = palloc(sizeof(alert_signal_data)); new_signal->event = TextPCopy(event); new_signal->message = message ? TextPCopy(message) : NULL; new_signal->next = NULL; MemoryContextSwitchTo(oldcxt); if (signals) last_signal->next = new_signal; else signals = new_signal; PG_RETURN_VOID(); } /* * removed by Orafce 9.6, header is necessary to allow upgrade * */ Datum dbms_alert_defered_signal(PG_FUNCTION_ARGS) { PG_RETURN_NULL(); } orafce-VERSION_4_14_4/assert.c000066400000000000000000000241161501757153000160670ustar00rootroot00000000000000#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 "orafce.h" #include "builtins.h" #include "utils/regproc.h" 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); PG_FUNCTION_INFO_V1(dbms_alert_defered_signal); #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); /* * Is character a valid identifier start? * Must match scan.l's {ident_start} character class. */ static bool orafce_is_ident_start(unsigned char c) { /* Underscores and ASCII letters are OK */ if (c == '_') return true; if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) return true; /* Any high-bit-set character is OK (might be part of a multibyte char) */ if (IS_HIGHBIT_SET(c)) return true; return false; } /* * Is character a valid identifier continuation? * Must match scan.l's {ident_cont} character class. */ static bool orafce_is_ident_cont(unsigned char c) { /* Can be digit or dollar sign ... */ if ((c >= '0' && c <= '9') || c == '$') return true; /* ... or an identifier start character */ return orafce_is_ident_start(c); } /* * 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 { if (*nextp == '\"') { char *endp; /* Quoted name --- collapse quote-quote pairs, no downcasing */ 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 */ if (orafce_is_ident_start(*nextp)) { nextp++; while (*nextp && orafce_is_ident_cont(*nextp)) nextp++; } else return false; } 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); #if PG_VERSION_NUM >= 160000 names = stringToQualifiedNameList(nspname, NULL); #else names = stringToQualifiedNameList(nspname); #endif 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(); #if PG_VERSION_NUM >= 160000 aclresult = object_aclcheck(NamespaceRelationId,namespaceId, GetUserId(), ACL_USAGE); #else aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_USAGE); #endif 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 == '"') { char *last = cp + len - 1; /* don't allow empty identifier */ if (len < 3) return false; /* last char should be double quote */ if (*last != '"') return false; cp += 1; while (*cp && cp < last) { if (*cp++ == '"') { if (cp < last) { if (*cp++ != '"') return false; } else return false; } } return true; } else { if (orafce_is_ident_start(*cp)) { char *last = cp + len - 1; cp += 1; while (cp < last) { if (!orafce_is_ident_cont(*cp++)) return false; } } else 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); #if PG_VERSION_NUM >= 160000 names = stringToQualifiedNameList(object_name, NULL); #else names = stringToQualifiedNameList(object_name); #endif classId = RangeVarGetRelid(makeRangeVarFromNameList(names), NoLock, true); if (!OidIsValid(classId)) INVALID_OBJECT_NAME_EXCEPTION(); PG_RETURN_TEXT_P(str); } orafce-VERSION_4_14_4/assert.h000066400000000000000000000006061501757153000160720ustar00rootroot00000000000000#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_4_14_4/builtins.h000066400000000000000000000427641501757153000164350ustar00rootroot00000000000000 #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_waitany_maxwait(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_alert_waitone_maxwait(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); extern PGDLLEXPORT Datum orafce_unistr(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); extern PGDLLEXPORT Datum orafce_sys_extract_utc(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum orafce_sys_extract_utc_oracle_date(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); extern PGDLLEXPORT Datum ora_greatest(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum ora_least(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum orafce_sys_guid(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); extern PGDLLEXPORT Datum oracle_substrb2(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum oracle_substrb3(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); extern PGDLLEXPORT Datum dbms_utility_get_time(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); /* from replace_empty_string.c */ extern PGDLLEXPORT Datum orafce_replace_empty_strings(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum orafce_replace_null_strings(PG_FUNCTION_ARGS); /* from regexp.c */ extern PGDLLEXPORT Datum orafce_regexp_instr(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum orafce_regexp_instr_no_start(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum orafce_regexp_instr_no_n(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum orafce_regexp_instr_no_endoption(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum orafce_regexp_instr_no_flags(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum orafce_regexp_instr_no_subexpr(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum orafce_textregexreplace_noopt(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum orafce_textregexreplace(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum orafce_textregexreplace_extended(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum orafce_textregexreplace_extended_no_n(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum orafce_textregexreplace_extended_no_flags(PG_FUNCTION_ARGS); /* from math.c */ extern PGDLLEXPORT Datum orafce_reminder_smallint(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum orafce_reminder_int(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum orafce_reminder_bigint(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum orafce_reminder_numeric(PG_FUNCTION_ARGS); /* from dbms_sql.c */ extern PGDLLEXPORT Datum dbms_sql_is_open(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_sql_open_cursor(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_sql_close_cursor(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_sql_parse(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_sql_bind_variable(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_sql_bind_variable_f(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_sql_bind_array_3(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_sql_bind_array_5(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_sql_define_column(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_sql_define_array(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_sql_execute(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_sql_fetch_rows(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_sql_execute_and_fetch(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_sql_column_value(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_sql_column_value_f(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_sql_last_row_count(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_sql_describe_columns(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_sql_describe_columns_f(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum dbms_sql_debug_cursor(PG_FUNCTION_ARGS); #endif orafce-VERSION_4_14_4/charlen.c000066400000000000000000000015641501757153000162040ustar00rootroot00000000000000/* * 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 "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_4_14_4/charpad.c000066400000000000000000000240361501757153000161710ustar00rootroot00000000000000/*---------------------------------------------------------------------------- * * 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" #if PG_VERSION_NUM >= 160000 #include "varatt.h" #endif /* 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, 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 character */ { 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) { int s2_add_width; /* 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, 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 character */ { 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) { int s2_add_width; /* 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_4_14_4/convert.c000066400000000000000000000475131501757153000162540ustar00rootroot00000000000000#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" #if PG_VERSION_NUM < 130000 #include "catalog/namespace.h" #include "utils/memutils.h" #endif #if PG_VERSION_NUM >= 160000 #include "varatt.h" #endif 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); PG_FUNCTION_INFO_V1(orafce_unistr); static int getindex(const char **map, char *mbchar, int mblen); #if PG_VERSION_NUM < 130000 static FmgrInfo *orafce_Utf8ToServerConvProc = NULL; #endif 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), CStringGetTextDatum(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; if (VARSIZE_ANY_EXHDR(arg0) == 0) PG_RETURN_NULL(); 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) * * Note - there is a difference with Oracle - it returns \342\210\274 * what is a tilde char. Orafce returns fullwidth tilde. If it is a * problem, fix it for sef in code. */ #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\274\274", "\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", /* Oracle returns different value \241\307 */ "\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 }; static const char * TO_MULTI_BYTE__EUCCN[95] = { "\241\241", "\243\241", "\243\242", "\243\243", "\243\244", "\243\245", "\243\246", "\243\247", "\243\250", "\243\251", "\243\252", "\243\253", "\243\254", "\243\255", "\243\256", "\243\257", "\243\260", "\243\261", "\243\262", "\243\263", "\243\264", "\243\265", "\243\266", "\243\267", "\243\270", "\243\271", "\243\272", "\243\273", "\243\274", "\243\275", "\243\276", "\243\277", "\243\300", "\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", "\243\333", "\243\334", "\243\335", "\243\336", "\243\337", "\243\340", "\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", "\243\373", "\243\374", "\243\375", "\243\376", }; 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; case PG_EUC_CN: map = TO_MULTI_BYTE__EUCCN; 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; case PG_EUC_CN: map = TO_MULTI_BYTE__EUCCN; 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 - 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); } /* convert hex digit (caller should have verified that) to value */ static unsigned int hexval(unsigned char c) { if (c >= '0' && c <= '9') return c - '0'; if (c >= 'a' && c <= 'f') return c - 'a' + 0xA; if (c >= 'A' && c <= 'F') return c - 'A' + 0xA; elog(ERROR, "invalid hexadecimal digit"); return 0; /* not reached */ } /* * First four chars should be hexnum digits */ static bool isxdigit_four(const char *instr) { return isxdigit((unsigned char) instr[0]) && isxdigit((unsigned char) instr[1]) && isxdigit((unsigned char) instr[2]) && isxdigit((unsigned char) instr[3]); } /* * Translate string with hexadecimal digits to number */ static long int hexval_four(const char *instr) { return (hexval(instr[0]) << 12) + (hexval(instr[1]) << 8) + (hexval(instr[2]) << 4) + hexval(instr[3]); } #if PG_VERSION_NUM < 130000 static bool is_utf16_surrogate_first(pg_wchar c) { return (c >= 0xD800 && c <= 0xDBFF); } static bool is_utf16_surrogate_second(pg_wchar c) { return (c >= 0xDC00 && c <= 0xDFFF); } static pg_wchar surrogate_pair_to_codepoint(pg_wchar first, pg_wchar second) { return ((first & 0x3FF) << 10) + 0x10000 + (second & 0x3FF); } static inline bool is_valid_unicode_codepoint(pg_wchar c) { return (c > 0 && c <= 0x10FFFF); } #define MAX_UNICODE_EQUIVALENT_STRING 16 /* * Convert a single Unicode code point into a string in the server encoding. * * The code point given by "c" is converted and stored at *s, which must * have at least MAX_UNICODE_EQUIVALENT_STRING+1 bytes available. * The output will have a trailing '\0'. Throws error if the conversion * cannot be performed. * * Note that this relies on having previously looked up any required * conversion function. That's partly for speed but mostly because the parser * may call this outside any transaction, or in an aborted transaction. */ static void pg_unicode_to_server(pg_wchar c, unsigned char *s) { unsigned char c_as_utf8[MAX_MULTIBYTE_CHAR_LEN + 1]; int c_as_utf8_len; int server_encoding; /* * Complain if invalid Unicode code point. The choice of errcode here is * debatable, but really our caller should have checked this anyway. */ if (!is_valid_unicode_codepoint(c)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("invalid Unicode code point"))); /* Otherwise, if it's in ASCII range, conversion is trivial */ if (c <= 0x7F) { s[0] = (unsigned char) c; s[1] = '\0'; return; } /* If the server encoding is UTF-8, we just need to reformat the code */ server_encoding = GetDatabaseEncoding(); if (server_encoding == PG_UTF8) { unicode_to_utf8(c, s); s[pg_utf_mblen(s)] = '\0'; return; } /* For all other cases, we must have a conversion function available */ if (orafce_Utf8ToServerConvProc == NULL) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("conversion between UTF8 and %s is not supported", GetDatabaseEncodingName()))); /* Construct UTF-8 source string */ unicode_to_utf8(c, c_as_utf8); c_as_utf8_len = pg_utf_mblen(c_as_utf8); c_as_utf8[c_as_utf8_len] = '\0'; /* Convert, or throw error if we can't */ FunctionCall5(orafce_Utf8ToServerConvProc, Int32GetDatum(PG_UTF8), Int32GetDatum(server_encoding), CStringGetDatum(c_as_utf8), CStringGetDatum(s), Int32GetDatum(c_as_utf8_len)); } static void initializeUtf8ToServerConvProc(void) { int current_server_encoding; orafce_Utf8ToServerConvProc = NULL; /* * Also look up the UTF8-to-server conversion function if needed. Since * the server encoding is fixed within any one backend process, we don't * have to do this more than once. */ current_server_encoding = GetDatabaseEncoding(); if (current_server_encoding != PG_UTF8 && current_server_encoding != PG_SQL_ASCII) { Oid utf8_to_server_proc; utf8_to_server_proc = FindDefaultConversionProc(PG_UTF8, current_server_encoding); /* If there's no such conversion, just leave the pointer as NULL */ if (OidIsValid(utf8_to_server_proc)) { FmgrInfo *finfo; finfo = (FmgrInfo *) MemoryContextAlloc(TopMemoryContext, sizeof(FmgrInfo)); fmgr_info_cxt(utf8_to_server_proc, finfo, TopMemoryContext); /* Set Utf8ToServerConvProc only after data is fully valid */ orafce_Utf8ToServerConvProc = finfo; } } } #endif /* is Unicode code point acceptable? */ static void check_unicode_value(pg_wchar c) { if (!is_valid_unicode_codepoint(c)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("invalid Unicode escape value"))); } /* * Replaces unicode escape sequences by unicode chars */ Datum orafce_unistr(PG_FUNCTION_ARGS) { StringInfoData str; text *input_text; text *result; pg_wchar pair_first = 0; char cbuf[MAX_UNICODE_EQUIVALENT_STRING + 1]; char *instr; int len; /* when input string is NULL, then result is NULL too */ if (PG_ARGISNULL(0)) PG_RETURN_NULL(); input_text = PG_GETARG_TEXT_PP(0); instr = VARDATA_ANY(input_text); len = VARSIZE_ANY_EXHDR(input_text); initStringInfo(&str); #if PG_VERSION_NUM < 130000 initializeUtf8ToServerConvProc(); #endif while (len > 0) { if (instr[0] == '\\') { if (len >= 2 && instr[1] == '\\') { if (pair_first) goto invalid_pair; appendStringInfoChar(&str, '\\'); instr += 2; len -= 2; } else if ((len >= 5 && isxdigit_four(&instr[1])) || (len >= 6 && instr[1] == 'u' && isxdigit_four(&instr[2]))) { pg_wchar unicode; int offset = instr[1] == 'u' ? 2 : 1; unicode = hexval_four(instr + offset); check_unicode_value(unicode); if (pair_first) { if (is_utf16_surrogate_second(unicode)) { unicode = surrogate_pair_to_codepoint(pair_first, unicode); pair_first = 0; } else goto invalid_pair; } else if (is_utf16_surrogate_second(unicode)) goto invalid_pair; if (is_utf16_surrogate_first(unicode)) pair_first = unicode; else { pg_unicode_to_server(unicode, (unsigned char *) cbuf); appendStringInfoString(&str, cbuf); } instr += 4 + offset; len -= 4 + offset; } else if (len >= 8 && instr[1] == '+' && isxdigit_four(&instr[2]) && isxdigit((unsigned char) instr[6]) && isxdigit((unsigned char) instr[7])) { pg_wchar unicode; unicode = (hexval_four(&instr[2]) << 8) + (hexval(instr[6]) << 4) + hexval(instr[7]); check_unicode_value(unicode); if (pair_first) { if (is_utf16_surrogate_second(unicode)) { unicode = surrogate_pair_to_codepoint(pair_first, unicode); pair_first = 0; } else goto invalid_pair; } else if (is_utf16_surrogate_second(unicode)) goto invalid_pair; if (is_utf16_surrogate_first(unicode)) pair_first = unicode; else { pg_unicode_to_server(unicode, (unsigned char *) cbuf); appendStringInfoString(&str, cbuf); } instr += 8; len -= 8; } else if (len >= 10 && instr[1] == 'U' && isxdigit_four(&instr[2]) && isxdigit_four(&instr[6])) { pg_wchar unicode; unicode = (hexval_four(&instr[2]) << 16) + hexval_four(&instr[6]); check_unicode_value(unicode); if (pair_first) { if (is_utf16_surrogate_second(unicode)) { unicode = surrogate_pair_to_codepoint(pair_first, unicode); pair_first = 0; } else goto invalid_pair; } else if (is_utf16_surrogate_second(unicode)) goto invalid_pair; if (is_utf16_surrogate_first(unicode)) pair_first = unicode; else { pg_unicode_to_server(unicode, (unsigned char *) cbuf); appendStringInfoString(&str, cbuf); } instr += 10; len -= 10; } else ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("invalid Unicode escape"), errhint("Unicode escapes must be \\XXXX, \\+XXXXXX, \\uXXXX or \\UXXXXXXXX."))); } else { if (pair_first) goto invalid_pair; appendStringInfoChar(&str, *instr++); len--; } } /* unfinished surrogate pair? */ if (pair_first) goto invalid_pair; result = cstring_to_text_with_len(str.data, str.len); pfree(str.data); PG_RETURN_TEXT_P(result); invalid_pair: ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("invalid Unicode surrogate pair"))); #if defined(_MSC_VER) /* be MSVC quiet */ return 0; #endif } orafce-VERSION_4_14_4/datefce.c000066400000000000000000000633751501757153000161730ustar00rootroot00000000000000#include "postgres.h" #include "access/xact.h" #if PG_VERSION_NUM >= 160000 #include "utils/guc_hooks.h" #else #include "commands/variable.h" #endif #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" bool orafce_emit_error_on_date_bug = true; #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, size_t 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: static 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); PG_FUNCTION_INFO_V1(orafce_sys_extract_utc); PG_FUNCTION_INFO_V1(orafce_sys_extract_utc_oracle_date); /* * Search const value in char array * */ int ora_seq_search(const char *name, STRING_PTR_FIELD_TYPE array[], size_t 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 < (int) 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 ndays; if (m < 0 || 12 < m) ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("date out of range"))); ndays = month_days[m - 1]; if (m == 2 && (y % 400 == 0 || (y % 4 == 0 && y % 100 != 0))) ndays += 1; /* February 29 in leap year */ return ndays; } /******************************************************************** * * months_between * * Syntax: * * numeric 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_DATUM(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 ndays; DateADT result; div_t v; bool is_last_day; j2date(day + POSTGRES_EPOCH_JDATE, &y, &m, &d); is_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; ndays = days_of_month(y, m); if (is_last_day || d > ndays) d = ndays; 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, 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) { DateADT result2; 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 d2 = J2DAY(day1); /* some exceptions */ if ((day >= cmp - 2) && (!(d2 == 3 && overl))) { /* if year don't starts in thursday */ if ((d2 < 4 && J2DAY(day) != 5 && !isSaturday) ||(d2 == 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 (VARSIZE_ANY_EXHDR(date_txt) == 0) PG_RETURN_NULL(); /* * Du to an Oracle bug, when we have a format we emit an error * if the date is before 1582-10-04 with the J format or before * 1100-03-01 for the other formats. */ if (PG_NARGS() == 2) { text *fmt_txt = PG_GETARG_TEXT_PP(1); Datum newDate; /* * With Oracle passing en empty string to to_date(txt, fmt) returns * NULL, PostgreSQL returns 0001-01-01 BC whatever is the format. */ if (strlen(text_to_cstring(date_txt)) == 0) PG_RETURN_NULL(); /* it will return timestamp at GMT */ newDate = DirectFunctionCall2(to_timestamp, PointerGetDatum(date_txt), PointerGetDatum(fmt_txt)); /* convert to local timestamp */ result = DatumGetTimestamp(DirectFunctionCall1(timestamptz_timestamp, newDate)); if (orafce_emit_error_on_date_bug) { if (pg_strcasecmp(text_to_cstring(fmt_txt), "J") == 0) { if (atoi(text_to_cstring(date_txt)) <= 2299160) elog(ERROR, "Dates before 1582-10-05 ('J2299159') cannot be verified due to a bug in Oracle."); } else { text *buglimit_txt = cstring_to_text("1100-03-01 00:00:00"); text *buglimit_fmt = cstring_to_text("YYYY-MM-DD H24:MI:SS"); Datum bugDate; Timestamp bugResult; bugDate = DirectFunctionCall2(to_timestamp, PointerGetDatum(buglimit_txt), PointerGetDatum(buglimit_fmt)); bugResult = DatumGetTimestamp(DirectFunctionCall1(timestamptz_timestamp, bugDate)); if (result < bugResult) elog(ERROR, "Dates before 1100-03-01 cannot be verified due to a bug in Oracle."); } } PG_RETURN_TIMESTAMP(result); } if(nls_date_format && strlen(nls_date_format)) { Datum newDate; /* it will return timestamp at GMT */ newDate = DirectFunctionCall2(to_timestamp, PointerGetDatum(date_txt), CStringGetTextDatum(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 } #define TRUNC_DAY tm->tm_hour = 0; tm->tm_min = 0; *redotz = true; /* * 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); TRUNC_DAY; break; CASE_fmt_YYYY tm->tm_mon = 1; tm->tm_mday = 1; TRUNC_DAY; break; CASE_fmt_Q tm->tm_mon = (3*((tm->tm_mon - 1)/3)) + 1; tm->tm_mday = 1; TRUNC_DAY; break; CASE_fmt_MON tm->tm_mday = 1; TRUNC_DAY; break; CASE_fmt_DDD TRUNC_DAY; break; CASE_fmt_HH tm->tm_min = 0; break; } } 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)); } /******************************************************************** * * oracle.sys_extract_utc(timestamp with time zone * * Returns timestamp at utc time zone * ********************************************************************/ Datum orafce_sys_extract_utc(PG_FUNCTION_ARGS) { PG_RETURN_DATUM(DirectFunctionCall2(timestamptz_zone, CStringGetTextDatum("utc"), PG_GETARG_DATUM(0))); } /******************************************************************** * * oracle.sys_extract_utc(oracle.date) * * Returns timestamp at utc time zone, session time zone is used * as default time zone. * ********************************************************************/ Datum orafce_sys_extract_utc_oracle_date(PG_FUNCTION_ARGS) { TimestampTz loc_ts; #if PG_VERSION_NUM >= 130000 loc_ts = timestamp2timestamptz_opt_overflow(PG_GETARG_TIMESTAMP(0), NULL); #else loc_ts = DatumGetTimestampTz(DirectFunctionCall1(timestamp_timestamptz, PG_GETARG_TIMESTAMP(0))); #endif PG_RETURN_DATUM(DirectFunctionCall2(timestamptz_zone, CStringGetTextDatum("utc"), TimestampTzGetDatum(loc_ts))); } orafce-VERSION_4_14_4/dbms_sql.c000066400000000000000000001430041501757153000163700ustar00rootroot00000000000000#include "postgres.h" #include "fmgr.h" #include "funcapi.h" #if PG_VERSION_NUM < 120000 #include "access/htup_details.h" #endif #include "access/tupconvert.h" #include "catalog/pg_type_d.h" #include "catalog/pg_type.h" #include "executor/spi.h" #include "lib/stringinfo.h" #include "parser/parse_coerce.h" #include "parser/scansup.h" #include "utils/array.h" #include "utils/builtins.h" #include "utils/datum.h" #include "utils/elog.h" #include "utils/lsyscache.h" #include "utils/syscache.h" #include "utils/memutils.h" #include "utils/typcache.h" #include "executor/spi_priv.h" #include "orafce.h" #include "builtins.h" #define MAX_CURSORS 100 /* * bind variable data */ typedef struct { char *refname; int position; Datum value; Oid typoid; bool typbyval; int16 typlen; bool isnull; unsigned int varno; /* number of assigned placeholder of parsed query */ bool is_array; /* true, when a value is assigned via bind_array */ Oid typelemid; /* Oid of element of a array */ bool typelembyval; int16 typelemlen; int index1; int index2; } VariableData; /* * Query result column definition */ typedef struct { int position; Oid typoid; bool typbyval; int16 typlen; int32 typmod; bool typisstr; Oid typarrayoid; /* oid of requested array output value */ uint64 rowcount; /* maximal rows of requested array */ int index1; /* output array should be rewrited from this index */ } ColumnData; /* * It is used for transformation result data to form * generated by column_value procedure or column * value function. */ typedef struct { bool isvalid; /* true, when this cast can be used */ bool without_cast; /* true, when cast is not necessary */ Oid targettypid; /* used for domains */ Oid array_targettypid; /* used for array domains */ int32 targettypmod; /* used for strings */ bool typbyval; /* used for copy result to outer memory context */ int16 typlen; /* used for copy result to outer memory context */ bool is_array; Oid funcoid; Oid funcoid_typmod; CoercionPathType path; CoercionPathType path_typmod; FmgrInfo finfo; FmgrInfo finfo_typmod; FmgrInfo finfo_out; FmgrInfo finfo_in; Oid typIOParam; } CastCacheData; /* * dbms_sql cursor definition */ typedef struct { int16 cid; char *parsed_query; char *original_query; unsigned int nvariables; int max_colpos; List *variables; List *columns; char cursorname[32]; Portal portal; /* one shot (execute) plan */ SPIPlanPtr plan; MemoryContext cursor_cxt; MemoryContext cursor_xact_cxt; MemoryContext tuples_cxt; MemoryContext result_cxt; /* short life memory context */ HeapTuple tuples[1000]; TupleDesc coltupdesc; TupleDesc tupdesc; CastCacheData *casts; uint64 processed; uint64 nread; uint64 start_read; bool assigned; bool executed; Bitmapset *array_columns; /* set of array columns */ uint64 batch_rows; /* how much rows should be fetched to fill target arrays */ } CursorData; typedef enum { TOKEN_SPACES, TOKEN_COMMENT, TOKEN_NUMBER, TOKEN_BIND_VAR, TOKEN_STR, TOKEN_EXT_STR, TOKEN_DOLAR_STR, TOKEN_IDENTIF, TOKEN_QIDENTIF, TOKEN_DOUBLE_COLON, TOKEN_OTHER, TOKEN_NONE } orafceTokenType; static char *next_token(char *str, char **start, size_t *len, orafceTokenType *typ, char **sep, size_t *seplen); PG_FUNCTION_INFO_V1(dbms_sql_is_open); PG_FUNCTION_INFO_V1(dbms_sql_open_cursor); PG_FUNCTION_INFO_V1(dbms_sql_close_cursor); PG_FUNCTION_INFO_V1(dbms_sql_parse); PG_FUNCTION_INFO_V1(dbms_sql_bind_variable); PG_FUNCTION_INFO_V1(dbms_sql_bind_variable_f); PG_FUNCTION_INFO_V1(dbms_sql_bind_array_3); PG_FUNCTION_INFO_V1(dbms_sql_bind_array_5); PG_FUNCTION_INFO_V1(dbms_sql_define_column); PG_FUNCTION_INFO_V1(dbms_sql_define_array); PG_FUNCTION_INFO_V1(dbms_sql_execute); PG_FUNCTION_INFO_V1(dbms_sql_fetch_rows); PG_FUNCTION_INFO_V1(dbms_sql_execute_and_fetch); PG_FUNCTION_INFO_V1(dbms_sql_column_value); PG_FUNCTION_INFO_V1(dbms_sql_column_value_f); PG_FUNCTION_INFO_V1(dbms_sql_last_row_count); PG_FUNCTION_INFO_V1(dbms_sql_describe_columns); PG_FUNCTION_INFO_V1(dbms_sql_describe_columns_f); PG_FUNCTION_INFO_V1(dbms_sql_debug_cursor); static uint64 last_row_count = 0; static MemoryContext persist_cxt = NULL; static CursorData cursors[MAX_CURSORS]; static void open_cursor(CursorData *c, int cid) { c->cid = cid; if (!persist_cxt) { persist_cxt = AllocSetContextCreate(NULL, "dbms_sql persist context", ALLOCSET_DEFAULT_SIZES); memset(cursors, 0, sizeof(cursors)); } c->cursor_cxt = AllocSetContextCreate(persist_cxt, "dbms_sql cursor context", ALLOCSET_DEFAULT_SIZES); c->assigned = true; } /* * FUNCTION dbms_sql.open_cursor() RETURNS int */ Datum dbms_sql_open_cursor(PG_FUNCTION_ARGS) { int i; (void) fcinfo; /* find and initialize first free slot */ for (i = 0; i < MAX_CURSORS; i++) { if (!cursors[i].assigned) { open_cursor(&cursors[i], i); PG_RETURN_INT32(i); } } ereport(ERROR, (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("too many opened cursors"), errdetail("There is not free slot for new dbms_sql's cursor."), errhint("You should to close unused cursors"))); /* be msvc quiet */ return (Datum) 0; } static CursorData * get_cursor(FunctionCallInfo fcinfo, bool should_be_assigned) { CursorData *cursor; int cid; if (PG_ARGISNULL(0)) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("cursor id is NULL"))); cid = PG_GETARG_INT32(0); if (cid < 0 || cid >= MAX_CURSORS) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("value of cursor id is out of range"))); cursor = &cursors[cid]; if (!cursor->assigned && should_be_assigned) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_CURSOR), errmsg("cursor is not valid"))); return cursor; } /* * CREATE FUNCTION dbms_sql.is_open(c int) RETURNS bool; */ Datum dbms_sql_is_open(PG_FUNCTION_ARGS) { CursorData *c; c = get_cursor(fcinfo, false); PG_RETURN_BOOL(c->assigned); } /* * Release all sources assigned to cursor */ static void close_cursor(CursorData *c) { if (c->executed && c->portal) SPI_cursor_close(c->portal); /* release all assigned memory */ if (c->cursor_cxt) MemoryContextDelete(c->cursor_cxt); if (c->cursor_xact_cxt) MemoryContextDelete(c->cursor_xact_cxt); if (c->plan) SPI_freeplan(c->plan); memset(c, 0, sizeof(CursorData)); } /* * PROCEDURE dbms_sql.close_cursor(c int) */ Datum dbms_sql_close_cursor(PG_FUNCTION_ARGS) { CursorData *c; c = get_cursor(fcinfo, false); close_cursor(c); return (Datum) 0; } /* * Print state of cursor - just for debug purposes */ Datum dbms_sql_debug_cursor(PG_FUNCTION_ARGS) { CursorData *c; ListCell *lc; c = get_cursor(fcinfo, false); if (c->assigned) { if (c->original_query) elog(NOTICE, "orig query: \"%s\"", c->original_query); if (c->parsed_query) elog(NOTICE, "parsed query: \"%s\"", c->parsed_query); } else elog(NOTICE, "cursor is not assigned"); foreach(lc, c->variables) { VariableData *var = (VariableData *) lfirst(lc); if (var->typoid != InvalidOid) { if (!var->isnull) { Oid typOutput; bool isVarlena; char *str; getTypeOutputInfo(var->typoid, &typOutput, &isVarlena); str = OidOutputFunctionCall(typOutput, var->value); elog(NOTICE, "variable \"%s\" is assigned to \"%s\"", var->refname, str); } else elog(NOTICE, "variable \"%s\" is NULL", var->refname); } else elog(NOTICE, "variable \"%s\" is not assigned", var->refname); } foreach(lc, c->columns) { ColumnData *col = (ColumnData *) lfirst(lc); elog(NOTICE, "column definition for position %d is %s", col->position, format_type_with_typemod(col->typoid, col->typmod)); } return (Datum) 0; } /* * Search a variable in cursor's variable list */ static VariableData * get_var(CursorData *c, char *refname, int position, bool append) { ListCell *lc; foreach(lc, c->variables) { VariableData *var = (VariableData *) lfirst(lc); if (strcmp(var->refname, refname) == 0) return var; } if (append) { VariableData *nvar; MemoryContext oldcxt; oldcxt = MemoryContextSwitchTo(c->cursor_cxt); nvar = palloc0(sizeof(VariableData)); nvar->refname = pstrdup(refname); nvar->varno = c->nvariables + 1; nvar->position = position; c->variables = lappend(c->variables, nvar); c->nvariables += 1; MemoryContextSwitchTo(oldcxt); return nvar; } else ereport(ERROR, (errcode(ERRCODE_UNDEFINED_PARAMETER), errmsg("variable \"%s\" doesn't exists", refname))); /* be msvc quite */ return NULL; } /* * PROCEDURE dbms_sql.parse(c int, stmt varchar) */ Datum dbms_sql_parse(PG_FUNCTION_ARGS) { char *query, *ptr; char *start; size_t len; orafceTokenType typ; StringInfoData sinfo; CursorData *c; MemoryContext oldcxt; c = get_cursor(fcinfo, true); if (PG_ARGISNULL(1)) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("parsed query string is NULL"))); if (c->parsed_query) { int cid = c->cid; close_cursor(c); open_cursor(c, cid); } query = text_to_cstring(PG_GETARG_TEXT_P(1)); ptr = query; initStringInfo(&sinfo); while (ptr) { char *startsep; char *next_ptr; size_t seplen; next_ptr = next_token(ptr, &start, &len, &typ, &startsep, &seplen); if (next_ptr) { if (typ == TOKEN_DOLAR_STR) { appendStringInfo(&sinfo, "%.*s", (int) seplen, startsep); appendStringInfo(&sinfo, "%.*s", (int) len, start); appendStringInfo(&sinfo, "%.*s", (int) seplen, startsep); } else if (typ == TOKEN_BIND_VAR) { char *name = downcase_identifier(start, (int) len, false, true); VariableData *var = get_var(c, name, (int) (ptr - query), true); appendStringInfo(&sinfo, "$%d", var->varno); pfree(name); } else if (typ == TOKEN_EXT_STR) { appendStringInfo(&sinfo, "e\'%.*s\'", (int) len, start); } else if (typ == TOKEN_STR) { appendStringInfo(&sinfo, "\'%.*s\'", (int) len, start); } else if (typ == TOKEN_QIDENTIF) { appendStringInfo(&sinfo, "\"%.*s\"", (int) len, start); } else if (typ != TOKEN_NONE) { appendStringInfo(&sinfo, "%.*s", (int) len, start); } } ptr = next_ptr; } /* save result to persist context */ oldcxt = MemoryContextSwitchTo(c->cursor_cxt); c->original_query = pstrdup(query); c->parsed_query = pstrdup(sinfo.data); MemoryContextSwitchTo(oldcxt); pfree(query); pfree(sinfo.data); return (Datum) 0; } /* * Calling procedure can be slow, so there is a function alternative */ static Datum bind_variable(PG_FUNCTION_ARGS) { CursorData *c; VariableData *var; char *varname, *varname_downcase; Oid valtype; bool is_unknown = false; c = get_cursor(fcinfo, true); if (PG_ARGISNULL(1)) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("name of bind variable is NULL"))); varname = text_to_cstring(PG_GETARG_TEXT_P(1)); if (*varname == ':') varname += 1; varname_downcase = downcase_identifier(varname, (int) strlen(varname), false, true); var = get_var(c, varname_downcase, -1, false); valtype = get_fn_expr_argtype(fcinfo->flinfo, 2); if (valtype == RECORDOID) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot to bind a value of record type"))); valtype = getBaseType(valtype); if (valtype == UNKNOWNOID) { is_unknown = true; valtype = TEXTOID; } if (var->typoid != InvalidOid) { if (!var->typbyval && !var->isnull) { pfree(DatumGetPointer(var->value)); var->value = (Datum) 0; } var->isnull = true; } var->typoid = valtype; if (!PG_ARGISNULL(2)) { MemoryContext oldcxt; get_typlenbyval(var->typoid, &var->typlen, &var->typbyval); oldcxt = MemoryContextSwitchTo(c->cursor_cxt); if (is_unknown) var->value = CStringGetTextDatum(DatumGetPointer(PG_GETARG_DATUM(2))); else var->value = datumCopy(PG_GETARG_DATUM(2), var->typbyval, var->typlen); var->isnull = false; MemoryContextSwitchTo(oldcxt); } else var->isnull = true; return (Datum) 0; } /* * CREATE PROCEDURE dbms_sql.bind_variable(c int, name varchar2, value "any"); */ Datum dbms_sql_bind_variable(PG_FUNCTION_ARGS) { return bind_variable(fcinfo); } /* * CREATE FUNCTION dbms_sql.bind_variable_f(c int, name varchar2, value "any") RETURNS void; */ Datum dbms_sql_bind_variable_f(PG_FUNCTION_ARGS) { return bind_variable(fcinfo); } static void bind_array(FunctionCallInfo fcinfo, int index1, int index2) { CursorData *c; VariableData *var; char *varname, *varname_downcase; Oid valtype; Oid elementtype; c = get_cursor(fcinfo, true); if (PG_ARGISNULL(1)) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("name of bind variable is NULL"))); varname = text_to_cstring(PG_GETARG_TEXT_P(1)); if (*varname == ':') varname += 1; varname_downcase = downcase_identifier(varname, (int) strlen(varname), false, true); var = get_var(c, varname_downcase, -1, false); valtype = get_fn_expr_argtype(fcinfo->flinfo, 2); if (valtype == RECORDOID) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot to bind a value of record type"))); valtype = getBaseType(valtype); elementtype = get_element_type(valtype); if (!OidIsValid(elementtype)) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("value is not a array"))); if (var->typoid != InvalidOid) { if (!var->typbyval && !var->isnull) { pfree(DatumGetPointer(var->value)); var->value = (Datum) 0; } var->isnull = true; } var->is_array = true; var->typoid = valtype; var->typelemid = elementtype; get_typlenbyval(elementtype, &var->typelemlen, &var->typelembyval); if (!PG_ARGISNULL(2)) { MemoryContext oldcxt; get_typlenbyval(var->typoid, &var->typlen, &var->typbyval); oldcxt = MemoryContextSwitchTo(c->cursor_cxt); var->value = datumCopy(PG_GETARG_DATUM(2), var->typbyval, var->typlen); var->isnull = false; MemoryContextSwitchTo(oldcxt); } else var->isnull = true; var->index1 = index1; var->index2 = index2; } /* * CREATE PROCEDURE dbms_sql.bind_array(c int, name varchar2, value anyarray); */ Datum dbms_sql_bind_array_3(PG_FUNCTION_ARGS) { bind_array(fcinfo, -1, -1); return (Datum) 0; } /* * CREATE PROCEDURE dbms_sql.bind_array(c int, name varchar2, value anyarray, index1 int, index2 int); */ Datum dbms_sql_bind_array_5(PG_FUNCTION_ARGS) { int index1, index2; if (PG_ARGISNULL(3) || PG_ARGISNULL(4)) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("index is NULL"))); index1 = PG_GETARG_INT32(3); index2 = PG_GETARG_INT32(4); if (index1 < 0 || index2 < 0) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("index is below zero"))); if (index1 > index2) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("index1 is greater than index2"))); bind_array(fcinfo, index1, index2); return (Datum) 0; } static ColumnData * get_col(CursorData *c, int position, bool append) { ListCell *lc; foreach(lc, c->columns) { ColumnData *col = (ColumnData *) lfirst(lc); if (col->position == position) return col; } if (append) { ColumnData *ncol; MemoryContext oldcxt; oldcxt = MemoryContextSwitchTo(c->cursor_cxt); ncol = palloc0(sizeof(ColumnData)); ncol->position = position; if (c->max_colpos < position) c->max_colpos = position; c->columns = lappend(c->columns, ncol); MemoryContextSwitchTo(oldcxt); return ncol; } else ereport(ERROR, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("column no %d is not defined", position))); /* be msvc quite */ return NULL; } /* * CREATE PROCEDURE dbms_sql.define_column(c int, col int, value "any", column_size int DEFAULT -1); */ Datum dbms_sql_define_column(PG_FUNCTION_ARGS) { CursorData *c; ColumnData *col; Oid valtype; Oid basetype; int position; int colsize; TYPCATEGORY category; bool ispreferred; c = get_cursor(fcinfo, true); if (PG_ARGISNULL(1)) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("column position (number) is NULL"))); position = PG_GETARG_INT32(1); col = get_col(c, position, true); valtype = get_fn_expr_argtype(fcinfo->flinfo, 2); if (valtype == RECORDOID) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot to define a column of record type"))); if (valtype == UNKNOWNOID) valtype = TEXTOID; basetype = getBaseType(valtype); if (col->typoid != InvalidOid) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_COLUMN), errmsg("column is defined already"))); col->typoid = valtype; if (PG_ARGISNULL(3)) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("column_size is NULL"))); colsize = PG_GETARG_INT32(3); get_type_category_preferred(basetype, &category, &ispreferred); col->typisstr = category == TYPCATEGORY_STRING; col->typmod = (col->typisstr && colsize != -1) ? colsize + 4 : -1; get_typlenbyval(basetype, &col->typlen, &col->typbyval); col->rowcount = 1; return (Datum) 0; } /* * CREATE PROCEDURE dbms_sql.define_array(c int, col int, value "anyarray", rowcount int, index1 int); */ Datum dbms_sql_define_array(PG_FUNCTION_ARGS) { CursorData *c; ColumnData *col; Oid valtype; Oid basetype; int position; int rowcount; int index1; Oid elementtype; TYPCATEGORY category; bool ispreferred; c = get_cursor(fcinfo, true); if (PG_ARGISNULL(1)) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("column position (number) is NULL"))); position = PG_GETARG_INT32(1); col = get_col(c, position, true); valtype = get_fn_expr_argtype(fcinfo->flinfo, 2); if (valtype == RECORDOID) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot to define a column of record type"))); get_type_category_preferred(valtype, &category, &ispreferred); if (category != TYPCATEGORY_ARRAY) elog(ERROR, "defined value is not array"); col->typarrayoid = valtype; basetype = getBaseType(valtype); elementtype = get_element_type(basetype); if (!OidIsValid(elementtype)) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("column is not a array"))); if (col->typoid != InvalidOid) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_COLUMN), errmsg("column is defined already"))); col->typoid = elementtype; if (PG_ARGISNULL(3)) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("cnt is NULL"))); rowcount = PG_GETARG_INT32(3); if (rowcount <= 0) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("cnt is less or equal to zero"))); col->rowcount = (uint64) rowcount; if (PG_ARGISNULL(4)) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("lower_bnd is NULL"))); index1 = PG_GETARG_INT32(4); if (index1 < 1) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("lower_bnd is less than one"))); if (index1 != 1) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("lower_bnd can be only only \"1\""))); col->index1 = index1; get_typlenbyval(col->typoid, &col->typlen, &col->typbyval); return (Datum) 0; } static void cursor_xact_cxt_deletion_callback(void *arg) { CursorData *cur = (CursorData *) arg; cur->cursor_xact_cxt = NULL; cur->result_cxt = NULL; cur->tuples_cxt = NULL; cur->processed = 0; cur->nread = 0; cur->executed = false; cur->tupdesc = NULL; cur->coltupdesc = NULL; cur->casts = NULL; cur->array_columns = NULL; } static uint64 execute(CursorData *c) { last_row_count = 0; /* clean space with saved result */ if (!c->cursor_xact_cxt) { MemoryContextCallback *mcb; MemoryContext oldcxt; c->cursor_xact_cxt = AllocSetContextCreate(TopTransactionContext, "dbms_sql transaction context", ALLOCSET_DEFAULT_SIZES); oldcxt = MemoryContextSwitchTo(c->cursor_xact_cxt); mcb = palloc0(sizeof(MemoryContextCallback)); mcb->func = cursor_xact_cxt_deletion_callback; mcb->arg = c; MemoryContextRegisterResetCallback(c->cursor_xact_cxt, mcb); MemoryContextSwitchTo(oldcxt); } else { MemoryContext save_cxt = c->cursor_xact_cxt; MemoryContextReset(c->cursor_xact_cxt); c->cursor_xact_cxt = save_cxt; c->casts = NULL; c->tupdesc = NULL; c->tuples_cxt = NULL; } c->result_cxt = AllocSetContextCreate(c->cursor_xact_cxt, "dbms_sql short life context", ALLOCSET_DEFAULT_SIZES); /* * When column definitions are available, build final query * and open cursor for fetching. When column definitions are * missing, then the statement can be called with high frequency * etc INSERT, UPDATE, so use cached plan. */ if (c->columns) { Datum *values; Oid *types; char *nulls; ListCell *lc; int i; MemoryContext oldcxt; uint64 batch_rows = 0; oldcxt = MemoryContextSwitchTo(c->cursor_xact_cxt); /* prepare query arguments */ values = palloc(sizeof(Datum) * c->nvariables); types = palloc(sizeof(Oid) * c->nvariables); nulls = palloc(sizeof(char) * c->nvariables); i = 0; foreach(lc, c->variables) { VariableData *var = (VariableData *) lfirst(lc); if (var->is_array) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("a array (bulk) variable can be used only when no column is defined"))); if (!var->isnull) { /* copy a value to xact memory context, to be independent on a outside */ values[i] = datumCopy(var->value, var->typbyval, var->typlen); nulls[i] = ' '; } else nulls[i] = 'n'; if (var->typoid == InvalidOid) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_PARAMETER), errmsg("variable \"%s\" has not a value", var->refname))); types[i] = var->typoid; i += 1; } /* prepare or refresh target tuple descriptor, used for final tupconversion */ if (c->tupdesc) FreeTupleDesc(c->tupdesc); #if PG_VERSION_NUM >= 120000 c->coltupdesc = CreateTemplateTupleDesc(c->max_colpos); #else c->coltupdesc = CreateTemplateTupleDesc(c->max_colpos, false); #endif /* prepare current result column tupdesc */ for (i = 1; i <= c->max_colpos; i++) { ColumnData *col = get_col(c, i, false); char genname[32]; snprintf(genname, 32, "col%d", i); Assert(col->rowcount > 0); if (col->typarrayoid) { if (batch_rows != 0) batch_rows = col->rowcount < batch_rows ? col->rowcount : batch_rows; else batch_rows = col->rowcount; c->array_columns = bms_add_member(c->array_columns, i); } else { /* in this case we cannot do batch of rows */ batch_rows = 1; } TupleDescInitEntry(c->coltupdesc, (AttrNumber) i, genname, col->typoid, col->typmod, 0); } c->batch_rows = batch_rows; Assert(c->coltupdesc->natts >= 0); c->casts = palloc0(sizeof(CastCacheData) * ((unsigned int) c->coltupdesc->natts)); MemoryContextSwitchTo(oldcxt); snprintf(c->cursorname, sizeof(c->cursorname), "__orafce_dbms_sql_cursor_%d", c->cid); if (SPI_connect() != SPI_OK_CONNECT) elog(ERROR, "SPI_connact failed"); c->portal = SPI_cursor_open_with_args(c->cursorname, c->parsed_query, (int) c->nvariables, types, values, nulls, false, 0); /* internal error */ if (c->portal == NULL) elog(ERROR, "could not open cursor for query \"%s\": %s", c->parsed_query, SPI_result_code_string(SPI_result)); SPI_finish(); /* Describe portal and prepare cast cache */ if (c->portal->tupDesc) { int natts = 0; TupleDesc tupdesc = c->portal->tupDesc; for (i = 0; i < tupdesc->natts; i++) { Form_pg_attribute att = TupleDescAttr(tupdesc, i); if (att->attisdropped) continue; natts += 1; } if (natts != c->coltupdesc->natts) ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION), errmsg("number of defined columns is different than number of query's columns"))); } c->executed = true; } else { MemoryContext oldcxt; Datum *values; char *nulls; ArrayIterator *iterators; bool has_iterator = false; bool has_value = true; int max_index1 = -1; int min_index2 = -1; uint64 result = 0; ListCell *lc; int i; if (SPI_connect() != SPI_OK_CONNECT) elog(ERROR, "SPI_connact failed"); /* prepare, or reuse cached plan */ if (!c->plan) { Oid *types = NULL; SPIPlanPtr plan; types = palloc(sizeof(Oid) * c->nvariables); i = 0; foreach(lc, c->variables) { VariableData *var = (VariableData *) lfirst(lc); if (var->typoid == InvalidOid) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_PARAMETER), errmsg("variable \"%s\" has not a value", var->refname))); types[i++] = var->is_array ? var->typelemid : var->typoid; } plan = SPI_prepare(c->parsed_query, (int) c->nvariables, types); if (!plan) /* internal error */ elog(ERROR, "cannot to prepare plan"); if (types) pfree(types); SPI_keepplan(plan); c->plan = plan; } oldcxt = MemoryContextSwitchTo(c->result_cxt); /* prepare query arguments */ values = palloc(sizeof(Datum) * c->nvariables); nulls = palloc(sizeof(char) * c->nvariables); iterators = palloc(sizeof(ArrayIterator *) * c->nvariables); has_value = true; i = 0; foreach(lc, c->variables) { VariableData *var = (VariableData *) lfirst(lc); if (var->is_array) { if (!var->isnull) { iterators[i] = array_create_iterator(DatumGetArrayTypeP(var->value), 0, NULL); /* search do lowest common denominator */ if (var->index1 != -1) { if (max_index1 != -1) { max_index1 = max_index1 < var->index1 ? var->index1 : max_index1; min_index2 = min_index2 > var->index2 ? var->index2 : min_index2; } else { max_index1 = var->index1; min_index2 = var->index2; } } has_iterator = true; } else { /* cannot to read data from NULL array */ has_value = false; break; } } else { values[i] = var->value; nulls[i] = var->isnull ? 'n' : ' '; } i += 1; } if (has_iterator) { int max_rows = -1; if (has_value) { if (max_index1 != -1) { max_rows = min_index2 - max_index1 + 1; has_value = max_rows > 0; if (has_value && max_index1 > 1) { i = 0; foreach(lc, c->variables) { VariableData *var = (VariableData *) lfirst(lc); if (var->is_array) { int j; Assert(iterators[i]); for (j = 1; j < max_index1; j++) { Datum value; bool isnull; has_value = array_iterate(iterators[i], &value, &isnull); if (!has_value) break; } if (!has_value) break; } i += 1; } } } } while (has_value && (max_rows == -1 || max_rows > 0)) { int rc; i = 0; foreach(lc, c->variables) { VariableData *var = (VariableData *) lfirst(lc); if (var->is_array) { Datum value; bool isnull; has_value = array_iterate(iterators[i], &value, &isnull); if (!has_value) break; values[i] = value; nulls[i] = isnull ? 'n' : ' '; } i += 1; } if (!has_value) break; rc = SPI_execute_plan(c->plan, values, nulls, false, 0); if (rc < 0) /* internal error */ elog(ERROR, "cannot to execute a query"); result += SPI_processed; if (max_rows > 0) max_rows -= 1; } MemoryContextReset(c->result_cxt); } else if (has_value) { int rc; rc = SPI_execute_plan(c->plan, values, nulls, false, 0); if (rc < 0) /* internal error */ elog(ERROR, "cannot to execute a query"); result = SPI_processed; } SPI_finish(); MemoryContextSwitchTo(oldcxt); return result; } return 0L; } /* * CREATE FUNCTION dbms_sql.execute(c int) RETURNS bigint; */ Datum dbms_sql_execute(PG_FUNCTION_ARGS) { CursorData *c; c = get_cursor(fcinfo, true); PG_RETURN_INT64((int64) execute(c)); } static uint64 fetch_rows(CursorData *c, bool exact) { uint64 can_read_rows; if (!c->executed) ereport(ERROR, (errcode(ERRCODE_INVALID_CURSOR_STATE), errmsg("cursor is not executed"))); if (!c->portal) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("cursor has not portal"))); if (c->nread == c->processed) { MemoryContext oldcxt; uint64 i; int batch_rows; if (!exact) { if (c->array_columns) batch_rows = (1000 / c->batch_rows) * c->batch_rows; else batch_rows = 1000; } else batch_rows = 2; /* create or reset context for tuples */ if (!c->tuples_cxt) c->tuples_cxt = AllocSetContextCreate(c->cursor_xact_cxt, "dbms_sql tuples context", ALLOCSET_DEFAULT_SIZES); else MemoryContextReset(c->tuples_cxt); if (SPI_connect() != SPI_OK_CONNECT) elog(ERROR, "SPI_connact failed"); /* try to fetch data from cursor */ SPI_cursor_fetch(c->portal, true, batch_rows); if (SPI_tuptable == NULL) elog(ERROR, "cannot fetch data"); if (exact && SPI_processed > 1) ereport(ERROR, (errcode(ERRCODE_TOO_MANY_ROWS), errmsg("too many rows"), errdetail("In exact mode only one row is expected"))); if (exact && SPI_processed == 0) ereport(ERROR, (errcode(ERRCODE_NO_DATA_FOUND), errmsg("no data found"), errdetail("In exact mode only one row is expected"))); oldcxt = MemoryContextSwitchTo(c->tuples_cxt); c->tupdesc = CreateTupleDescCopy(SPI_tuptable->tupdesc); for (i = 0; i < SPI_processed; i++) c->tuples[i] = heap_copytuple(SPI_tuptable->vals[i]); MemoryContextSwitchTo(oldcxt); c->processed = SPI_processed; c->nread = 0; SPI_finish(); } if (c->processed - c->nread >= c->batch_rows) can_read_rows = c->batch_rows; else can_read_rows = c->processed - c->nread; c->start_read = c->nread; c->nread += can_read_rows; last_row_count = can_read_rows; return can_read_rows; } /* * CREATE FUNCTION dbms_sql.fetch_rows(c int) RETURNS int; */ Datum dbms_sql_fetch_rows(PG_FUNCTION_ARGS) { CursorData *c; c = get_cursor(fcinfo, true); PG_RETURN_INT32(fetch_rows(c, false)); } /* * CREATE FUNCTION dbms_sql.execute_and_fetch(c int, exact bool DEFAULT false) RETURNS int; */ Datum dbms_sql_execute_and_fetch(PG_FUNCTION_ARGS) { CursorData *c; bool exact; c = get_cursor(fcinfo, true); if (PG_ARGISNULL(1)) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("exact option is NULL"))); exact = PG_GETARG_BOOL(1); execute(c); PG_RETURN_INT32(fetch_rows(c, exact)); } /* * CREATE FUNCTION dbms_sql.last_row_count() RETURNS int; */ Datum dbms_sql_last_row_count(PG_FUNCTION_ARGS) { (void) fcinfo; PG_RETURN_INT32(last_row_count); } /* * Initialize cast case entry. */ static void init_cast_cache_entry(CastCacheData *ccast, Oid targettypid, int32 targettypmod, Oid sourcetypid) { Oid funcoid; Oid basetypid; basetypid = getBaseType(targettypid); if (targettypid != basetypid) ccast->targettypid = targettypid; else ccast->targettypid = InvalidOid; ccast->targettypmod = targettypmod; if (sourcetypid == targettypid) ccast->without_cast = targettypmod == -1; else ccast->without_cast = false; if (!ccast->without_cast) { ccast->path = find_coercion_pathway(basetypid, sourcetypid, COERCION_ASSIGNMENT, &funcoid); if (ccast->path == COERCION_PATH_NONE) ereport(ERROR, (errcode(ERRCODE_CANNOT_COERCE), errmsg("cannot to find cast from source type \"%s\" to target type \"%s\"", format_type_be(sourcetypid), format_type_be(basetypid)))); if (ccast->path == COERCION_PATH_FUNC) { fmgr_info(funcoid, &ccast->finfo); } else if (ccast->path == COERCION_PATH_COERCEVIAIO) { bool typisvarlena; getTypeOutputInfo(sourcetypid, &funcoid, &typisvarlena); fmgr_info(funcoid, &ccast->finfo_out); getTypeInputInfo(targettypid, &funcoid, &ccast->typIOParam); fmgr_info(funcoid, &ccast->finfo_in); } if (targettypmod != -1) { ccast->path_typmod = find_typmod_coercion_function(targettypid, &funcoid); if (ccast->path_typmod == COERCION_PATH_FUNC) fmgr_info(funcoid, &ccast->finfo_typmod); } } ccast->isvalid = true; } /* * Apply cast rules to a value */ static Datum cast_value(CastCacheData *ccast, Datum value, bool isnull) { if (!isnull && !ccast->without_cast) { if (ccast->path == COERCION_PATH_FUNC) value = FunctionCall1(&ccast->finfo, value); else if (ccast->path == COERCION_PATH_RELABELTYPE) { /* do nothing */ } else if (ccast->path == COERCION_PATH_COERCEVIAIO) { char *str; str = OutputFunctionCall(&ccast->finfo_out, value); value = InputFunctionCall(&ccast->finfo_in, str, ccast->typIOParam, ccast->targettypmod); } else ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("unsupported cast path yet %d", ccast->path))); if (ccast->targettypmod != -1 && ccast->path_typmod == COERCION_PATH_FUNC) value = FunctionCall3(&ccast->finfo_typmod, value, Int32GetDatum(ccast->targettypmod), BoolGetDatum(true)); } if (ccast->targettypid != InvalidOid) domain_check(value, isnull, ccast->targettypid, NULL, NULL); return value; } /* * CALL statement is relatily slow in PLpgSQL - due repated parsing, planning. * So I wrote two variant of this routine. When spi_transfer is true, then * the value is copyied to SPI outer memory context. */ static Datum column_value(CursorData *c, int pos, Oid targetTypeId, bool *isnull, bool spi_transfer) { Datum value; int32 columnTypeMode; Oid columnTypeId; CastCacheData *ccast; Assert(c->executed); if (last_row_count == 0) ereport(ERROR, (errcode(ERRCODE_NO_DATA_FOUND), errmsg("no data found"))); if (!c->tupdesc) ereport(ERROR, (errcode(ERRCODE_INVALID_CURSOR_STATE), errmsg("cursor is not fetched"))); if (!c->coltupdesc) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("no column is defined"))); if (pos < 1 && pos > c->coltupdesc->natts) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("column position is of of range [1, %d]", c->coltupdesc->natts))); columnTypeId = (TupleDescAttr(c->coltupdesc, pos - 1))->atttypid; columnTypeMode = (TupleDescAttr(c->coltupdesc, pos - 1))->atttypmod; Assert(c->casts); ccast = &c->casts[pos - 1]; if (!ccast->isvalid) { Oid basetype = getBaseType(targetTypeId); init_cast_cache_entry(ccast, columnTypeId, columnTypeMode, SPI_gettypeid(c->tupdesc, pos)); ccast->is_array = bms_is_member(pos, c->array_columns); if (ccast->is_array) { ccast->array_targettypid = basetype != targetTypeId ? targetTypeId : InvalidOid; if (get_array_type(getBaseType(columnTypeId)) != basetype) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("unexpected target type \"%s\" (expected type \"%s\")", format_type_be(basetype), format_type_be(get_array_type(getBaseType(columnTypeId)))))); } else ccast->array_targettypid = InvalidOid; get_typlenbyval(basetype, &ccast->typlen, &ccast->typbyval); } if (ccast->is_array) { ArrayBuildState *abs; uint64 idx; uint64 i; abs = initArrayResult(columnTypeId, CurrentMemoryContext, false); idx = c->start_read; for (i = 0; i < c->batch_rows; i++) { if (idx < c->processed) { value = SPI_getbinval(c->tuples[idx], c->tupdesc, pos, isnull); value = cast_value(ccast, value, *isnull); abs = accumArrayResult(abs, value, *isnull, columnTypeId, CurrentMemoryContext); idx += 1; } } value = makeArrayResult(abs, CurrentMemoryContext); if (ccast->array_targettypid != InvalidOid) domain_check(value, isnull, ccast->array_targettypid, NULL, NULL); } else { /* Maybe it can be solved by uncached slower cast */ if (targetTypeId != columnTypeId) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("unexpected target type \"%s\" (expected type \"%s\")", format_type_be(targetTypeId), format_type_be(columnTypeId)))); value = SPI_getbinval(c->tuples[c->start_read], c->tupdesc, pos, isnull); value = cast_value(ccast, value, *isnull); } if (*isnull) return (Datum) 0; if (spi_transfer) value = SPI_datumTransfer(value, ccast->typbyval, ccast->typlen); return value; } /* * CREATE PROCEDURE dbms_sql.column_value(c int, pos int, INOUT value "any"); * Note - CALL statement is slow from PLpgSQL block (against function execution). * This is reason why this routine is in function form too. */ Datum dbms_sql_column_value(PG_FUNCTION_ARGS) { CursorData *c; Datum value; Datum result; int pos; bool isnull; Oid targetTypeId; Oid resultTypeId; TupleDesc resulttupdesc; HeapTuple resulttuple; MemoryContext oldcxt; if (SPI_connect() != SPI_OK_CONNECT) elog(ERROR, "SPI_connact failed"); c = get_cursor(fcinfo, true); if (PG_ARGISNULL(1)) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("column position (number) is NULL"))); pos = PG_GETARG_INT32(1); if (!c->executed) ereport(ERROR, (errcode(ERRCODE_INVALID_CURSOR_STATE), errmsg("cursor is not executed"))); oldcxt = MemoryContextSwitchTo(c->result_cxt); /* * Setting of OUT field is little bit more complex, because although * there is only one output field, the result should be compisite type. */ if (get_call_result_type(fcinfo, &resultTypeId, &resulttupdesc) == TYPEFUNC_COMPOSITE) { /* check target types */ if (resulttupdesc->natts != 1) /* internal error, should not to be */ elog(ERROR, "unexpected number of result composite fields"); targetTypeId = get_fn_expr_argtype(fcinfo->flinfo, 2); Assert((TupleDescAttr(resulttupdesc, 0))->atttypid == targetTypeId); } else /* internal error, should not to be */ elog(ERROR, "unexpected function result type"); value = column_value(c, pos, targetTypeId, &isnull, false); resulttuple = heap_form_tuple(resulttupdesc, &value, &isnull); result = PointerGetDatum(SPI_returntuple(resulttuple, CreateTupleDescCopy(resulttupdesc))); SPI_finish(); MemoryContextSwitchTo(oldcxt); MemoryContextReset(c->result_cxt); PG_RETURN_DATUM(result); } /* * CREATE FUNCTION dbms_sql.column_value(c int, pos int, value anyelement) RETURNS anyelement; * Note - CALL statement is slow from PLpgSQL block (against function execution). * This is reason why this routine is in function form too. */ Datum dbms_sql_column_value_f(PG_FUNCTION_ARGS) { CursorData *c; Datum value; int pos; bool isnull; Oid targetTypeId; MemoryContext oldcxt; if (SPI_connect() != SPI_OK_CONNECT) elog(ERROR, "SPI_connact failed"); c = get_cursor(fcinfo, true); if (PG_ARGISNULL(1)) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("column position (number) is NULL"))); pos = PG_GETARG_INT32(1); if (!c->executed) ereport(ERROR, (errcode(ERRCODE_INVALID_CURSOR_STATE), errmsg("cursor is not executed"))); oldcxt = MemoryContextSwitchTo(c->result_cxt); targetTypeId = get_fn_expr_argtype(fcinfo->flinfo, 2); value = column_value(c, pos, targetTypeId, &isnull, true); SPI_finish(); MemoryContextSwitchTo(oldcxt); PG_RETURN_DATUM(value); } /****************************************************************** * Simple parser - just for replacement of bind variables by * PostgreSQL $ param placeholders. * ****************************************************************** */ /* * It doesn't work for multibyte encodings, but same implementation * is in Postgres too. */ static bool is_identif(unsigned char c) { if (c >= 'a' && c <= 'z') return true; else if (c >= 'A' && c <= 'Z') return true; else if (c >= 0200) return true; else return false; } /* * simple parser to detect :identif symbols in query */ static char * next_token(char *str, char **start, size_t *len, orafceTokenType *typ, char **sep, size_t *seplen) { if (*str == '\0') { *typ = TOKEN_NONE; return NULL; } /* reduce spaces */ if (*str == ' ') { *start = str++; while (*str == ' ') str++; *typ = TOKEN_SPACES; *len = 1; return str; } /* Postgres's dolar strings */ if (*str == '$' && (str[1] == '$' || is_identif((unsigned char) str[1]) || str[1] == '_')) { char *aux = str + 1; char *endstr; bool is_valid = false; char *buffer; /* try to find end of separator */ while (*aux) { if (*aux == '$') { is_valid = true; aux++; break; } else if (is_identif((unsigned char) *aux) || isdigit(*aux) || *aux == '_') { aux++; } else break; } if (!is_valid) { *typ = TOKEN_OTHER; *len = 1; *start = str; return str + 1; } /* now it looks like correct $ separator */ *start = aux; *sep = str; Assert(aux >= str); *seplen = (size_t) (aux - str); *typ = TOKEN_DOLAR_STR; /* try to find second instance */ buffer = palloc(*seplen + 1); memcpy(buffer, *sep, *seplen); buffer[*seplen] = '\0'; endstr = strstr(aux, buffer); if (endstr) { Assert(endstr >= *start); *len = (size_t) (endstr - *start); return endstr + *seplen; } else { while (*aux) aux++; Assert(aux >= *start); *len = (size_t) (aux - *start); return aux; } return aux; } /* Pair comments */ if (*str == '/' && str[1] == '*') { *start = str; str += 2; while (*str) { if (*str == '*' && str[1] == '/') { str += 2; break; } str++; } *typ = TOKEN_COMMENT; Assert(str >= *start); *len = (size_t) (str - *start); return str; } /* Number */ if (isdigit(*str) || (*str == '.' && isdigit(str[1]))) { bool point = *str == '.'; *start = str++; while (*str) { if (isdigit(*str)) str++; else if (*str == '.' && !point) { str++; point = true; } else break; } *typ = TOKEN_NUMBER; Assert(str >= *start); *len = (size_t) (str - *start); return str; } /* Double colon :: */ if (*str == ':' && str[1] == ':') { *start = str; *typ = TOKEN_DOUBLE_COLON; *len = 2; return str + 2; } /* Bind variable placeholder */ if (*str == ':' && (is_identif((unsigned char) str[1]) || str[1] == '_')) { *start = &str[1]; str += 2; while (*str) { if (is_identif((unsigned char) *str) || isdigit(*str) || *str == '_') str++; else break; } *typ = TOKEN_BIND_VAR; Assert(str >= *start); *len = (size_t) (str - *start); return str; } /* Extended string literal */ if ((*str == 'e' || *str == 'E') && str[1] == '\'') { *start = &str[2]; str += 2; while (*str) { if (*str == '\'') { *typ = TOKEN_EXT_STR; Assert(str >= *start); *len = (size_t) (str - *start); return str + 1; } if (*str == '\\' && str[1] == '\'') str += 2; else if (*str == '\\' && str[1] == '\\') str += 2; else str += 1; } *typ = TOKEN_EXT_STR; Assert(str >= *start); *len = (size_t) (str - *start); return str; } /* String literal */ if (*str == '\'') { *start = &str[1]; str += 1; while (*str) { if (*str == '\'') { if (str[1] != '\'') { *typ = TOKEN_STR; Assert(str >= *start); *len = (size_t) (str - *start); return str + 1; } str += 2; } else str += 1; } *typ = TOKEN_STR; Assert(str >= *start); *len = (size_t) (str - *start); return str; } /* Quoted identifier */ if (*str == '"') { *start = &str[1]; str += 1; while (*str) { if (*str == '"') { if (str[1] != '"') { *typ = TOKEN_QIDENTIF; Assert(str >= *start); *len = (size_t) (str - *start); return str + 1; } str += 2; } else str += 1; } *typ = TOKEN_QIDENTIF; Assert(str >= *start); *len = (size_t) (str - *start); return str; } /* Identifiers */ if (is_identif((unsigned char) *str) || *str == '_') { *start = str++; while (*str) { if (is_identif((unsigned char) *str) || isdigit(*str) || *str == '_') str++; else break; } *typ = TOKEN_IDENTIF; Assert(str >= *start); *len = (size_t) (str - *start); return str; } /* Others */ *typ = TOKEN_OTHER; *start = str; *len = 1; return str + 1; } /* * CREATE PROCEDURE dbms_sql.describe_columns(c int, OUT col_cnt int, OUT desc_t dbms_sql.desc_rec[]) * * Returns an array of column's descriptions. Attention, the typid are related to PostgreSQL type * system. */ Datum dbms_sql_describe_columns(PG_FUNCTION_ARGS) { CursorData *c; Datum values[13]; bool nulls[13]; TupleDesc tupdesc; TupleDesc desc_rec_tupdesc; TupleDesc cursor_tupdesc; HeapTuple tuple; Oid arraytypid; Oid desc_rec_typid; Oid *types = NULL; ArrayBuildState *abuilder; SPIPlanPtr plan; CachedPlanSource *plansource = NULL; int ncolumns = 0; int rc; int i = 0; bool nonatomic; MemoryContext callercxt = CurrentMemoryContext; if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) elog(ERROR, "return type must be a row type"); arraytypid = TupleDescAttr(tupdesc, 1)->atttypid; desc_rec_typid = get_element_type(arraytypid); if (!OidIsValid(desc_rec_typid)) elog(ERROR, "second output field must be an array"); desc_rec_tupdesc = lookup_rowtype_tupdesc_copy(desc_rec_typid, -1); abuilder = initArrayResult(desc_rec_typid, callercxt, true); c = get_cursor(fcinfo, true); if (c->variables) { ListCell *lc; types = palloc(sizeof(Oid) * c->nvariables); i = 0; foreach(lc, c->variables) { VariableData *var = (VariableData *) lfirst(lc); if (var->typoid == InvalidOid) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_PARAMETER), errmsg("variable \"%s\" has not a value", var->refname))); types[i++] = var->is_array ? var->typelemid : var->typoid; } } /* * Connect to SPI manager */ nonatomic = fcinfo->context && IsA(fcinfo->context, CallContext) && !castNode(CallContext, fcinfo->context)->atomic; if ((rc = SPI_connect_ext(nonatomic ? SPI_OPT_NONATOMIC : 0)) != SPI_OK_CONNECT) elog(ERROR, "SPI_connect failed: %s", SPI_result_code_string(rc)); plan = SPI_prepare(c->parsed_query, (int) c->nvariables, types); if (!plan || plan->magic != _SPI_PLAN_MAGIC) elog(ERROR, "plan is not valid"); if (list_length(plan->plancache_list) != 1) elog(ERROR, "plan is not single execution plany"); plansource = (CachedPlanSource *) linitial(plan->plancache_list); cursor_tupdesc = plansource->resultDesc; ncolumns = cursor_tupdesc->natts; for (i = 0; i < ncolumns; i++) { HeapTuple tp; Form_pg_type typtup; text *txt; Form_pg_attribute attr = TupleDescAttr(cursor_tupdesc, i); /* * 0. col_type BINARY_INTEGER := 0, * 1. col_max_len BINARY_INTEGER := 0, * 2. col_name VARCHAR2(32) := '', * 3. col_name_len BINARY_INTEGER := 0, * 4. col_schema_name VARCHAR2(32) := '', * 5. col_schema_name_len BINARY_INTEGER := 0, * 6. col_precision BINARY_INTEGER := 0, * 7. col_scale BINARY_INTEGER := 0, * 8. col_charsetid BINARY_INTEGER := 0, * 9. col_charsetform BINARY_INTEGER := 0, * 10. col_null_ok BOOLEAN := TRUE * 11. col_type_name varchar2 := '', * 12. col_type_name_len BINARY_INTEGER := 0 ); */ values[0] = Int32GetDatum(attr->atttypid); tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(attr->atttypid)); if (!HeapTupleIsValid(tp)) elog(ERROR, "cache lookup failed for type %u", attr->atttypid); typtup = (Form_pg_type) GETSTRUCT(tp); values[1] = Int32GetDatum(0); values[6] = Int32GetDatum(0); values[7] = Int32GetDatum(0); if (attr->attlen != -1) values[1] = Int32GetDatum(attr->attlen); else if (typtup->typcategory == 'S' && attr->atttypmod > VARHDRSZ) values[1] = Int32GetDatum(attr->atttypmod - VARHDRSZ); else if (attr->atttypid == NUMERICOID && attr->atttypmod > VARHDRSZ) { values[6] = Int32GetDatum(((attr->atttypmod - VARHDRSZ) >> 16) & 0xffff); values[7] = Int32GetDatum((((attr->atttypmod - VARHDRSZ) & 0x7ff) ^ 1024) - 1024); } txt = cstring_to_text(NameStr(attr->attname)); values[2] = PointerGetDatum(txt); values[3] = DirectFunctionCall1(textlen, PointerGetDatum(txt)); txt = cstring_to_text(get_namespace_name(typtup->typnamespace)); values[4] = PointerGetDatum(txt); values[5] = DirectFunctionCall1(textlen, PointerGetDatum(txt)); values[8] = Int32GetDatum(0); values[9] = Int32GetDatum(0); values[10] = BoolGetDatum(true); if (attr->attnotnull) values[10] = BoolGetDatum(false); else if (typtup->typnotnull) values[10] = BoolGetDatum(false); txt = cstring_to_text(NameStr(typtup->typname)); values[11] = PointerGetDatum(txt); values[12] = DirectFunctionCall1(textlen, PointerGetDatum(txt)); memset(nulls, 0, sizeof(nulls)); tuple = heap_form_tuple(desc_rec_tupdesc, values, nulls); abuilder = accumArrayResult(abuilder, HeapTupleGetDatum(tuple), false, desc_rec_typid, CurrentMemoryContext); ReleaseSysCache(tp); } SPI_freeplan(plan); if ((rc = SPI_finish()) != SPI_OK_FINISH) elog(ERROR, "SPI_finish failed: %s", SPI_result_code_string(rc)); MemoryContextSwitchTo(callercxt); memset(values, 0, sizeof(values)); memset(nulls, 0, sizeof(nulls)); values[0] = Int32GetDatum(ncolumns); nulls[0] = false; values[1] = makeArrayResult(abuilder, callercxt); nulls[1] = false; tuple = heap_form_tuple(tupdesc, values, nulls); PG_RETURN_DATUM(HeapTupleGetDatum(tuple)); } Datum dbms_sql_describe_columns_f(PG_FUNCTION_ARGS) { return dbms_sql_describe_columns(fcinfo); } orafce-VERSION_4_14_4/doc/000077500000000000000000000000001501757153000151635ustar00rootroot00000000000000orafce-VERSION_4_14_4/doc/orafce_documentation/000077500000000000000000000000001501757153000213535ustar00rootroot00000000000000orafce-VERSION_4_14_4/doc/orafce_documentation/Orafce_Documentation_01.md000066400000000000000000000107711501757153000262730ustar00rootroot00000000000000Orafce 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| |REGEXP_COUNT|searches a string for a regular expression, and returns a count of the matches| |REGEXP_INSTR|returns the beginning or ending position within the string where the match for a pattern was located| |REGEXP_LIKE|condition in the WHERE clause of a query, causing the query to return rows that match the given pattern| |REGEXP_SUBSTR|returns the string that matches the pattern specified in the call to the function| |REGEXP_REPLACE|replace substring(s) matching a POSIX regular expression| |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| |GREATEST|Returns the greatest of the list of one or more expressions| |LEAST|Returns the least of the list of one or more expressions| |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_4_14_4/doc/orafce_documentation/Orafce_Documentation_02.md000066400000000000000000000106221501757153000262670ustar00rootroot00000000000000Chapter 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_4_14_4/doc/orafce_documentation/Orafce_Documentation_03.md000066400000000000000000000062601501757153000262730ustar00rootroot00000000000000 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_4_14_4/doc/orafce_documentation/Orafce_Documentation_04.md000066400000000000000000000010041501757153000262630ustar00rootroot00000000000000Chapter 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_4_14_4/doc/orafce_documentation/Orafce_Documentation_05.md000066400000000000000000001571021501757153000262770ustar00rootroot00000000000000Chapter 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 - REGEXP_COUNT - REGEXP_INSTR - REGEXP_LIKE - REGEXP_SUBSTR - 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 REGEXP_COUNT **Description** Searches a string for a regular expression, and returns a count of the matches. **General rules** - REGEXP_COUNT returns the number of times *pattern* occurs in a source *string*. It returns an integer indicating the number of occurrences of *pattern*. If no match is found, then the function returns 0. - The search starts from the specified start position *startPos* in *string*, default starts from the beginning of *string*. - *startPos* is a positive integer, negative values to search from the end of *string* are not allowed. - *flags* is a character expression that lets you change the default matching behavior of the function. The value of *flags* can include one or more of the following characters: - 'i': case-insensitive matching. - 'c': case-sensitive and accent-sensitive matching. - 'n': the period (.) match the newline character. By default the period does not match the newline character. - 'm': treats the source string as multiple lines. - 'x': ignores whitespace characters. By default, whitespace characters match themselves. If you omit *flags*, then: - The default is case and accent sensitivity. - A period (.) does not match the newline character. - The source string is treated as a single line. **Example** ~~~ SELECT REGEXP_COUNT('a'||CHR(10)||'d', 'a.d') FROM DUAL; regexp_count -------------- 0 (1 row) SELECT REGEXP_COUNT('a'||CHR(10)||'d', 'a.d', 1, 'm') FROM DUAL; regexp_count -------------- 0 (1 row) SELECT REGEXP_COUNT('a'||CHR(10)||'d', 'a.d', 1, 'n') FROM DUAL; regexp_count -------------- 1 (1 row) SELECT REGEXP_COUNT('a'||CHR(10)||'d', '^d$', 1, 'm') FROM DUAL; regexp_count -------------- 1 (1 row) ~~~ ---- #### 5.2.9 REGEXP_INSTR **Description** Returns the beginning or ending position within the string where the match for a pattern was located. **General rules** - REGEXP_INSTR returns an integer indicating the beginning or ending position of the matched substring, depending on the value of the *return_opt* argument. If no match is found, then the function returns 0. - The search starts from the specified start position *startPos* in *string*, default starts from the beginning of *string*. - *startPos* is a positive integer, negative values to search from the end of *string* are not allowed. - *occurrence* is a positive integer indicating which occurrence of *pattern* in *string* should be search for. The default is 1, meaning the first occurrence of *pattern* in *string*. - *return_opt* lets you specify what should be returned in relation to the occurrence: - 0, the position of the first character of the occurrence is returned. This is the default. - 1, the position of the character following the occurrence is returned. - *flags* is a character expression that lets you change the default matching behavior of the function. See [REGEXP_COUNT](#REGEXP_COUNT) for detailed information. - For a *pattern* with capture group, *group* is a positive integer indicating which capture group in *pattern* shall be returned by the function. Capture groups can be nested, they are numbered in order in which their left parentheses appear in *pattern*. If *group* is zero, then the position of the entire substring that matches the pattern is returned. If *group* value exceed the number of capture groups in *pattern*, the function returns zero. A null *group* value returns *NULL*. The default value for *group* is zero. **Example** ~~~ SELECT REGEXP_INSTR('1234567890', '(123)(4(56)(78))') FROM DUAL; regexp_instr -------------- 1 (1 row) SELECT REGEXP_INSTR('1234567890', '(4(56)(78))', 3) FROM DUAL; regexp_instr -------------- 4 (1 row) SELECT REGEXP_INSTR('123 123456 1234567, 1234567 1234567 12', '[^ ]+', 1, 6) FROM DUAL; regexp_instr -------------- 37 (1 row) SELECT REGEXP_INSTR('199 Oretax Prayers, Riffles Stream, CA', '[S|R|P][[:alpha:]]{6}', 3, 2, 1) FROM DUAL; regexp_instr -------------- 28 (1 row) ~~~ ---- #### 5.2.10 REGEXP_LIKE **Description** Condition in the WHERE clause of a query, causing the query to return rows that match the given pattern. **General rules** - REGEXP_LIKE is similar to the LIKE condition, except it performs regular expression matching instead of the simple pattern matching performed by LIKE. - Returns a boolean, *true* when *pattern* match in *string*, *false* otherwise. - *flags* is a character expression that lets you change the default matching behavior of the function. See [REGEXP_COUNT](#REGEXP_COUNT) for detailed information. **Example** ~~~ SELECT REGEXP_LIKE('a'||CHR(10)||'d', 'a.d', 'm') FROM DUAL; regexp_like ------------- f (1 row) SELECT REGEXP_LIKE('a'||CHR(10)||'d', 'a.d', 'n') FROM DUAL; regexp_like ------------- t (1 row) ~~~ ---- #### 5.2.11 REGEXP_SUBSTR **Description** Returns the string that matches the pattern specified in the call to the function. **General rules** - REGEXP_SUBSTR returns the matched substring resulting from matching a POSIX regular expression pattern to a string. If no match is found, then the function returns *NULL*. - The search starts from the specified start position *startPos* in *string*, default starts from the beginning of *string*. - *startPos* is a positive integer, negative values to search from the end of *string* are not allowed. - *occurrence* is a positive integer indicating which occurrence of *pattern* in *string* should be search for. The default is 1, meaning the first occurrence of *pattern* in *string*. - *flags* is a character expression that lets you change the default matching behavior of the function. See [REGEXP_COUNT](#REGEXP_COUNT) for detailed information. - For a *pattern* with capture group, *group* is a positive integer indicating which capture group in *pattern* shall be returned by the function. Capture groups can be nested, they are numbered in order in which their left parentheses appear in *pattern*. If *group* is zero, then the position of the entire substring that matches the pattern is returned. If *group* value exceed the number of capture groups in *pattern*, the function returns *NULL*. A null *group* value returns *NULL*. The default value for *group* is zero. **Example** ~~~ SELECT REGEXP_SUBSTR('number of your street, zipcode town, FR', ',[^,]+') FROM DUAL; regexp_substr ---------------- , zipcode town (1 row) SELECT regexp_substr('number of your street, zipcode town, FR', ',[^,]+', 24) FROM DUAL; regexp_substr --------------- , FR (1 row) SELECT regexp_substr('number of your street, zipcode town, FR', ',[^,]+', 1, 2) FROM DUAL; regexp_substr --------------- , FR (1 row) SELECT regexp_substr('1234567890 1234567890', '(123)(4(56)(78))', 1, 1, 'i', 0) FROM DUAL; regexp_substr --------------- 12345678 (1 row) ~~~ ---- #### 5.2.12 REGEXP_REPLACE **Description** Returns the string that matches the pattern specified in the call to the function. **General rules** - REGEXP_REPLACE returns a modified version of the source string where occurrences of a POSIX regular expression pattern found in the source string are replaced with the specified replacement string. If no match is found or the occurrence queried exceed the number of match, then the source string untouched is returned. - The search and replacement starts from the specified start position *startPos* in *string*, default starts from the beginning of *string*. - *startPos* is a positive integer, negative values to search from the end of *string* are not allowed. - *occurrence* is a positive integer indicating which occurrence of *pattern* in *string* should be search for and replaced. The default is 0, meaning all occurrences of *pattern* in *string*. - *flags* is a character expression that lets you change the default matching behavior of the function. See [REGEXP_COUNT](#REGEXP_COUNT) for detailed information. **Example** ~~~ SELECT regexp_replace('512.123.4567 612.123.4567', '([[:digit:]]{3})\.([[:digit:]]{3})\.([[:digit:]]{4})', '(\1) \2-\3') FROM DUAL; regexp_replace ------------------------------- (512) 123-4567 (612) 123-4567 (1 row) SELECT oracle.REGEXP_REPLACE('number your street, zipcode town, FR', '( ){2,}', ' ', 9); regexp_replace ---------------------------------------- number your street, zipcode town, FR (1 row) SELECT oracle.REGEXP_REPLACE('number your street, zipcode town, FR', '( ){2,}', ' ', 9, 2); regexp_replace --------------------------------------------- number your street, zipcode town, FR (1 row) ~~~ ---- #### 5.2.13 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.14 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.15 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.16 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 - GREATEST - LEAST - 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 GREATEST and LEAST **Description** The GREATEST and LEAST functions select the largest or smallest value from a list of any number of expressions. The expressions must all be convertible to a common data type, which will be the type of the result **Syntax** ``` GREATEST(value [, ...]) LEAST(value [, ...]) ``` **General rules** - These two function are the same behavior than the POstgreSQL one except that instead of retunring NULL only when all parameters are NULL ,they return NULL when one of the parameters is NULL like in Oracle. **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 GREATEST ('C', 'F', 'E') greatest ---------- F (1 row) ~~~ ~~~ \pset null ### SELECT LEAST ('C', NULL, 'E') greatest ---------- ### (1 row) ~~~ ---- #### 5.5.3 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.4 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.5 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.6 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_4_14_4/doc/orafce_documentation/Orafce_Documentation_06.md000066400000000000000000001452131501757153000263000ustar00rootroot00000000000000Chapter 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 TABLE dbms_output_table(c1 text, c2 int); CREATE FUNCTION dbms_output_exe() RETURNS VOID AS $$ DECLARE buff1 VARCHAR(20); stts1 INTEGER; BEGIN PERFORM DBMS_OUTPUT.SERVEROUTPUT(TRUE); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.PUT('DBMS_OUTPUT TEST 1'); PERFORM DBMS_OUTPUT.NEW_LINE(); PERFORM DBMS_OUTPUT.PUT_LINE('DBMS_OUTPUT TEST 2'); PERFORM DBMS_OUTPUT.SERVEROUTPUT(FALSE); PERFORM DBMS_OUTPUT.ENABLE(); PERFORM DBMS_OUTPUT.PUT_LINE('DBMS_OUTPUT TEST 3'); SELECT line,status INTO buff1,stts1 FROM DBMS_OUTPUT.GET_LINE(); INSERT INTO dbms_output_table VALUES(buff1,stts1); END; $$ LANGUAGE plpgsql; SELECT dbms_output_exe(); SELECT * FROM dbms_output_table; DROP FUNCTION dbms_output_exe(); DROP TABLE dbms_output_table; ~~~ ### 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.| |GET_TIME|Returns the number of hundredths of seconds that have elapsed since a point in time in the past.| **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(); ~~~ **GET_TIME** - GET_TIME returns the current time in 100th's of a second from a point in time in the past. This function is used for determining elapsed time. **Example** ---- ~~~ DO $$ DECLARE start_time integer; end_time integer; BEGIN start_time := DBMS_UTILITY.GET_TIME; PERFORM pg_sleep(10); end_time := DBMS_UTILITY.GET_TIME; RAISE NOTICE 'Execution time: % seconds', (end_time - start_time)/100; END $$; ~~~ ---- **Note** ---- The function is called twice, the first time at the beginning of some procedural code and the second time at end. Then the first (earlier) number is subtracted from the second (later) number to determine the time elapsed. Must be divided by 100 to report the number of seconds elapsed. ---- ### 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_4_14_4/doc/orafce_documentation/Orafce_Documentation_07.md000066400000000000000000000027321501757153000262770ustar00rootroot00000000000000Chapter 7 Transaction behavior --- Most of the transaction behavior are exactly same, however the below stuff is not. ### 7.1 Handled Statement Failure. ``` create table t (a int primary key, b int); begin; insert into t values(1,1); insert into t values(1, 1); commit; ``` Oracle : commit can succeed. t has 1 row after that. PostgreSQL: commit failed due to the 2nd insert failed. so t has 0 row. ### 7.2 DML with Subquery Case 1: ``` create table dml(a int, b int); insert into dml values(1, 1), (2,2); -- session 1: begin; delete from dml where a in (select min(a) from dml); --session 2: delete from dml where a in (select min(a) from dml); -- session 1: commit; ``` In Oracle: 1 row deleted in sess 2. so 0 rows in the dml at last. In PG : 0 rows are deleted in sess 2, so 1 rows in the dml at last. Oracle probably detects the min(a) is changed and rollback/rerun the statement. The same reason can cause the below difference as well. ``` create table su (a int, b int); insert into su values(1, 1); - session 1: begin; update su set b = 2 where b = 1; - sess 2: select * from su where a in (select a from su where b = 1) for update; - sess 1: commit; ``` In oracle, 0 row is selected. In PostgreSQL, 1 row (1, 2) is selected. A best practice would be never use subquery in DML & SLEECT ... FOR UPDATE. Even in Oracle, the behavior is inconsistent as well. Oracle between 11.2.0.1 and 11.2.0.3 probably behavior same as Postgres, but other versions not. orafce-VERSION_4_14_4/doc/orafce_documentation/gif/000077500000000000000000000000001501757153000221205ustar00rootroot00000000000000orafce-VERSION_4_14_4/doc/orafce_documentation/gif/ADD_MONTHS.gif000066400000000000000000000044671501757153000243020ustar00rootroot00000000000000GIF89ał?p!łM,ł?‡3f™Ģ’++3+f+™+Ģ+’UU3UfU™UĢU’€€3€f€™€Ģ€’ŖŖ3ŖfŖ™ŖĢŖ’ÕÕ3ÕfՙÕĢÕ’’’3’f’™’Ģ’’3333f3™3Ģ3’3+3+33+f3+™3+Ģ3+’3U3U33Uf3U™3UĢ3U’3€3€33€f3€™3€Ģ3€’3Ŗ3Ŗ33Ŗf3Ŗ™3ŖĢ3Ŗ’3Õ3Õ33Õf3ՙ3ÕĢ3Õ’3’3’33’f3’™3’Ģ3’’ff3fff™fĢf’f+f+3f+ff+™f+Ģf+’fUfU3fUffU™fUĢfU’f€f€3f€ff€™f€Ģf€’fŖfŖ3fŖffŖ™fŖĢfŖ’fÕfÕ3fÕffՙfÕĢfÕ’f’f’3f’ff’™f’Ģf’’™™3™f™™™Ģ™’™+™+3™+f™+™™+Ģ™+’™U™U3™Uf™U™™UĢ™U’™€™€3™€f™€™™€Ģ™€’™Ŗ™Ŗ3™Ŗf™Ŗ™™ŖĢ™Ŗ’™Õ™Õ3™Õf™Õ™™Õ̙Ւ™’™’3™’f™’™™’Ģ™’’ĢĢ3ĢfĢ™ĢĢĢ’Ģ+Ģ+3Ģ+fĢ+™Ģ+ĢĢ+’ĢUĢU3ĢUfĢU™ĢUĢĢU’̀̀3Ģ€fĢ€™Ģ€ĢĢ€’ĢŖĢŖ3ĢŖfĢŖ™ĢŖĢĢŖ’ĢÕĢÕ3ĢÕfĢՙĢÕĢĢÕ’Ģ’Ģ’3Ģ’fĢ’™Ģ’ĢĢ’’’’3’f’™’Ģ’’’+’+3’+f’+™’+Ģ’+’’U’U3’Uf’U™’UĢ’U’’€’€3’€f’€™’€Ģ’€’’Ŗ’Ŗ3’Ŗf’Ŗ™’ŖĢ’Ŗ’’Õ’Õ3’Õf’ՙ’ÕĢ’Õ’’’’’3’’f’’™’’Ģ’’’©÷ H° Įƒ*\Ȱ”Ƈ#JœH±¢Å‹3jÜȱ£Ē CŠI²¤É“(SŖ\ɲ„Ė—0cʜI³¦Ķ›8sźÜɳ§ĻŸ@ƒ J“ØŃ£H“*]Ź“©Ó§P£JJµŖÕ«X³jŻŹµ«×Æ`ÊK¶¬Ł³hÓŖ]˶­Ū·p欝K·®Ż»xóźŻĖ·Æßæ€ Lø°įƈ+^Ģø±ćǐ#KžL¹²ėå˘3kŽĢ¹³ēĻ C‹Mŗ“éÓØS«^Ķŗµė×°cĖžM»¶ķŪøsėŽĶ»·ļÖ1N¼øńćȓ+_μ¹óēŠ£KŸ®Ü€ÅąŌ³·~»öļąµsŸč=|öń Ė›_Ļ9śīķ©ĒX ąwĀśńæŌŸæ+’ˆ’±ą}žm4 JŽ•ąo 2Ō I:X E’Tį>:•įB‚ŌaVÖ¢@#rT"‰Nt¢F®X”‹(ĀcT3¶Vbż]„#P#īØāC>ś4c¢” ‘Ś‡Š1­ˆäN=6 dŠ=鐕ū(#[’…åhLŹX%•EŠy%™}ÉįH™l)†2z©äAaī7&WQšŁš6 )%H“C&ń™QƒĄI"q„.:\£KŽ0ś)¤@ē ĘÅYč@ĽU'B™ aį ””)A’ •§gŠŌź›5ł‰Š|zĶ–7c”ØD “¤ ™f‰¬Æ+Ę@Į 4 ®šz¬~Ē”­±üm ³™PK_š )#nHN©hAĜ+dްī)R»1ŅdėAmęŗ1œ>»¤œ Ż`.ØįŹ_=­­õPZoŒßR‹ģ§#»®Z£„³#„«„ßār}Š7Ÿ„ ’ėōŖK-*4Øpü 7„śõ sÉü²~ h B_˜‰ 4ĄĶ>+”Ū‚ŖLÓ$^¬ķ·„f’É ū„[01ŁŖŖģŌ`‡ƒ»le\Ö%yL*Ś‚ī3I«“˜ŗqÖhĒĄqN+·Ō2©1{dÕ¦N+­µ9g]ģÜęšZź>K½Ņ½Ķ}ŖEZ z7<&”ļĄžDė/©Œ¤oÖ7zAćgp=ƒŚ)·ĀI–Ł! MŚĮžŖ(žNŖ4œ‰›2NyūėAo D¬@˜|–X'Ÿµ¤1Ą)†æ“<{¬©z’œPÜøSDŒ›ĮØ^|”"ÄépŽ; 5†²­tœü’Ōė¶™LŅōžŻĘp;ANJŸYĄ£9²}Ä< ”—@ÄP¬- ĒWõ!Fq†w“ļ4 : ©ž@4ø)0Kó‘\ćpŗ®kK“{’æ“iĒ –Ž2č9Bu‹m4`œTõ,üüLJ5œXė@UĪIkUh”“ōE.„(c<7Ȅƒ7Ÿ'"-†’׿ź…5#ŠĮThŪĒ žf°`MkūŸń„šM"•ėŹō“MRüŖ²˜¶G'F0QųćY±ų‡­BЇ˜J!Y”ų0‘ØĶ Ź#扟.åKŒp OŠ÷ø)%ĶXžŅš&³uŗ,IŖ~Z^+‰D&ę®Ļ ^{£D(Õ«ņ]‘Ug£Ł„\×3ĢvÉz˜ēˆ!bž—Ļ+[Ņ8YRˆ…Ā®@ę°cIźZ2üŃ3·>-BWœ[œ²dBU«zžJå>@FĮ“@Ī aģŲEĀU“ć½kNa¤)» /­pRyīōäVŽIq:“"£ٹ{Š8—ÓŒ>³Ö;t½ņ*’t[@ķ "ļ}s£ T-¹éP|6’Ž,»ØU2Š’½ Ō£)ķH  ŠŹlöÓ¤uå6_ŗÓ˜zӟ0ķŽḠЋ›Ł“§8]¦OoŠ–‚TBx ź?R75źØŚ4éIm©'¦bŌ«(PY”E‘ alGŗ%>sŹO¤6¬)qéXŁŲU6E‹GčĖ«^÷Ź×¾¦©ÆĪ©`;üv9@:¬b›c Å"'% ÕŖd'KŁŹZö²˜Ķ¬f7ĖŁĪzö³  ­hGKŚŅšö“ØM­jWĖŚÖŗöµ°­lgKŪŚŚö¶øĶ­nwĖŪŽśö·Ą5J@;orafce-VERSION_4_14_4/doc/orafce_documentation/gif/BITAND.gif000066400000000000000000000036241501757153000235550ustar00rootroot00000000000000GIF89aŌ5p!ł:,Ō5‡3f™Ģ’++3+f+™+Ģ+’UU3UfU™UĢU’€€3€f€™€Ģ€’ŖŖ3ŖfŖ™ŖĢŖ’ÕÕ3ÕfՙÕĢÕ’’’3’f’™’Ģ’’3333f3™3Ģ3’3+3+33+f3+™3+Ģ3+’3U3U33Uf3U™3UĢ3U’3€3€33€f3€™3€Ģ3€’3Ŗ3Ŗ33Ŗf3Ŗ™3ŖĢ3Ŗ’3Õ3Õ33Õf3ՙ3ÕĢ3Õ’3’3’33’f3’™3’Ģ3’’ff3fff™fĢf’f+f+3f+ff+™f+Ģf+’fUfU3fUffU™fUĢfU’f€f€3f€ff€™f€Ģf€’fŖfŖ3fŖffŖ™fŖĢfŖ’fÕfÕ3fÕffՙfÕĢfÕ’f’f’3f’ff’™f’Ģf’’™™3™f™™™Ģ™’™+™+3™+f™+™™+Ģ™+’™U™U3™Uf™U™™UĢ™U’™€™€3™€f™€™™€Ģ™€’™Ŗ™Ŗ3™Ŗf™Ŗ™™ŖĢ™Ŗ’™Õ™Õ3™Õf™Õ™™Õ̙Ւ™’™’3™’f™’™™’Ģ™’’ĢĢ3ĢfĢ™ĢĢĢ’Ģ+Ģ+3Ģ+fĢ+™Ģ+ĢĢ+’ĢUĢU3ĢUfĢU™ĢUĢĢU’̀̀3Ģ€fĢ€™Ģ€ĢĢ€’ĢŖĢŖ3ĢŖfĢŖ™ĢŖĢĢŖ’ĢÕĢÕ3ĢÕfĢՙĢÕĢĢÕ’Ģ’Ģ’3Ģ’fĢ’™Ģ’ĢĢ’’’’3’f’™’Ģ’’’+’+3’+f’+™’+Ģ’+’’U’U3’Uf’U™’UĢ’U’’€’€3’€f’€™’€Ģ’€’’Ŗ’Ŗ3’Ŗf’Ŗ™’ŖĢ’Ŗ’’Õ’Õ3’Õf’ՙ’ÕĢ’Õ’’’’’3’’f’’™’’Ģ’’’’÷ H° Įƒ*\Ȱ”Ƈ#JœH±¢Å‹3jÜȱ£Ē CŠI²¤É“(SŖ\ɲ„Ė—0cʜI³¦Ķ›8sźÜɳ§ĻŸ@ƒ J“ØŃ£H“*]Ź“©Ó§P£JJµŖÕ«X³jŻŹµ«×Æ`ÊK¶¬Ł³hÓŖ]˶­Ū·p欝K·®Ż»xóźŻĖ·ļŽ Lø°įƈ+^L8†CŒ#vܲä˘Sfh9³āĶ ;{Mhƒ¢K7ö `j놯;Ę^8Ūfķ„·3ę.øgļ}æ+wMöĒį‘·T®<āšę1C8½iõ Ģ;¼~2»Ēē@„kyļŹż§wŁŪužē޼ĀņļYgwśœė7¶÷)ž;JbŠTOłiT €÷”G[xńłW’27† nƒe’Ü>7`rŹ €…&WaH” •(P tCA(:Hßx &Ä"B/`$õwŠi ؐL’܄ķ8ŠŽŹŌ›’ƒFŒ;>Ł”É’ŠŹ™ą‚Z 9*8£ŒöM$¦Žt˜‰—ģÕhP&bP$¤Bhć‘3łøŹ@3[m,֙åfÆĶVO™f‚yZ¦ų„A”Ż@L`FY`F¢)§~gŚ(„˜ j!Šä§AÜŻyŠ„Œņ)SoXv¹“KĪįŸ*‰FÆWÖÖ&Ž“‚p“”‰‘°īƒ*¤£Nņ+±ŸźAĖīÓ쳑š'Øi"­D®Ō卼!yPaÉՓŖ@“i+Ÿ›ŗ[ Ō†[Š¢ŠŲ™ģ@bXˆŖ³u¢+”žź nµL°@ØĢ’f $­¤ "«ź„%ÆµĪ–!P.«äĒĄµŲhÅo"kBųāĖė> Ķ›0B徫pA1·č0hb|ēĪŹvźGyī¹®E€©Ę®¾JŠfQœI¢ęnųd¢ŚÉ5ĪrH³¹±ź÷µlŒ5Ū°T—½„b ]L®ÓƒąnÅ,Ń:Ø2![¼±­VKŻ®LtŲ_k®có*SgĖ>“āÖė1ć”9ī,e1(=ŅŖ0näFõÄ 1Ē}¾7¢¬ĄŻė Wßķ,ö®ž/Ų0‹>śĖ)ƒā®:2@™7Øl8īKūk¹¹æēhėŽŽ¦ūĶ:«üF;ʌś¬ó-æę¤Ū¼{Ÿzų0ŗŒ÷M ›č9uM¢gņÜK„āĆäž;>囸oŪ\?HD2ā¢Ó½óéĻ€/™ßįדōa$g”2-2ĮŽķ‚ö‹žøAž]pyÓ¦,h b|5Qąõ>˜B&n$īĖ ™¢Āŗp9&aŗÜĆBŽ„H3\J ’×A¢P7E“Ķ †ćĮ¤‚÷ßE†˜·®y \āīøB·.zŃ0Ūłā`Ā(F1’±Œō)£ĒH!5śåpŒ£ēHĒ:ŚńŽxĢ£÷ČĒ>śń€ ¤ IČBņˆL¤"ÉČF:ņ‘Œ¤H;orafce-VERSION_4_14_4/doc/orafce_documentation/gif/BTRIM.gif000066400000000000000000000046201501757153000234660ustar00rootroot00000000000000GIF89alVp!łH,lV‡3f™Ģ’++3+f+™+Ģ+’UU3UfU™UĢU’€€3€f€™€Ģ€’ŖŖ3ŖfŖ™ŖĢŖ’ÕÕ3ÕfՙÕĢÕ’’’3’f’™’Ģ’’3333f3™3Ģ3’3+3+33+f3+™3+Ģ3+’3U3U33Uf3U™3UĢ3U’3€3€33€f3€™3€Ģ3€’3Ŗ3Ŗ33Ŗf3Ŗ™3ŖĢ3Ŗ’3Õ3Õ33Õf3ՙ3ÕĢ3Õ’3’3’33’f3’™3’Ģ3’’ff3fff™fĢf’f+f+3f+ff+™f+Ģf+’fUfU3fUffU™fUĢfU’f€f€3f€ff€™f€Ģf€’fŖfŖ3fŖffŖ™fŖĢfŖ’fÕfÕ3fÕffՙfÕĢfÕ’f’f’3f’ff’™f’Ģf’’™™3™f™™™Ģ™’™+™+3™+f™+™™+Ģ™+’™U™U3™Uf™U™™UĢ™U’™€™€3™€f™€™™€Ģ™€’™Ŗ™Ŗ3™Ŗf™Ŗ™™ŖĢ™Ŗ’™Õ™Õ3™Õf™Õ™™Õ̙Ւ™’™’3™’f™’™™’Ģ™’’ĢĢ3ĢfĢ™ĢĢĢ’Ģ+Ģ+3Ģ+fĢ+™Ģ+ĢĢ+’ĢUĢU3ĢUfĢU™ĢUĢĢU’̀̀3Ģ€fĢ€™Ģ€ĢĢ€’ĢŖĢŖ3ĢŖfĢŖ™ĢŖĢĢŖ’ĢÕĢÕ3ĢÕfĢՙĢÕĢĢÕ’Ģ’Ģ’3Ģ’fĢ’™Ģ’ĢĢ’’’’3’f’™’Ģ’’’+’+3’+f’+™’+Ģ’+’’U’U3’Uf’U™’UĢ’U’’€’€3’€f’€™’€Ģ’€’’Ŗ’Ŗ3’Ŗf’Ŗ™’ŖĢ’Ŗ’’Õ’Õ3’Õf’ՙ’ÕĢ’Õ’’’’’3’’f’’™’’Ģ’’’ę÷ H° Įƒ*\Ȱ”Ƈ#JœH±¢Å‹3jÜȱ£Ē CŠI²¤É“(SŖ\ɲ„Ė—0cʜI³¦Ķ›8sźÜɳ§ĻŸ@ƒ J“ØŃ£H“*]Ź“©Ó§P£JJµŖÕ«X³jŻŹµ«×Æ`ÊK¶¬Ł³hÓŖ]˶­Ū·p欝K·®Ż»xóźŻĖ·Æßæ€7Œ °įƈ+6cšāǐ#KžL¹²eɍkެĄGĻ AŪ͹“闤7¦FøZnėÓ°c‹|}‘6AŪnqĖŽĶ»¢ī‰æÆŽ»øń„Ä!Ē›’üøóćĶ.æż¹uŁÕC7ĢN–ūõ#ß¾PŒA1Ź*3l^ śŽķ[ŠOßļüƒÓ®§˜ItŒŻGŠ~. X߁Ō}Fž~…Ż@Ģ 1ÄMcŹÄŠ&yVį…‰QXfFøˆdvbahŌÓą>“¼øO…īcX&ˆąŽ®)Ø]B“ąŲ_zʘ§Ģ ęõ'd’hTa“™$ŁžPbøO”ī5)F{ž”!dfbi„“˜#h¦c‡ "tCzh”y"Ž[ŗ'g˜ūÄ@ĢAuīgA’iП©‰±ē éķCLc‚Ī@“>¦)i]Bhé˜Bøf€™v’z©m+ø·ē‰é½é^¢Īy©ū¤ŠĘa8²śźŹP‡ˆ™÷Ž@Æ&Ź—ėi§*NjģV£Œ²Ģ.ėģ¦6:KL³ĶrhP…3ŖZØŁ*˜r 4I“Ü橨Š1(S¤@‹¤'¶aŪe’Łø9R+ķ¾śB{ģæ;å÷k›×x¤@õ˜04ū$\£Zyef™aK ˆŁnč-Ę6~‹ĘŗŃ:Ŗ.€ū®jł šŹ6 < w.D dŹ™I“š>(P&įĪ,#1*é¬b؊Æ{…-naeĪl°a↋"Ée§2ĖXĒ3ƾL—ÕY‡ķŌÖ;wżćh)‹D­¶Rd×ęõ\`Æ-wQm[TwniĻ­wPwē½ŠÕVŽ÷ą<õ ÜŪ=Nųā9.‘ćj Īųä3wYeŪ]®łęœwιߒ”‡ŽščŹ‘n:K€Æœśé¬ßÖśßÆĒ>›ģ¬ŃnūĄ·»žūīfó¾:~¬šĄNü¤Ē?wņi2ĻažG/=dÅ*dĄōˆUŸŠõŲwļ=õnōŽkļ•ó' ­ś_‰‡žŽŃ­ßŻTģŸ‰8Vī¤a½_RżU“NūĀē»Ēń,ž# qw6®äO|“ŸX8’¢ģ~Wy`#"æĆ[@”ąģ0h7ž€»ŪŸ7R!ĀE„!± Fd˜ ¦0‚䈈pƇŠf=°jUö€x˜ˆ9ŠjÆJŸ Ā3Å5!ńYŠ s§B'Qƒy¤:Ę7…£ā¢#™bÆ1Ņl 7 Ż:/>ÄZlC!qx,ѱ"ż¹ĮĆŲ’ŌE„U²Ö~I3"‰Į| Y£Ŗœ;ä&.¢Y& „Č>öī†XTH%Żh‘śŠ!ää·t7ʝeӓföÉ>‘”wBŽÖ%±2Ž%„`&‚§]Nd‡µ³äµ²/ŃqDF\ĻŗŠ£Ę%ä`m”„“¢ō4*)S¼]™x2gBDD[ÄOGČ÷½"J3O8*%•ÉĒ.HŒ Ĝ“Źõ8y&¤W\d6ĖÉĻ~śóŸ ØbbGål„ēōÉIƒ†QR41J¦gØ4 8ŗ²‘»¤( 2 ’+a“āEĀ™»t–N!“č& RµņV/ÜØˆJóPžč”fZĻžš‰Azśr£/×Ē(tE¤ō0vøńR,2³]äØ<&LśŠ—} W³h ½I^.Uœ™š¢€•R¦@µuøń)W##’ŖS”ō[+ T­œ•u¶¹])LXĀU*Š„‘[WjSd)O%?Üd]+²‚t¶'w½ą+3ŲŖDÖtŌČzHvŁ`F„²Ńō¬›’Ģn¤­ėgå*DŽڕ“(1­SūŌøvÆ¢5,lM"[޼“p¶,F@ÜŻVš€,ks)Ü ÷Č=Ÿ@§;ŠĢ•S:ŌĶ®=ŸC~r÷»ą ÆxĒKŽņ)š÷¼čMÆz×ĖŽöŗ÷½šÆ|ēKßśŚ÷¾ųĶÆ~÷Ėßžś÷æŽ]@;orafce-VERSION_4_14_4/doc/orafce_documentation/gif/COSH.gif000066400000000000000000000034771501757153000233560ustar00rootroot00000000000000GIF89aī7p!ł>,ī7‡3f™Ģ’++3+f+™+Ģ+’UU3UfU™UĢU’€€3€f€™€Ģ€’ŖŖ3ŖfŖ™ŖĢŖ’ÕÕ3ÕfՙÕĢÕ’’’3’f’™’Ģ’’3333f3™3Ģ3’3+3+33+f3+™3+Ģ3+’3U3U33Uf3U™3UĢ3U’3€3€33€f3€™3€Ģ3€’3Ŗ3Ŗ33Ŗf3Ŗ™3ŖĢ3Ŗ’3Õ3Õ33Õf3ՙ3ÕĢ3Õ’3’3’33’f3’™3’Ģ3’’ff3fff™fĢf’f+f+3f+ff+™f+Ģf+’fUfU3fUffU™fUĢfU’f€f€3f€ff€™f€Ģf€’fŖfŖ3fŖffŖ™fŖĢfŖ’fÕfÕ3fÕffՙfÕĢfÕ’f’f’3f’ff’™f’Ģf’’™™3™f™™™Ģ™’™+™+3™+f™+™™+Ģ™+’™U™U3™Uf™U™™UĢ™U’™€™€3™€f™€™™€Ģ™€’™Ŗ™Ŗ3™Ŗf™Ŗ™™ŖĢ™Ŗ’™Õ™Õ3™Õf™Õ™™Õ̙Ւ™’™’3™’f™’™™’Ģ™’’ĢĢ3ĢfĢ™ĢĢĢ’Ģ+Ģ+3Ģ+fĢ+™Ģ+ĢĢ+’ĢUĢU3ĢUfĢU™ĢUĢĢU’̀̀3Ģ€fĢ€™Ģ€ĢĢ€’ĢŖĢŖ3ĢŖfĢŖ™ĢŖĢĢŖ’ĢÕĢÕ3ĢÕfĢՙĢÕĢĢÕ’Ģ’Ģ’3Ģ’fĢ’™Ģ’ĢĢ’’’’3’f’™’Ģ’’’+’+3’+f’+™’+Ģ’+’’U’U3’Uf’U™’UĢ’U’’€’€3’€f’€™’€Ģ’€’’Ŗ’Ŗ3’Ŗf’Ŗ™’ŖĢ’Ŗ’’Õ’Õ3’Õf’ՙ’ÕĢ’Õ’’’’’3’’f’’™’’Ģ’’’’÷ H° Įƒ*\Ȱ”Ƈ#JœH±¢Å‹3jÜȱ£Ē CŠI²¤É“(SŖ\ɲ„Ė—0cʜI³¦Ķ›8sźÜɳ§ĻŸ@ƒ J“ØŃ£H“*]Ź“©Ó§P£JJµŖÕ«X³jŻŹµ«×Æ`ÊK¶¬Ł³hÓŖ]˶­Ū·p欝K·®Ż»xóźŻĖ·Æßæ€ Lø°įƈłĘĄø±ćǐ#KžL¹²å˘3ˆQq±ęĻ–9Sō ŗ“éÓØ‹ÖH:µéÕ]ä•M‘6KŪqŸÕ}‘7JßYĒΐ8Ić ‘Už9HēQ”§•N:Gė±_Õ~;FļIĮ‡ Õ.¾"łµå³»Lo0’ūļ¹žo9śõõŃø’c­õ­ąn÷ŃĒ‘2b †2ūüבqŹ4›{ŒeR]cEH†M ŲŽ$š™‡^ÕsĆqĆÕõDÜ$¶”±‚@™Ģ˜ˆ C£hŗ9h`m Łųœˆj±'\&bŒ^XXƒŻ`aŠ4HÄp(P=P H$Bb89$ Ż@ cTŚF[ ŖČ˜RF&§¤E0Ę@„Aaf$œ2° hA1čxC ZMŸ)yøåh"቙°ˆą@œ‹īYˆdx$„†Ž!J„ą~{vēbBƒŌź@h8!›ūĢśX=Žy’¢źjŠ$'ī3I’ŸīC ‹b$¹O#, ŪģQu&T©HŅ)³bCŒöĘj°©H(©Õ)SO:åØ@ĐK­Æ”Ae¬ūĄ»O™ūÜ@„½į‹T“Mņ¬e²ŽŲ®šąīē>BŖ÷ź¼™x¹˜Y2…°2™t™1Ęw¬ 1Æ©Æ×2ž¢Œ†Ź,§ģ/qBNÉš@0h› µŁ”<ĒŠóĻ> 4 eB°B'ݳgG Qk®iVtŒ6ŗ7Ķ6‰©Ķ-j.Ļ`ūö cK©¤Ļbų›¶ŹžśŪHŪ*'Ś„ g­ę­’]šüq߀’-øß„‹œķ½š}¬xߋ+ƒq‚ 6g0«nؘ™ 6Ę ˜ø~¹·Iē „ų™ ēm­¢yö©µk4”ņ éCś©éōNŸCŗŻėFŠæķż °Dk.l'O¹?µ»³„–>b”ÕCrģeĀ_Ó-"?»æqOš*yg¢‚©Ŗ§=^ĖĻžŪó%µFśEžžłw„ß»óERßżFy:é~D’³˜÷@7@±€ÆQX“(9ōE¾#ō~ä9MĪ.ökŽśņ7Įۈ¤sø‹šGHB©Õ¦„ 1 WČĀĢ\§…˜IŒ gHĆŚš†8Ģ”wČĆś!š‡@ ¢‡HÄ"ńˆHL¢—ČÄ&:ń‰PŒ¢§h•€;orafce-VERSION_4_14_4/doc/orafce_documentation/gif/DATE.gif000066400000000000000000000022761501757153000233330ustar00rootroot00000000000000GIF89a˜0p!ł3,˜0‡3f™Ģ’++3+f+™+Ģ+’UU3UfU™UĢU’€€3€f€™€Ģ€’ŖŖ3ŖfŖ™ŖĢŖ’ÕÕ3ÕfՙÕĢÕ’’’3’f’™’Ģ’’3333f3™3Ģ3’3+3+33+f3+™3+Ģ3+’3U3U33Uf3U™3UĢ3U’3€3€33€f3€™3€Ģ3€’3Ŗ3Ŗ33Ŗf3Ŗ™3ŖĢ3Ŗ’3Õ3Õ33Õf3ՙ3ÕĢ3Õ’3’3’33’f3’™3’Ģ3’’ff3fff™fĢf’f+f+3f+ff+™f+Ģf+’fUfU3fUffU™fUĢfU’f€f€3f€ff€™f€Ģf€’fŖfŖ3fŖffŖ™fŖĢfŖ’fÕfÕ3fÕffՙfÕĢfÕ’f’f’3f’ff’™f’Ģf’’™™3™f™™™Ģ™’™+™+3™+f™+™™+Ģ™+’™U™U3™Uf™U™™UĢ™U’™€™€3™€f™€™™€Ģ™€’™Ŗ™Ŗ3™Ŗf™Ŗ™™ŖĢ™Ŗ’™Õ™Õ3™Õf™Õ™™Õ̙Ւ™’™’3™’f™’™™’Ģ™’’ĢĢ3ĢfĢ™ĢĢĢ’Ģ+Ģ+3Ģ+fĢ+™Ģ+ĢĢ+’ĢUĢU3ĢUfĢU™ĢUĢĢU’̀̀3Ģ€fĢ€™Ģ€ĢĢ€’ĢŖĢŖ3ĢŖfĢŖ™ĢŖĢĢŖ’ĢÕĢÕ3ĢÕfĢՙĢÕĢĢÕ’Ģ’Ģ’3Ģ’fĢ’™Ģ’ĢĢ’’’’3’f’™’Ģ’’’+’+3’+f’+™’+Ģ’+’’U’U3’Uf’U™’UĢ’U’’€’€3’€f’€™’€Ģ’€’’Ŗ’Ŗ3’Ŗf’Ŗ™’ŖĢ’Ŗ’’Õ’Õ3’Õf’ՙ’ÕĢ’Õ’’’’’3’’f’’™’’Ģ’’’’÷ H° Įƒ*\Ȱ”Ƈ#JœH±¢Å‹3jÜȱ£Ē CŠI²¤É“(SŖ\ɲ„Ė—0cʜI³¦Ķ›8sźÜɳ§ĻŸcJ“ØŃ£H“*]Ŗ4P‹€F}JqŖO«T#bå¹5«Ć®:Įz](gY‹Ä Ō ē¦ż§Ž$Öķ7ē@1°§@4ŗO&źµzz¬& ”§V^JČÕy&«Xé ȝ9¢­””jEnrZ¤œ÷m7jqĒīóÜØ”4hŸ=K¶ūŌ“ģ@ߌˆ•µŹØP&Ö’­¹Ļ$N‚*РĬ @=ūk©¹ eĀg˜ŹöĖļ«”‹*Ą‹ŃŸ«ś,)‡³Ž›©¦@:$›ö€'¹h˜*F¼hā‹1¦"ėļČŽ«œÆt’;%zzā™'Ė)ŸlRøÉ)ģæZ*d0rńn|čsd|oÄ ©‹3ÉHŪŻœŸZ·}ļ~4pAK[<³¢9;źń”`ļ“ KKźLAdļŃI·šAŚĘśņA7Dk€”Ūs3£Ųö½-z“ŠģōO’ń q×cĮ«ž©õœŹč-äC#~ŠĆ"»Ż|äżn؉WŻg™Ż„JŖĖó‚K°@b”ē°Ć§ėG…§óqø®źäˈfb꜓«d;B¾·ūńČ'ÆüņĢ7?nį2K·hx«Ü±Īj”ŁĀ|=ŌŻ‡Ģ0įēē'Śi¹šŖūZōi  ‘–?•öüķ»ļühÉÆŃ·÷SJŁ—æśĶ†gńSō5ūéĻk4 lhB$DJA¬A$$_üōĄ£lmšm(X–¢°S%lŠyœ—«¾m… ŒŸ}hˆ( ńš‡Ć³!>Č ‘yBLbC\Č&*ń‰kq¢b¤Å*¶ˆVĢ¢c؈.jń‹Ā"ĒX/ƌdL#cÄØĘ6ņ„£ēhB6ŅńŽs‘£`ōˆĒ>ŅȎ~ ¤ZųB ņh$"CśÅ‘ŒŒdJ łFIZ,”ÜK&/ÉIqŻf“ å(ŹRR”xA„)WłUŚÅ•¬Œ%śŸhKYŚŅ?м„.yRĖ<īņ—#Ä!0‡¹“^ŹÅ˜Ä%2į²Ģdr²™n¦3%)M¶Ts0r^šĘāžęm3פиnńœ=” ŸNŽÄœčŒgyźL ĘP† ō¤ŪŁæö³ž œ„óY3(ņ3žD(@õ©N¦œš|I””LŹ`a”±h€‰L…ÉYĒ%Ł’ĮT`ėl»¬/yŃ«²Ŗuß`”Z@ĢbR³øl^ ²‚L4*Ę["'Ż“Ć-l1fWÕ5dbõj”ÖņT„Œ±®i’¹…)ČrśÓŗ^šo‚ŠŚŸ Ē'2Õg·Ģm”ŗŠ÷³šŚt[­E¬ūv&µ}ųLfA#¬}EśŌ¹rō“Ąµ.Ó¬ėA6‰j*XͶ±»vģ¾Į%o†Į6±™m¹gŌaŠ[×X˜$„z䖦Q5—M„ŪÖƞ‹²µ †ć­€ ¢8Öm'Ž­Å(G9én8®ēµ”o DōŻ ŗŖƒ\œč%·}üU°Ųµ°jåɹŁ:·@īpZU®ž®WhO¾ÄWR.»łĶp޳šLæĶ„zcEN&Øå,ō$÷8ŃņÖŖ“VįŻø š5°HØ>£•®tN±B1|ŃĆ:©ś…4Š[ŗR‹®ÓŅ#…iu{zk^ gÖÓ…ė@A=jp–ZĒ^Y­¤”‡*ś²Æ¶l§)żiZkÓµ“i¤9=TTӔյž!…½i{ÖŌ'M–‘œčĢ%Ē„Óζr¦¹¹\sūŪĪn6øĒ}$o“ūܦ~ŗ×ąŲX›ŻĢ®Ķ»į}byÓū޽¦%¾÷Pä ņūß·&%ĄŽJs|ßóćĮŽlÖ$œįH{xV$qQü*Æ8§2ī"{œć§ōøĘA>’‹|Y?łøM¾S•œåésłĮa¾j™€œęI²łĖS®ódā<£=ē÷Ļ/t”ó¼čæzؑ~o„3šéM?zC²©ķŖ#Ļсēņ°­+ėQv@ćŲī|·śģF;CCU³÷»Ņwz²gĶö²§ķé¾¹Ō"÷¼ć֙¦;Ćū^GĮ¦ķw»Ūg¾w`ÓńĒN<Ü!’Nx|»v¼ęĒNłĘkōŖź-Ԝ„µÕUéł]Ē¢RžƒŗA$µŹ<™u­ųįž5¬ ŒŖ½v'¹ąb1Ģ7X9eyǐ„<Ų}좱ŁÄqĻ}C;Ūē)ż5^”1.#ŒŚž¶c_•=’gXä—-ź·~­6^·‡o&H(Øb8~±Ó=ž•1Ļ¢ŚB&5öz\ 6™>H8]9ų~g€Q`WyG9~9Lف™tł‘mŌ‘‰$’ ي&iJ$id)©’!Ł’`“’“±$“F“«d“M…“ŅņC˜Ø,’:éAyT7ŽļAO¢6Œ@ł’Wr|'uįuɃ”¶Č”¬!•ČC•`HtII‡Xi”Ė֕ĢxC #Ū–Ėt—Ē`1'–:Fs¶¶Šóˆ’ĖhÕyu x)Nn‚s ŽuŁq\¹–røt —wpéx%byö&ŒQ2˜įĘ|'ų”¹˜˜})—÷˜Ji˜s§ŒyI™žÉ—‡ŁŒ٘Źč”ÉyČx]eE7,ɖ‘¹•S„˜²(„/™pw™y¢ŠŃc3)™~Y˜§fi¶œūhš„r©‰hω²Y,5ÄX‘Õ†ł5I ™œ– jŲ…ļØn³hU޳'}Ņ4ܲ]XnœĖ™-#ˆ™4(\”.å.Ņ/¬B/9¶“£iœŪ¹h?ł~¶I—ÕåU°•5¤b*éÄ2jx“æ¶(Œø˜b‰]s1U’eĘ «¹vj-¼¢7=tzõbĖ4@łé‰œ±©ƒž70h-dų„_ZGh–œI\­ ü%:ƒr(Š'f¤—ŗ©ŠĆ&¬BžƒŪAŸÕ™‹ÖĪ‰3‘ ’ųxe'ZĮu0u88@£*T”›—x£“&SUāV.*bÆ)œłž¬³/h°;hĄ's2wŸ’©‘‹ęƒĘ)4A%ĘQI³Ų2sƛn„ńi†ŖŸLŠhwzdŗÄ@OŒC9u 9Dv†F,éY›"õ\ߕTĢ…UƆ…Ēj³ēž|*Ą25€zšØ25ō’5żÕÅ÷.6ˆ”ŒY`šŠÅ8»„'‡Ś'ZҜŌ(œ~¢:°5|Ėu”¹śØ‹8–„ø‚†öHU Ę7ŻvĆ¢‹č,`b,T8Yj ­œśœ‹śœ ”Ä ~Ö©ŚbąqR&F˜® œśŠ§’/Į*ķy­eēUõź4ƒØ5­2/¤ŗ>]Z®Q€ĒʦOw™&Z˜lÅXp:¼#†ųźØc¬ģZ•0)גƩ€Ü£-„r„±ņÆ]uÊŖPچtų™“éqŁ޵±°¹-/ ±Ē¹‘²]ꐇš5Šhķł°4+±J«]•““É“OŗŽ#+ė °ŽŁr: K»ŸīŁŸčŗ™iƒ†^;uh™¶é¤jDé1g<ā¶· D·sŪ¶q ĘEū˜G›;˰śįa{mRū±æČ1°­9“Ģ•m±Ś‰·ó³Wtøē³$<ąåøoŃ·ZŪ ® `;ø%ܘø.įÆg+šÉi“Dø˜A¹Gt\„+P‹µ£¹<¹E3,i`…»o+»°³»‘F"k5­J¼Źd¬ā8É«¼éˆSz| ½„dHVZ½ÖJŽŌøuQ–Ū›Œ(¾‘¾™J¾–d¾Ų‰¾ék•ģŪ>źė#ļKMī;æmæźi戄æ[£æūN[æž;2ü++H ¹üEœµ ¬ĄÜĄ›²Ą¹ ĮV$Į­KĮZdĮ)ŠĮi¤ĮŖÉĮdäĮ Āc$Ā€KĀYdĀՈš6¾,œĮüĀćJĆ2Ü!* 5ŒkšĆåµĆ<U4üĆģqĆk*Ä@ģĆF¬9D,¶IÜ/K<Mģ6O,­Q,ĄA\ÅĀ1Ť‰ÅN|Å\üZ¼§_L2Ža ³cܔH|ĘēÅj¬e<±mŒĘšĒkœĘtŒ%oü°wĮ/Y”ĀĖC=ūN>™Ćy<µ'|¹ ™y_łĒŁVN?¤•lÜEl –;ĀūŠ˜k³½QȈūĮĻęAŠ‹«kČ.ģn“lø‰\™eT³{›œœ¹–7 ,OĘU©'V0S„©ē† ČŃMŌūŠ®"Æe2ƒ#ū\‡ā„ٲ„ŃjRtŖpģoÄ|¬\&p& S\WĆTÖM/}uԐmV•ŒŲ3ėeN“¬˜'rՄ06Õf³×ę:Ұ<Ó«}Ź]‘ÖEMŁśó@Ę]×“CO•ŠUć,ūŪ/Ø»ę:ƒb ¬=ĻŻĢŗ’MŽå%2ć(ž!ięE.ā+¬ąõĆB’~éÄQ鯭éĪēžĪ źd>ź¤œĪé§īĖ&¾ź‘¾å®¾é¦ėœ‘ź“^č³~ė™aėŗī!¼ŽėŸžéĄėB§”źĆÓ©aģĒĪćžģņėĪNé¹ķ¤;ķŌĪ»Ā~ķ­NģŚŲÜŽķZ^ŹąĪŠ>ī`lķęnĻčžīN.īģžķ„'õīēļņ^źō^慨īųžå¾ļßNʾļżīļŽīī"éĒ_Qś^?• Ńš3Nā‡~v‹<ēÓöĻ9ĻÄ)Čļ<ĻÆ¬Žµfåy®I@ŽĆ\žģ»ĢĖ7¾¦$ņĶ­“ŗĶķp-Oəłå–ž¬ƒ>óS”ņE¼ņØŒQt¢žüč¢ūä žóŚ[ه|ä¢>Į.ßĖ8ĪŽNŸå4/ō/ę’ńNõ:’ņ»āæ‹[oņ¬.õŸóØlõ\‹õeļwgõo~óH¾–ĘģUE¦Ģ5øm¦hąĶŪCVæéå̉ŌcbڶŪ%O÷ĪЊö-¹ī#Ń|÷_Ī“ed–Īb +Nb'ėŒÖHϳįż;Īc|vF­-ż±ļ·M/X0m÷øĻņqˆĻšr&ūlÜØ¢Ż„Õ,!6b«U~杶»‚±æ,cūśnn=Ļ%VL]5NÕ`ŅU f1+˜Žßé^ŸõSO˜ķ_ݲ4Č}ÖčĢTu5öĀgÉļök=žų.²…W€bŸ Ž>1™öD˜PįB†’ .šš`D‰%R|ˆ‘!ƒÄŠģ#ćc&3}œćą būRœōQ™˜ƒ3 “˜SēNž5^”X°§ĀŸC5šTéR¦MņDśt_Ō•Ä Ń,xõ`¦Iū”Ż˜˜£2• *£X–"¶m„*„ś–iŌz7 ĶZQĢGŽS•Õ»÷ ˜ærĘ k!ā© ß܇lä®.i(LÖoĶūNōH°°bŅI/–ų.éÓ„]æ†ż¶µé‡™øœÉõ`Œ¶Ń"ü z2ĀĂsż<¶ĪŁĖFĶŌoF‡bz·Œ” mļĄ…›æfü½gxź¢ ¶Ü—}„öŽ—’õŖR(dńĪ ĻF¬{µāśöż’_®?ę"fÆĀÄx¬.„ŠčJ#‰J즵̋Ānæ£Ņl"eTFŗ„ąƒĻBŌ*äϧ‡ŌŠ£ĪBTH9Į0Ā,=żĆ/5š4”KĄr'-BģųŒÜ §ų«I#’ėJ¹ķ¼2Å ĖcØJ&7dˆ‹ˆ˜É ų -eÄīJņRŽĒēŹ¬Æ–ōjG/"“JöŹōmG$Ѽ¼ «C6+E4ŃĆ\CŒ‹į&™¬Ä}V i ›dKIˆhŖö”“PKŲØbp:.7bĖ:Ļv܎¢˜š”4TśČŌSB+»F¼š¬€CÕZĪ­ŻŲ‚”ŹXu*LJ¾\JŌ,‘…6Z,•öGguHĮfQ¬v¼YÕŠi»%÷Vnzu[jĖe7ČöŽ…7^yŁj7ŌyļÅ7_}…m(“MĆ·^!óe”`Ž—^/a‡Æ=8ā@!–ųŪh)†p܊!²ų¾Ž7–VŁŅ0̹dI6Y¬nQ¾ōŁ”3ÖX¶_FTdÖhĘ9ēœX~™ē§xFĢg×¼ł\“yŻ£—ÖY蒝¶Õć˜M&ZiŽ™VsŠ¢±ęšfØ7žŚĶ¦Ś§‡ž¹ė’’–Zm·Į~[܋±Ķčl»ļĘ[į‹óę»oæ’֗9Ąå»p„G<ń¼WV¼7Ƈxį‡'¾xć"G>yå—g¾yēŸ‡>zé§§¾zėÆĒ>{ķ·ē¾{ļæ0 ;orafce-VERSION_4_14_4/doc/orafce_documentation/gif/DBMS_ALERT_flow.gif000066400000000000000000000115371501757153000253210ustar00rootroot00000000000000GIF89a”³p!łI,”³‡3f™Ģ’++3+f+™+Ģ+’UU3UfU™UĢU’€€3€f€™€Ģ€’ŖŖ3ŖfŖ™ŖĢŖ’ÕÕ3ÕfՙÕĢÕ’’’3’f’™’Ģ’’3333f3™3Ģ3’3+3+33+f3+™3+Ģ3+’3U3U33Uf3U™3UĢ3U’3€3€33€f3€™3€Ģ3€’3Ŗ3Ŗ33Ŗf3Ŗ™3ŖĢ3Ŗ’3Õ3Õ33Õf3ՙ3ÕĢ3Õ’3’3’33’f3’™3’Ģ3’’ff3fff™fĢf’f+f+3f+ff+™f+Ģf+’fUfU3fUffU™fUĢfU’f€f€3f€ff€™f€Ģf€’fŖfŖ3fŖffŖ™fŖĢfŖ’fÕfÕ3fÕffՙfÕĢfÕ’f’f’3f’ff’™f’Ģf’’™™3™f™™™Ģ™’™+™+3™+f™+™™+Ģ™+’™U™U3™Uf™U™™UĢ™U’™€™€3™€f™€™™€Ģ™€’™Ŗ™Ŗ3™Ŗf™Ŗ™™ŖĢ™Ŗ’™Õ™Õ3™Õf™Õ™™Õ̙Ւ™’™’3™’f™’™™’Ģ™’’ĢĢ3ĢfĢ™ĢĢĢ’Ģ+Ģ+3Ģ+fĢ+™Ģ+ĢĢ+’ĢUĢU3ĢUfĢU™ĢUĢĢU’̀̀3Ģ€fĢ€™Ģ€ĢĢ€’ĢŖĢŖ3ĢŖfĢŖ™ĢŖĢĢŖ’ĢÕĢÕ3ĢÕfĢՙĢÕĢĢÕ’Ģ’Ģ’3Ģ’fĢ’™Ģ’ĢĢ’’’’3’f’™’Ģ’’’+’+3’+f’+™’+Ģ’+’’U’U3’Uf’U™’UĢ’U’’€’€3’€f’€™’€Ģ’€’’Ŗ’Ŗ3’Ŗf’Ŗ™’ŖĢ’Ŗ’’Õ’Õ3’Õf’ՙ’ÕĢ’Õ’’’’’3’’f’’™’’Ģ’’’Ń÷ H° Įƒ*\Ȱ”Ƈ#JœH±¢Å‹3jÜȱ£Ē CŠI²¤É“(SŖ\ɲ„Ė—0cʜI³¦Ķ›8sźÜɳ§ĻŸ@ƒ J“ØŃ£H“*]Ź“©Ó§P£JJµŖÕ«X³jŻŹµ«×Æ`ÊK¶¬Ł³hÓŖ]˶­Ū·p欝K·®Ż»xóźŻĖ·Æßæ€ Lø°įƈ+^ĢøńWe"K¾ą`eŒ— ŽČäø3_ə%nŽŗbé}£‡Īć'ĪžcŪ›5Å×"q’«&yądߑ• ü YYk12UVvCLdŲ¤Ĉ!\ äČÖ3G6pƒŲpģĆe‹W@uā͟ēN¬7s瓁OƾļśåŽßŁ×~æ@Ūūˆ1É>ŽÖ›€WŁ ÕµVY= ØĢ !Xœo’)X”„ń”1 €ć…xÖ Ē„ mJHa€rö`„õ­h”y&‹õuųa‰wAZ‰T·biA Dao“ ±O’¤ķ ū0ƒQG„I‰œw4īĆ£ˆ`Še_uEzé$”Zz™ –O֘&•ČŃ·–QVÉeƒzµ™#} ™g\A}r‰jŹ@ Ac¦@Ż’ dŸwmś‡†‹ yę„cA(\ t>yhf“øųivŠ–Ųhv‘Aŗ\f“F'™„xe¦Ü@+Dg•]&€—A™™rZ§į>µ&·(¦Čzõē@­~©'™%mæ[ß°Åröe^·zyƒ@h(‰ßhX¢!FŽgÖC ⮪(b(I –sœ{—™›#gśś—ģæ)T|Ćy×oÆź6¹ä¹‰j蜺ŹKÆ@öf‡ī>óĖšité)„Æp]J&¢$¼ÜŠž‰Ü}šA‰+Ä`i #ū šĪ qĢĪ##ō}™ŻŁfXā×2/s3×|sĪ>ó µÕXCT5Y[g}Š]z-¶G]{¶µc§­öMŪ®ķöŪpĒ-÷Üt×m÷ŻbĮŠ÷Ž|ūUv߀ĪÖ߂nøX„®ųāXµĶWųćG.łä”Wnłå.鍳ęœļ”xē ‡~Ņ碗nzG¤Ÿ®śź9Īśė°Ē.ūģ“×n;Lšß®;ķ©ļīūę½’.<åĮoü㮯üņĢ7ļüóŠ–{ōNŌ^|õŲ«}}öÜg½}÷ąœ|ųä—ožłč§Æ>AÓÆļ>¦ßæ/ańĻo’n÷ē?Žųś÷ļ’’  cÓ¾p/õ; Ė’Ą:, ’| PśDĮ Zš‚Ģ 7ČĮö©pü“`T"HŠŠ|&”J O¾BŅ—* G†É†3¬ ™²Ćõ0‡1łaR„("±%F4J;Ā#Q!$™ÉP€sŻČU—1Śģó*,‚g%Kt¢š¶¶šÖčĢbŒ²bÆ,5««ql5µJIÅ軪łKS +ˆ±¦”£zxĢKÕń×iüõG”Ģ‘12¤ćRĘ+„cšJ õF‚L¢‰d³ž"U˜.J‡Šæi›Ē5'%Ģ‹«ś5¹ÉB1;Ü–ŅŗųʟܟŒ »K¹^¶ņ#v”ÕeŗU%čFīįŃD®Huµ s•‚Ćä/BFµ¦°ĢfÆ c„+óL‰Į·Ą8Ķ’‘ń”Aƒ@›uMŠzK™@žŌ'’4R‰/Ėułŗ}śÄŸ‡I$?VCVt‘oØazPŠ0T'LD ‘‰ŽÄ¢€‘&Eq‚Qnt~„IH?*9šō¤(M©JAS8’T.#Ż[L_Ś“™ŽĶ¦4…(÷pšSŽrO£=M OƒJŃ”õ F•›KJž2u6NX}*]’7ŖJu—?½ź\¬ŖU1rµ«GüźŚ– VÄEµ¬m«öŠźµ¦Ķ­lfVćŗøŅUv½«óš5²źU+|ÅZ`’jš³–k†=¬Y³TÅNe°ŽR½d# Rīł•²œĢŽd1Ū³Ärv+›żWh?k™¹’–+£=młR«ŚZ¶µ õ,lK(ŪŁf{¬mmnĆŌXŪe·¾pƒū¼į†č²Ä%ŠqdzŸ\ÅzR=ĀMnT“(™ŽÖ®¹Ī­gõ¬+]žÄŒ»Ż%©}ŒŽø ¼“Cny{Ņ0Ķ®÷)łÄ­mWJßśŚ÷¾ųĶļ/…]źõw)’eŪ|ēą÷B³Ŗ."“„^ŗ)é€åį™TxyVn²2|<Ÿµj_Öē11DŻČG9Š% tšCĮźˆaķ­ˆĆ¶ >•ˆĘĘĢ¢$ā‹& ½’`õY&ńŸxż'ŸŹ02ÄILŌjķ*ĻÅ ’eBə@²’»Uš$ ģ:”ōĶy<—ąŲų¬擣qNE+ŽRŹL>ęqL™Göµę8jfŌĶ’<ĻĢč¬Ķb¾±Ó¾… –¹3UĖb€Œāq†ĖŽś’“*ƒļ°‰c­R“YFčGĆYXŽ^r«ŗµå„Ć/ip\«ÖØsķ VĢņµĄ‰Ę}£ĒKŹ„ž®ł"U2@…rµ®c-!^‡y ²žÓ®iż‚~>H&¦Ķ™$_Yh“¹Õ-%ķ¢"7 ›Ė¢vµweE°½ČV”)ń’ $bvÕ.÷;ƒJW '“ń«åy&E9²M·Jι Āg[×ŪRńŹ·ÓtĶoO}¬Dū^8ü=ågó7ڙΔN¼b.ų§[mÄ'³£Sń A‡D’OĒ?.«ŽēĢč®é1nę8­Ü1Ą¼āLIčB蔬ŁT=į„š‹ēŃyy†kڬ†ß#?õ”½ą©7FŽ?ĮśJTĶV­ĖY^×]ŲÉ vš»mģ£3ūŚŠn w•ķ>µ:cōK÷ŗŪżī+•ū¼³Ē^u½ĆīŸń{QŗY=ĄÕšzA|NĆF=· ^%q|üQ'.ł§ąžŃė{åõ‰yč)ž¦+ ø7OĶŚ’ž&eŚīé’ŁłÕoōó®Ēģķ¢łŲ$õ£·ż©[ļ¼Ł”š¹ˆ×żEE=Ē æ#—?žė•æŃ Ķyµg>G(/_éĻ$¼ožļ_O|Ļ[&Īgģ]šNžņ_rŪ×>\ŅOĶē[]ŽģĻśk”šPČ%æśu?śMßÖõ£ßżĢĆvś÷8ńĘ[õ‡<xhdō/';ęluFc“›—hldFļ”F9āg~¶e6’U€5µ€Ź}]‘h$(j¢Ʊ,yhQ÷uŒsś¢~ōw(7Ius£v¶n„÷8įē$“;†a” ™ąKXmKH Äą„L…õń„MX…cdńr.ę¢$[ˆ1ZØ/] b†ē2w¦qhč%jŲ†ių†Ž‚3 1&č₱lz’ ⢠ŻGv3Ø(ø6Ź…Čdˆõp…ŠH…‹Č…œ/ź$‰õ@‰–.•ˆ‰—8‰˜h'ņ‰¢ФH£hŠŌa2Ŗ«h“ńŠQ4Óń-$’†“Ų†·h‹Ø‹Kā!Ć$I2 ¢$Įų‹Äč‹ĆŲ‹Ā’Č$‡H ČdkϘ ĻŲĀ!ĀAĪxķA8³*TD tretbn%'ƒ‹!Ōnę"ń2 ʰŽöbbóņHųhõxś˜ā4/ t YyŪŌ1ųʐĘ!Nlų-³‘9‘ ‘²Œł‹™‘ł‘‰Č$#YĻX’(y’*I’ĻųXIØL gr¤ ³+‡f ·ƒęØ8ģBA ’$kā!Ņ(”õA ŠRˆI‰”G¹”NŁ”P©”PIS‰AB'óHęĮe•*‘Ę“IzČ8”Ēwćg~˜‰™ˆß÷Œw˜Wé™‚š%qŖGšń†šæō™ŖVóך*a˜Ž›ś4š“I6$Ųa·)G¦µ›%1„¾9CŌœ,dšŌƒ—ÄÉH¶™œœĮǜ 1œĻ aœÅG!!–ZŲéι{ՇŠēѝ³)ž”iž!›Å„žēŁ›īi¬ŸśƒžōIģž÷)ŸĖ¹Ÿ1Ÿ½ēŸ…å^:䳌<Ŗ ąé—%ŠÖYž-ZZ£q¢Ģ“ Ū”4ŖY$0;š=1怜£ń£?¤ś£’q¤Hś£h°_×’I¤čF^Tš=>z„`’™\Ś„^š_Zjq€cŸŹYdD>DZgświśYk*šĢ„¦†ó¦ĮE§¦6į3ĻJĮ"„Č&°‘qŅb&EČÄ4Ģ"LŠE؀dØ-ŲL`™§xw2š!Ž4O+°cF£©Ćń!ńum ŅdĆr‡:%—"0"kަ§J¦3ød©qź¦ŹY“`YE$雺·)qkī&¬¹,õį«;¬Nc¬,3–+rIuøzžādåxLŽøs¢GŚB’xĖGŁjŪŗ2Žśk‚K²L“śnmj¦įNąAÆ«ĀgĄR·Vó­H J¢‡óAĄ¶§ĖRÅįj½±Æ&Ā„’Ŗ$özd³¶ƒßäc·*Æ”'žMMājM¢°S­ŃÆŲdŖ7¢Kė–‹¦Æø–!«*8ČRtVJ:źQ—j«™r•.ųÖ+: ³©¶ö-ž³„„³,Ö³õH©ÄĀ,ršZ³4kŻ‚rgõp!­Ŗ£.Īō¬žNßņMV‹µĶę[+0ß4mŽrƒnŁgavPµńG)ņ\ŻÖ$ž1^¼Ń%v‹¬u2v«0ŽHEʤKvū%„fcōT]˜Ŗ`Õ*8vڳ˜¹äT±“;§ńz¹·hŗ¹œ §ū¹2A¹µi¹”Eŗ¼iŗ‘õ„¬Ūŗ®«A™+ŗ(»“[»¶{»ø[¹k<Ø»»·2å»u¼Ā;¼Ä[¼Ę¢Ēk;½›¼Ƽ¼ć¼Š½Ņ;½%ŗ¼Ō„×{:֛½ÓʽŽū½1ą¾¶·½āk³å‹9ä{¾p«¾ģŪ¾īū¾Ŗ•¾š‹Uó[Rõkæ÷›æś»æü;PņŪæZ3Ąs)Ą˜KĄ|ĄœĄėóæ ¬ ÜĄ˜Į²'Į\Į|Į°óĄŒ” 7ÜĮ ńĮ /<Ā$\Ā&ĢĮ'ģ5"œĀ<ĒĀV³Ā.Ć2<Ć Ć.lĆ,ŒĆ)¬Ć4ÜĆ>üĆåĖĆ-&,Ä%LÄ$lÄ@œÄJ¼ÄÄ‹Ä ģÄ Å,ÅL\ÅV|ÅxJŬÅĢÅģÅ(XĘb<Ę ĘlĘŒĘ ¬ĘdÜĘnüĘ»ÉĘ ,ĒLĒ5 ĒxœĒz/¼Ē(ĢĒåĒōȄaĒ‚\Ȇ|Čń‹ČAČĢČģȊɒ<ÉWÉżkÉü›„”¼ÉœÜɞüɠʢ<ʤ\ŹD;orafce-VERSION_4_14_4/doc/orafce_documentation/gif/DBMS_ASSERT.gif000066400000000000000000000204311501757153000244150ustar00rootroot00000000000000GIF89a%p!łO,%‡3f™Ģ’++3+f+™+Ģ+’UU3UfU™UĢU’€€3€f€™€Ģ€’ŖŖ3ŖfŖ™ŖĢŖ’ÕÕ3ÕfՙÕĢÕ’’’3’f’™’Ģ’’3333f3™3Ģ3’3+3+33+f3+™3+Ģ3+’3U3U33Uf3U™3UĢ3U’3€3€33€f3€™3€Ģ3€’3Ŗ3Ŗ33Ŗf3Ŗ™3ŖĢ3Ŗ’3Õ3Õ33Õf3ՙ3ÕĢ3Õ’3’3’33’f3’™3’Ģ3’’ff3fff™fĢf’f+f+3f+ff+™f+Ģf+’fUfU3fUffU™fUĢfU’f€f€3f€ff€™f€Ģf€’fŖfŖ3fŖffŖ™fŖĢfŖ’fÕfÕ3fÕffՙfÕĢfÕ’f’f’3f’ff’™f’Ģf’’™™3™f™™™Ģ™’™+™+3™+f™+™™+Ģ™+’™U™U3™Uf™U™™UĢ™U’™€™€3™€f™€™™€Ģ™€’™Ŗ™Ŗ3™Ŗf™Ŗ™™ŖĢ™Ŗ’™Õ™Õ3™Õf™Õ™™Õ̙Ւ™’™’3™’f™’™™’Ģ™’’ĢĢ3ĢfĢ™ĢĢĢ’Ģ+Ģ+3Ģ+fĢ+™Ģ+ĢĢ+’ĢUĢU3ĢUfĢU™ĢUĢĢU’̀̀3Ģ€fĢ€™Ģ€ĢĢ€’ĢŖĢŖ3ĢŖfĢŖ™ĢŖĢĢŖ’ĢÕĢÕ3ĢÕfĢՙĢÕĢĢÕ’Ģ’Ģ’3Ģ’fĢ’™Ģ’ĢĢ’’’’3’f’™’Ģ’’’+’+3’+f’+™’+Ģ’+’’U’U3’Uf’U™’UĢ’U’’€’€3’€f’€™’€Ģ’€’’Ŗ’Ŗ3’Ŗf’Ŗ™’ŖĢ’Ŗ’’Õ’Õ3’Õf’ՙ’ÕĢ’Õ’’’’’3’’f’’™’’Ģ’’’Ø÷ H° Įƒ*\Ȱ”Ƈ#JœH±¢Å‹3jÜȱ£Ē CŠI²¤É“(SŖ\ɲ„Ė—0cʜI³¦Ķ›8sźÜɳ§ĻŸ@ƒ J“ØŃ£H“*]Ź“©Ó§P£JJµŖÕ«X³jŻŹµ«×Æ`ÊK¶¬Ł³hÓŖ]˶­Ū·p欝K·®Ż»xóźŻĖ·Æßæ€ Lø°įƈ+^Ģø±ćǐ#KžL¹²å˘3kŽĢ¹³ēĻ C‹Mŗ“éÓØS«^Ķŗµė×°cĖžM»¶ķŪøsėŽĶ»·ļߥƒ N¼øńćČ[ĒĄ¼¹óēŠ£KŸN½ŗõėŲ³kßĪŻzŒ‡Ė»_’Ž0¼ųóčÓ7'ÆŠ¼zčģ“Ėąv}‡÷?ę7ø’j’ƒ’mą|h}! ø‚R1(ƒAX’ ŖVį‚ &t!Sn‘‡biŽˆŸ†[u˜aˆ,dāh%®h V*‚ōb‹æŻZŒ6¢H#C:*$Ž»11 f22łeҜ’ū0I”9É”7<“Ļ)s•ÕS_–Īmyä‚Ϲče”C¢ÄcB™LB‘‚ސTÕcg„D⨠˜K2GŠ}b°’Zå ­€†¢UŲ4ūUj„9¹¤>Ō›1:§)#źQx”‰|öÉ¢‘*ch=˜.i›‰é)¤ø ¤+CæZ@`fłm¹§±=jPNDēBOryƒ¬7ÄTŖüµź’ź„°v‹†’ŗŹZŠ ^ī‡)1·t”ĮÖŗ¼¾Z*½‘fŹŽwb ‰/OĪŌīØ1ˆ†œ¢¤“kÅmA WŌę·µż ]ÆßaŗjA׊ ͱQ²J“÷šń>b–©į°Éėq½iréÜ@“bx)ĀD=LPĶS ®3®ŖėĶj&Jl}T»‹h¼2 &˜’&ŹdĆd ¶NÄ®·Ż.„é t­QJ”I§Ņ:½Ś{Ō%h½A[•Ä(£§@ Šņžū›_ĪQzr¤“?ž˜š¢Ģ“b²ģÓvķEŲ7Bļ#5Ī=z­B„KĖ÷ė°Ē.ūģ“GŪÜśA]Š×‚šNs‹±ē>7ˆœł‚x*”©«üŒÅ`g&Ń*cēÄ&„oÓ'“@Кk=Ŗ@*1Į!b_Y ŠwdńsJīwü$Ķ1Ł)żĄOłd®łÉ¼?€e¢”ēśųynA“ރ¬“(!$C_Ū"ęŲ‰I1h]ŅŹ÷3‰Ø6œĢ–zdķK>ėŽØ'¼åķUĘ·kGBH’5G†f1a•†–Bča„nõHDh"Bf„¹+įĪ’čC’p‰OƒĶ pØ#VF‡™Ö uÅYŃ1ģ#aŖč-f„nłbkŌȘ|BŒ $£ū:h4b„{‹ Ėx v‘W?|"a(E*¦± !¢ÉB8zQ†¼cķ&IÉJZr:ō™¤†.ÉÉģI“„|ĶõFŹ"é±a„L%"]ó.UŗR‰° ć+gYÄSŅņ–®Į£bF‰Ė^šF—v‰i„/‡I"Hó˜¢&bx‰ĢffF™‡a¦3§IhfŠŌ̦e¬YYjó›į&aÜĪr:Fœƒ‘¦9×9t ›ģŒgaÜoŹóž”'`ȉĻ~öEŸQ§?*€śžM(] Ś{*tž ,X''ŹI‡’éń=Œ"¹øP‹Ę•m§ŒšXP¾”!©#]t†śŃ5M)`6JĒøø4‘•)ahŖĀŗÜTŹ©NżĀS’ŚŌ¤¬ŒäPóRŌ vT(?ĶKL—ŗ—¦²‚B-KT9ŖŒR•Ø#ujA !D²lµ¦ŖčWķbU@$kVśŻMĒ*+ķIVbøÕŪŠ©½žźvĶÉY{šŌµĪÅ: Ŗœä4 ņp C²RRŃ2Až šnD#£(+4<Šiŗāģ>,{“é °&ƒ­ĖT »–pżŃ­#S’Öļ[UvB±Xu4Ä% `Ž02œ謩„ ?Yū×’H°)1Ųc.Ž*ć`™°!æ¼Ä<‚ģõJy›2“k\£Ņ$¹sQ+ssČÕ¶w ·Óco0‰ģ6ā‚“"OֈuŖ-‰vUŻŻÉq’Ćõ6÷½UDštÄŻū !õĀFȤ‘§VÅ3ŃG(9Ķ–MYÉ€ŃfL·Å¹Wåtķ†0™ŽU` ZļīF³ümXh„²ąÕzW^±Ś½rY®‰Õ‚ā‘eĮö1jm9äÖ"9ZT2\F,Ų7™ČH¾c–OlŽ™9.«•$EĒLę󡄒›,³ššāēvŁ-TĘODa»!»÷Šg+©bǶnϧo4Ūž ÓkĻ/ń³Õ™eE/ś°‚n󄜔޹šy^)”ŲČ hĖl‰3N5żeø„łČˆv‰¢K}ČN°vBR³¬_é=·ZҬ±ó§SŻ’bU§ˆĶµ¢žkC£Ӊö®ĪlŲxØ­¬v‹„wlU+›ŲU±ć{čęMēZ©ƒÖ_—*Ģ+F Yvū_٘c¦.}éP€$.“†÷66¹;%īt_XėĄŻ©ŁÆy6ĻŽm’kŌč:Į5å1•)%ŠJ¢E`¼åØMįmCĖҲ{éG¹ąłŪ]=“iü¹iŌ«b£ĀĶP½"–\!…nĄy»`¶ZŃ.,4īVełīųA"˜r\»čJ)»V ņ:rPēQŲh}éĶU3m„æ;äõ!Y¹“·‡cM[¤•—ČÆ®õū˜«¾ VR&ŲE« ';ź£~so “3¬(ŚfÉ)enO=5§÷±Ņ”(;aj<$ZÜ@6¾ŲžŁ†Z4ü}h,>øńö{_‰ŪĖ#ųcoE#ʔʐ²ĀŌļŁwŃ=Æ÷9õ?æŖY¹PŲuxS9¼ˆ‹ķ<’ŻGö÷q§x[«|ĻZA –Ųč̇YŪĻŲ;¾ō§OżÕ-Vł¶+¤¦½-/ĮXHŖlĆ4\ó˜CīRłńžhƛ ]ģQõ9曄n­žļ’eÕwrT?)„i×{€}-×<°W)“÷;%Ā8r<|Å+gc€Rh' †5šf{x›×o]f1ŗG5ūÕtDb0}uFGuąV€āęń“)ł? ūš]('3}G@š9ņcy£)Ågo0Øhćā‚wcų-£Gz®Ā §rŃÖ,€q„Ķcz$§rOQ…‘” ŖG…%Öm?ų9ō§*‰'IG^č`NĮ‚”q…÷—…kHm”Ö ßmLf†rųvÆÅzŁö‡Ć‡j!L‚؇„Ųˆč‡Q˜ˆe8iÕĘqŪ‰Q”ˆēD‰u•‰”…|ø‚SĮ‰”艢”†®S}¬8fgęzƒŅŠ–ō‡°Ø‰¦QuW–‹ż÷mŗŲ‹t“S¾ŒŸˆĀXŒ¦}ʘŒUK-،Īh„ĄųŒŅø‡i„ŠÓx xøˆÜ(¦x×ā8ŠÅ6ŽęčÄxŽźhud¬”‚ėųŽXxĶōw§‡õ˜o8ų؏śųfĮˆž8öøróHõeяłŽ I ِźųc!ِ)įx‘š˜‘a‘)Ž  ’Ü8’_a‘&ł•ø’,’ł‰.9(é%“Ļ8“]”’U$‹Ś‘Oµų <‰fŌņ“Ɂ“\Q“]8Œ`•‰FIŠKHpälצ†KYˆ¶ų…whéSDti&XU×֔*ēhĒ!–Y±“c‰_©¾¶E©„ņa–Œ‰TłOałkIɎQpֈzJi—L‰—NČ!—œVˆäögę&ƒąE„ĢįB·Ęś™nų”Ļņoy¹~W”±a]IŽ‘B@Ub(q€0ū”[ ‰Ā…H¶!c…Oö„*E–9w5·›īāŽpŁR Atuči±ø€I‡Wö·-Yy#†ÉVEŌ—µ©?Dćp_Ē1kvŁ(Ä9=č•`éqńČ ö8FC›g˜•cˆžœ’élDł{hZ‰7Eü×JF” ŠX‘|s²|æÕ|Ƃ;Ic}'‡} ŗ”śźŁˆņ•9ÉySˆ!ņ™õ‰É  bH³®yŒY€y ©ø}Ž3yłqšU²£rҁZ)™ƒIœH%ŠB‚§õ—p—„„Y–Ŗ–A/Ē#c ų‚ē†ŽUyLZ£ą©cLā„äƝ%  …Ł™Ÿ©—噢Dæi˜hōŸdź¤R™˜p҆R·Ņlt§"ņœt*£B˜nI¤Aŗ—¹4•Ķ’OwYØvb¦JbY „zŗy÷›e:§VY—ƒŗž‚é5ŗ©Æ”št¹Ø•JŸ—-Ŗ™Ś¤źli©ŖJŖ¦–j™XɝP©°į™6Ņ”˜DTź«°óI°J‰j“ž\؜UaŖČJŹŹg±Ś¬ėų¬SaҚE­×jŽŌ*Ģŗ­ēŲ­›®™Žä*’Oz®čźlŪ©®¾(®PÆī*§„Ś®óš‹ņ ‡ŚzÆ7©GgʯΘÆMa2{’|±ń­°éš°Ź(°L” kX‹©;ĖŖöZ±»°Œ›۱"›Œ‹ÖZ²Åx²Ø²Æ*Ūd,k!ū²0˱Y$¬8›}ͬ9«ÄJ;-³E± œžZ«†ČgY™«ó!“k‰¢;՟„Źløŗ™¤Źß’“O+Ŗl)µ źØ}Č“éŁ7`N;œHčՖT;¤hk›)A?¬r¶1³VĖØG+«I[ŠK{·ÆŠd«‡å²šŠ·Øśµm˵~ZĄ”%ØD·‘²zŪ£‰&’s5@é“Õ@Ä£%e•Ņ0B^ŗyoó—·©ĒŸW'˜‰`‡ć·Œ{ō\NÉV„™šWŗŠ2vǃSˆŸ ×?õ C³1‡‰‡Ėy÷ ö‹™©Ao‹Ø!!+1 ­ūvŪ¦,({$@Ų–8½‰¹B’›±%"ó„^Rõv•#±¶Įé›q¶ÕbAŲ£„µœ°K_TAņ›½y µ2’]rB¼ü³’”oę~äbvvA Øvšr¢ŁćµEūwƒš7ø0ä9«ov>£JÆ!·UŪīѳ²6‡ļ™*£()Ó@wu Q+3y0Ę8Ź`]č¹Fč« ńŗś«s8ŗą³Ÿtƒ”A£„ĀLÜĕ}ܼГ9Ģ1H²ōUqaSVlĆæāqó(s»·hĮ»Ćœ)^…·µŌXppZ™cģ‚§‚[Rˆ,mēxł9äIZt÷Ćéē$ŠÄćā~ˆY¢Ųckš¤p,€łw8l ½Y'…ū·"QA”IĘvA“”rā½c³Óõ1ņ»§Ņ¼cÕóiøx‰œæŠKŠ"8āĆČf,wņŪ·±k1SQ¬ĖÓ{Ę•Ūƒ2Ó`ó)3ńŃ9„)‰WƒĢaŽY¹eŒŗ“Ė™i0^ DǷ܇hl¬5DÄulSl|Į€FĶ÷‚æ!ŖDśĘ|µ&ń6óµOŹo­[§¤ĆĶ×ĢĪęɕ¼Ė)D#ōĖŌRĪa›ŖĖˆøsiØbk£*į$?gø“;S݌¦ćL±%ģŖĶ­Š‡µčŅĶŖĄĀ–lĻū„е Ņ°ĢŠ‡Ėļ,ĀŪvŖ.żcšø½æĆaŠĘŅ«j“Ė›¶nzŅĮÜ“6+:N,¬gȳK :CY¬[É©4Ū‹>M©UmՀšÕŗxÕ ĶÕWęÕ8ĮÉ`ķObżŅe=d]gmŪ›ÖTµÖØu»n=TpMm=×:U×^†×&¦×21Å|ĶZ~-brŲ5ŲgöƆ-Sˆżˆ‹żÖęśŲŒŌ’żP­j@]ŁŌtŁŹ«Ły}°™ķŁĶÄŁ,A°¢=Ł’»ŖŲ§m֔½ŚųDŚ+q×®O°m„…=ŪėTŪ)ŲņŌ¾MQ±&ÕüńŪ=Õ@ ĪzWĻ%ē¶,źĻ Šü Ś6-E¶šī;°F½øŃ «ÓŌlŪŠęœŻĄ”Ūn¢ŚķŻ9 ŽĻ}Ž=ŻŚ(MŻĢ ©%Ļ; Żķ “G2ĄšÆā=Ó)ÜŻMÕėĶ„ĪŻŅö-ä큔‰‹éy¼ėyTņš—¹7d¹Ņüj?8̉ŗƒ"ŗCÓ¾ŠŃ࣪oŖŪĻaĖŹ™—@ĢŽ īŽGŻYÕĄŅ¹[’3Š,cW)‘„Ļ™¼ ÷} Į%gć‘r¼9¾döØĪ”›cŗ‹ĢĻ’ķ’ ĪĖ > Ęb.ų’,UüĢÆ7,’į|—Óeµa“Z.!/÷gč{5”Ǿŗ‰Ö}xžņ­Éõ J—-Oė”ß<Õ· ¢(„.Ę,ßq0ž§+’Raƒ,!¦ēS¢-‚! ,äćĮŌc:|SÕ=ßl>1w·ēĀ1ŃktÜqČZ#9-C ¢Œ3ä‰)/¬Ķø2ė‚ņ7ŠuĢį%Ņ‹M¦=ĆĮēåt%8¬Ćm×ĀÆ(”Ķ£ā?«³ļ64”7wź ”ÄBÜŲŽŠ0Žžü§[Ćž3ƒ/ˆęĀ.i² 7%ø ʤ»"5Į§¹ C4‰¢éH›üm‹jĢž$>Ķ“œÉ’÷Ļ刓µ¢ Ä@V±Šcš9'ŸÆ'äĒĒć'D L2f~bŽĮ"8ƒLoķW3ĘönmQ×ā„Ž¢;ÉL.ēoFÉ.U^!$†¢Ņ˜h0<1š(k·$×C‰ž¼ä;W*Ŗ8˜•9 !Ź£ŹKĀŹ¢Ü|ż­y¶™³>ūĒģślØtą]Ói{Y»nƒ8(7.Ā@ģ&ėaž.=8ŸiĘ{ ¤¾<Ģž£)“'„Š yÖ\ĮęY÷ßÉ|xĪ&Ū¦OŸą.æķuK†jšĶ ¶¤čĪ’NÓzwåEqĻ[ łćjŅŪČEĶā)_ą/Ną½Jšß܈Ō‹ąO·õś]ß1‡ÆÓį½Ń÷żē¦æÜū=æ‡S.ūŗZÆīś«’š.ś¶ŌÜżśšū«Ūūœžūq¾ģ¼½“ŁŽü³ÜØ>ÜĪÆģžüČ]śøP/O²żå“żļ{ŪŽ’Mą/Ė?ž÷TžŠŠžß/ŻģßOźo#ā’žĪ’qžōoNöŸūłL`ß@‚ D˜PįB† >„Qāă+”QĘQćFŽ=~RäH’%MžD™RåŹˆY¾„s!h2mŽÄ™SēNž=}ž:ŅeP¢E ØgTéR¦M>…µčP©USRµšUėV®]½~5‰ŠģXˆ1.’E›VķZ¶mcŠu»n\ŗuķŽÅėunŽ®ĪņXš`Ā*÷ŽzńbʍVüŲØ¤’-_Ɯ™kdĶ=9wZō蒟IĖō{ZõjÖ­!šv}5ölڵCƶ=Ņbn޽}óÅż»#Mįōļ‹<%eåĶ?śCé \Ēž]ūvīŻ½^üxņå±75Ÿ^azöķŻwų^ütōōEīY]“~˜üīõ/±ųJ³o© <Ŗ¦üŠ;Š0jŠ)Ī"<ˆB…’ŗŠ#ęΰDČC„&1ßDœND¤¬‹D’Z4Q#›Ć¤ ŪŃ£׋qĄkŒŽHŌ‘Įś†„0HėJ4R§CŹE%™ś±IŗdÄ0Jž¦4NřĪ#Hģb +ĢŌN3o  ŖRKČLbŽ:ź¬7ć\s»æPs#Å2A##C+.BÓF/æ|t"³¬„0“2i4“”äÜĒĢ‚<ŻG,hVHt †RFŒB×CUU "• S O,j”¢CÕŖE ŹdG#Ķ©ÖßÄŌ’Ö‹čHŒLźQ³Søć¢T‡ŖĪõ”É[n‚†ZkÅ’Z›Œ5t!g3ŚĀėž½īnÅ0@Ą'd—Ųbõ}ķOŗ!ׁ¾=(܂ĀMjZe,Ķ„—¾mÄR„<]×ÜNќDbæ&†2ƒQ[2Y]ńMH aC…&ć}4õ7ä™Ō•xd~ĻYHėÄī"b“­p;iµ“6Õ}Ŗu‰Š‹ń…óc£æ5Sh1ž9;–Š•9!'j÷ 3Wś"“«śX®±®ä²Ē”Æ;źī¼z ‹Ó\6Ä”÷AŌ¤Ör4,¾›LćcŖÓ&¼<…ˆi»„ļ’s٤ä>…‚e·pĖ/Ēė[’ą8hpż‰Ęk›ā> @ 3­TKMTą©ü6·Ąq÷Ą{Eś‚Õż„¦Jćm~B¹9ćō•”+Hģś„;בæ‡=žD=Bl˳ƒoœn‡†Ü•«»FHŃŪŽį]ŖxG[ae—·kOOr=Ōs“­„µ¾„dÄ*®õīTÜP@c Ń'ÆSLÄģ[Q_Øf|ė³¢ś‰˜˜Kź'gśĘ żą¹‹-X…šŹŗ3ØņgÓ¢i;ń.ˆ½™5 ģ8ŒhŁŃ!Uh·ŪlŠŃ¦µvm;Ā R!ä‚0 9ķntgWÉó6¶Sqķl4÷Ö₤ėm' ņO ‰6złfFA¾éŻž±ćd©0Ø?Īņ‹–ĶĢ_m.b+ū[ž?O½vłłZOķW8K²čg;ŗ“l ts3}č;ŗČµ>u„3-9nÖQõõ;–›č^ĒyÓó(vØŁķooOP‘ź.ø§’:Be{Žõ¾w¾÷Żļ|ą?xĀŽš‡G|āæxĘ7Žń‡|ä%?yŹWŽņ—Ē|ę5æyĪwŽóŸ}čE?zŅ—Žō§G}źC;orafce-VERSION_4_14_4/doc/orafce_documentation/gif/DBMS_OUTPUT.gif000066400000000000000000000165071501757153000244650ustar00rootroot00000000000000GIF89a€÷3f™Ģ’++3+f+™+Ģ+’UU3UfU™UĢU’€€3€f€™€Ģ€’ŖŖ3ŖfŖ™ŖĢŖ’ÕÕ3ÕfՙÕĢÕ’’’3’f’™’Ģ’’3333f3™3Ģ3’3+3+33+f3+™3+Ģ3+’3U3U33Uf3U™3UĢ3U’3€3€33€f3€™3€Ģ3€’3Ŗ3Ŗ33Ŗf3Ŗ™3ŖĢ3Ŗ’3Õ3Õ33Õf3ՙ3ÕĢ3Õ’3’3’33’f3’™3’Ģ3’’ff3fff™fĢf’f+f+3f+ff+™f+Ģf+’fUfU3fUffU™fUĢfU’f€f€3f€ff€™f€Ģf€’fŖfŖ3fŖffŖ™fŖĢfŖ’fÕfÕ3fÕffՙfÕĢfÕ’f’f’3f’ff’™f’Ģf’’™™3™f™™™Ģ™’™+™+3™+f™+™™+Ģ™+’™U™U3™Uf™U™™UĢ™U’™€™€3™€f™€™™€Ģ™€’™Ŗ™Ŗ3™Ŗf™Ŗ™™ŖĢ™Ŗ’™Õ™Õ3™Õf™Õ™™Õ̙Ւ™’™’3™’f™’™™’Ģ™’’ĢĢ3ĢfĢ™ĢĢĢ’Ģ+Ģ+3Ģ+fĢ+™Ģ+ĢĢ+’ĢUĢU3ĢUfĢU™ĢUĢĢU’̀̀3Ģ€fĢ€™Ģ€ĢĢ€’ĢŖĢŖ3ĢŖfĢŖ™ĢŖĢĢŖ’ĢÕĢÕ3ĢÕfĢՙĢÕĢĢÕ’Ģ’Ģ’3Ģ’fĢ’™Ģ’ĢĢ’’’’3’f’™’Ģ’’’+’+3’+f’+™’+Ģ’+’’U’U3’Uf’U™’UĢ’U’’€’€3’€f’€™’€Ģ’€’’Ŗ’Ŗ3’Ŗf’Ŗ™’ŖĢ’Ŗ’’Õ’Õ3’Õf’ՙ’ÕĢ’Õ’’’’’3’’f’’™’’Ģ’’’!łü,€’÷ H° Įƒ*\Ȱ”Ƈ#JœH±¢Å‹3jÜȱ£Ē CŠI²¤É“(SŖ\ɲ„Ė—0cʜI³¦Ķ›8sźÜɳ§ĻŸ@ƒ J“ØŃ£H“*]Ź“©Ó§P£JJµŖÕ«X³jŻŹµ«×Æ=oK¶¬Ł³hÓŖ]˶­Ū·pÓŽK·®Ż‹īrĢ«·Æßæł®(x°įĆY #~Øx±ćĒKCN(y²åĖ=+cØy³ēĻ/;o ŗ“i’¤/§>ĶŗuĘĪŹb4œ mŁe†!vuµėߥ+Ģ”©aŽ(¾/ӊ­¾ƒKŸ^°sڵ@ŁŁ}ϵ+rS6—XYę™ĘŹVŗūą³ļ‹QœüĄ¹™&5׿/ ŽƒAŹlēœrĢ!ÕŽ{ ²¦1s ”IĶI"1ŠQœ†ysi$›x®§`ƒ(¢ØqMbaˆ””É>»Ń A׌@öńhVģ’„(¤{šŃĒŁŽįķóß>sŁēA™Ž“šČŌ‚Cfł˜f+ą£l=ĘP˜ėŻ0``Å5ŁXwū˜·cRXj)'Wq!¤LéÉ7ßX“9asFVqÄP(FYgz'Nq„5ē£T­¶Øa“N é„:Iś[„˜vz„C–Ę©§¤„©k£–ŖŖP§¶–źŖ°fꦅšå ęŖė®¼äMōŖÖƵź`­ į*,ZÄŖ–­!A[E’.kķµŲb‹ģBŅāZ·DŪ‘øJR+e ‘K®VėÕīkÅłīt¤©ūķ³™Ękī¹Õ«ļg󬚓½ _ŗ’zfšN Äļ;®ĆüzĖmĀ£į;0ÅÅFlæ5,•fŠ’5^ŽœÄę>!“¬Xʼi’lj–_Ģk\īÄ Y™1Ą QIąX ¦Ģ‰ żŸĻ>ŗsDA£ó¬Ū,±BżI3Ļčn aŅ…1b`yżIcKO}Sg^­¶Ō'ŌlCe;rcOJRśģćō>v£,“šy­t¾ m·öĪRßLõBh$(Ö„|•ėń5ɀ[K6AɘeųĖ„Gįį'Ž6B33’ż•¶vŅĶW&hP)Y~“ҵ·”ķī“Ūł4ؼ/üšÄ’Żpg+ģ‰i¦d‚į™××ū4®ų>“Göąū^sā”:āQ› oėłģas"ʀtÄx8×,Å 5Bɕ~“ įųżś+Š­4гdié”QAV§Ał­,7`Ł’Fb?ø)¤o¤Ūß^ņ¹Ņ0\ēóJֳߑPƒįƒ’…2čA6ĻbŒZČųZˆĀ€Ģ„'üąPó„°†/ģŲ¶ŒĀĆՅnƒ@|˜ Ć<¼ōŠ&K¢ @:шŻS¢5E²*„]!Ī“øÅ ’‘…ī#OŽ8Å2Ŗ‘‹CąkŒGĒeeJxnœcšāhÅ<ś2b4ć‰˜@^‘ˆŒ!ł˜ČFŚe‘Lt¤$ŁÄIZ2Œ•¼¤&±Éļmņ“Ė$(Gł’”Nz‘”Ø„“(SÉJ"®²•° Š)ŃĖZ2ģ•¶Ģe ͧĖ^Ž’—¾ &q)Ģb®d–Ŗ3¦2CCĢe:S$Č$ß3§‰šf:dvuĢf£p“›ń&ļF§ĖhŅš”œd#«øĪ^š“čģ:ߘµ3Śņä³ˆÄ|ڳ–ųĢa$E8O}.n‰ī“¦?1ÉĻ6.Ō”åTØ@”SŠCN”ž± č“óŠ/79€Rv·‚°ģFŠ¬Ø„%̓dońd„F]ŹŃ’q†9|!ف.$–7k:¦J©×Ņzd†ēĢØD7jŅŒčIH©rīD?%wŠ(›9;㿘&šķ „§RYÓ܉JaȁdĆ!¤U®©BmhAŌšĢ‡$mE’«+ “łŃč€x»Yō§Ģ™p?+ 8!:LļyÕ¦ AŖ]ŗTšäysŻōv$N av ōĮŻgS²Õž½m²‘K“ Ė™RęZ=s*˜¦g% õØ?€%Höp‡»—iSW=#§ņą"Ć÷·ČM®rWY£Āõ¦¹ @‚ŗĆ¢ E°0lZ™VUV±ö«¼Ø^åČWyŌ¬eِĀ@³ÜM±JroIJ›¼ęõ» é®x[ŪÜŌ>±&¢Y,~Q+!žŌ5¢d(CwŁä±vc%ōäxūØą}2øŸū-k+]ėßņ¦S®0†sÉaW˜¢ ö0„Šą½ZŌĀ>d1SUŪŁbņ¾Åf¬eiLāžšĒ1žg‡…ĢßSk¹H>£š¼=ś²Ä+¦¦”Sjä)[™Ē;¼²–Gœå-{łĘ_ü²˜ūĖ1›Ł»?ņ™ĖØęÆ®łĶÓ’Ŗ2œįÜfČĪłĪ×£0žß\ēĶķyĪ}ĪóŸĻč@:b…>4}¬he&ŗŃ„f4¤…łčI‹¹Ņ–ö2¦+‚Ķ${[†Hg³ź=}śŌg)µ@F-į6eÓĘ øŗ8滓‡ÖƖ“›Fd Ēł/·¦¢*å|ą{q9ÄQöK°eœkbß×YĒVńƕ]l,ŹŁ¶Ģ¬…=ķ¾,»×ŗ–IM³mf;W/ߎv°fmƒ;ÖÉövµ‘;µ½cŁČ̲j]×,ū©„hÖŚ±śßdŅžÄjUūŁŚPZm»wĶ‘ģ)iµ7px\“ S2ė9Ģ`†nsĀÓŻĀh|3ƒ'”³S%ńG1…‰9{5;ķE•Ū±ó2Hŗs'1Nń¹"ى»’ŲĘeź0²š¾Ā0zxźķĀłŅA¼M]pU½Sv␠¤«“ģöĘʂõÜĒ”­—FxŠ/ÉÖ¾ķ%é6ˆ~3\o˜ÜŪ i}īĻt›æ(B®ƒŅ˜Ā™ŪtėfõP9ĒuxĒ“®Ļ;AŠšņ‘#ØMĄ…2±ž$gBėU  Ī“^9²įüĆA÷lūf›Ż<ł»A;P&,äū’e=TÕ-`ē'?ޤ~c~` žó®óHć³ß1AĢ“¼–•Ø9ėRŻß4 ahąMś§€ī“HÜÆ_õåń.¶ RĘh±ī—ØF’‚F%n"š \Fs1Z'x~¶LĆ;¦udĵ“??Ņā?ʐ$² 0 ć;&RŌS]Ų“vx—+ĆtŒjLvtև2o§v7x6[C}f•@ń+L§$7Ņqź#R%B8}a‡F·5š'!ė;b&ŅÄ VĖQwģ“~łńzĶ‘~VH āׅ*‘w;õrHƒJ2]4wY…&’ Dcg±pxƒq&h0:11xåhœą›["į‰RŠŸI'Y5 ø˜‹:Ȓ։?ŹU ——öIZæ( »Ł›Įœ™I”1}׳’ ` їįØŽa`5’ʵ „Itä8 ß)C+ ž- ŗyJ:„~„~—9ˆ K’?īĆ=Ü)†*¹¤į!Ź a˜2é†Q„(3: (@/Y£ų‘õ„h°7KxLnq13˜xj-70²˜¢Hb½„voׇJšž>J6ŹZ™ŠÄõŚi¢)JŠ9¤ } ¦ø¹›ŗ|Ź‹£éŠÖ#„ A„”ē7ĖńŽĮ™¢†˜„Š–*qś§œi›ā†£ģY™š™Ćē Ž%wr©³š©®Ź.4j§“Ś‘ĒŁ„÷˜¬æj±ś©“Ź›@öž©¬Üˆ­Žł ¬g²4IJPę©Pv:&™˜14ķ®Āi™Ēz­å*¤ņyŅ |ŗŖŌj¬ćź˜?ŗ¬Ņź«\Ś%*е:œ»z®żš­Å©œž)ÆīŗÆšjØŚ °ó©˜ż’§É`cJ5ė(ܲ±ƒšv©”u9²lV²&+Ex™²_‰²,[C©+ū²³2‹H4[³ƒt³8{—.»³lÓ³>«1:“[4“D›DF{“0 “J +IŪ“ūó“Pk:L;µ¤"µV+“U›µ˜"µzٱÄӗ~łM!¦xZ˜Įƒ˜ +²ķ©š±NŠœķ°+· v°Éi·ž:¬ ©H"I‘ļ‘’dGJ±ōś·(‰·ĀÆ~jøY·MšÖ*ø|ū¶…Ū·¢‚øuaJ «· K¬t’Ū°k«·ŹÆž+t•;Ə+ŗÜ™2‚€¬¦_Ś…&ŽrR.:¹G¤Åšŗ]ƒ»ż*¶#©øZ”ˆŠ”[WØ }ėć|› ŗ‹sÉQŠ„¼Ŗ»£K©ū™śÉŸĒ;”½5=Ą…TŅ0œ«Ąų™‘+(r ±” ųŚ¢­z¹Ų·Jh”`¼Ņ÷|°„µó$]Uäk¹yķ ¢µ3¢Ž§ž z¾ŗlė]0Z2ŹT÷Y²YSńėŠ‰Šf9Ŗ¼Į£ŌĖ Eץ{Ö[M׋ŚĀƒG%PČ~×H“PŖ¶; A„¼a„›‚m<¶DlŒ¬›™ˆ7’r[izM 6i*=ĶYM+…ś¦Į'§8ü¼-zĀ×Ė­Glœ*ƒ:ˆ8ŹæÜQśŠ¼¦«ĄįtÅ±Ø“ŠØmņØĪ™„’ڶĢ–ÕW@Ń©@—¾¤XL·žh@·ū¤„Š¢»{Ÿ¦Ŗ&©Ś˜YŗĮ ūŖŒ¾‰!Ą&•«˜LøĘŁ«˜ lš+°hńĆ+¼@JŖĆ»™ĶŖĒ)|É(JUœ·é‹ŗ÷¹­Ļ ¹ƒk°ØĢĮėɕģø~«Ė¼)š¼øŪ¹–ĢĒĪj̳ŒĢō»ĖŖ;ĢaĢ¤ė»Š¼ŹÖ¼„ÆĢĢ®,˧Œ°§›cŪ<Ķ™KĢź[ÄÅE ‹oźlÄÆu“ä¶µ\ )X[ϱrĻų¼*|ś¼Ļ„ŅĻžģ)Š]KĻ-$}Š’Š -' ŻŠYņŠŠ=ŃDRŃM/ŃƒĪ½ŠżŃØŅ"},]ŅMŅ(]½Ņ]Ķ.='^ūĪakfĖ+™¶Į$µĮ[°×H®Ī«I< øįLĖŅÜĢ›4Ō‰[ŗp{­P’9ʌ)ɔ{ĖĀܲŻÓłś¾ā\ĖU-IJ½¹Ē\°ŹœJ_Ż/ŽĆ~f! Ģak˜³»†µ{_šÕŒ:֋©śĮe ˚jÄņÓ[©“  X`‘£]kģ×V7/åaŖ|T²ŚÉ¤TÖz'¾9•>e¢ ėq„0\»į‹|•Mž½ĢĄ_,ŌŁČ£$ŁĮt—Ƽj „……ķWiüæ4 ŚL]¦p Ü,ŌPmƒœLŪį>Źąs¶åsˆXĮ|ńŪūÜcAÉÅ?Ņ­ Ó]ŻŌ}ŻÖŻŲ½ŻŚ=Ża£ŻĶŻ2s׿r9ęĶyč}ŽźŽģ½ŽīŻŽšżŽņßō}9brß’—ßų½ßśŻßüżßžą>ą^ą~ą^hųWŲĮĒŚeHõ‘=ŖŠž¬=Ćŗžį¾į ~ĆŌ¢įł-3Ī-õ]āó}ā&žā(~āÜŻāįżā.ć0>ć2^ć4nŻØ€ŃC¢ńH ¶Į ŠS¦üÄåÅ<®ŲaķŚ)Cä=Ī${Õ,l^‡ķĮ£“q±%Ūµż@SnŪŲ Z¹żĒŒŒ×‘ŻŪJzČņÅ$#ˆCƒ||…lrh}^[}Ø1Ŗ)Š}ԟ”ćw{Ū–½ä‘Õ£ß|Iz“̊YMĪÕŚŹ}Śd¾ē]N׿¼Ū‚žč’{čS=éęģՖ^­‘īĖcżä0-­č¼ĢēF]ĢŗšŌ®ÆEĶ™žŌP¾ŌŸ¾­”>ęWMÓÄĆĪņœĆȕ'Ó }ŅŅĄī**=ģ˜½ĘnĻŞģó«ĶĢ~µĖžģ{ŒģŅžŅæ^ķ“rķŲNģŚ¾ķ§!ģŽ>™|ī īäĘć~īŌaīźŽĶŌŽīŻķš~ģŃ<ļåķöÕi„Į‚ėĮsē&Ńļ»ŻŸ-Æź±ÖĻ,ÖA]é O‹ŻŌÆžē’«žÉ /éµīčÆļŗŌmLÖ͘ēØŽč°>źx>Ÿéņ馊’zr­—ōČ[ģ'"o.2‰,Õ¹ŪŲ&µÅņ«ń(?”™Č$ŃYÉŪ“ĮŽ’Ä;_Ā›ģēvŹŽ4čóį8³…>Q.8żēŁŽš\N0āóz'õ3Ūé’Ѽūū\yŃ7OBäMßńnóåAHĶŪŸŚæS|čŁTX¾åWÆ÷ӊŹsZĄ2ōŲ_ģņį²ą›-2Lßõūą€˜%ƱóŁóeĆŠ{\uЬ-čļœėn$ „ ›śĀÉū×;žŲ?}ńŒ.Æ"Né–Dõ’'XSLyg¼1Ķé!³’õ<ŸYP꯮oÕCĖY•oˆģų)s]—‡}ę^’ö¢mڤMö‰Dõ¬ŽĖŻ)ö'ż6ņĮ2(HĪ#/>#żŒżūœ~÷āŚź ’ń¢žņåģ¶źĶžĮÆéšÆž?’SĻż‹’±Oą@‚ īpPaB… dųPāDŠ-^ĘQćFŽ#vÉńćʑ!Mž¼X„F• [z\)šeLš5mŽÄ 1gĪ™{īJńgP1‡Ź¤y”čR¦MO*u:jCU­^ŚUėV®]½~ė5*Õ°e­ś4kvģZ¶mSéŗ Wī\ŗuķŽÅksjݽyżžXšą·„ ö5œXńbʍõ6FģXņdŹ•%G†‹ŁņfĪ=ÆÕÜ6ōgŅ„MŸf õjÖ­]g śõlڵ[Ē‹ŪönŽ½Łźv Ü÷pāōŖ6ž\łr¦Ā›3‡]śSäÓ­_ĒNµzvīŻ„;_ Žūxņ—·—GŸžµų ģÕæ‡O×żĪłńķßoZ§~üżż×äļ1nH«@D«čŠ!A®¤ØA'¤°B ½‚0Ā ­ŗA® éüD”Č9„Hœ *=5ˆŌƒL}čĪUU@ŅL2ĖK‡””uI0oZ”K] b4ŹĢŹŌō 0$Ā—fBõJe˜U Oa“R—=H dÅüÕ 5t>7†LŖŹ³*i;$×dĮč\2“j[Å.=hÜb#–ŪSUjVZfU’mwŠ„ĘōĻ€oČõZ[:ĄE©n Œ}2Uv5Ž'ĻFĻ ćŽ-n7ćŠ/5Ś}nt “Ć× mvK‡j˜P«ō½2ʂ’IH†z ÷ˆNt}g‰w=(’„¾øŃŽ%Ł ’ÓĄzŸIR• 44¹xjöYĮZb,¾Ój˜żU(Ų}eĖ1†ļ¶;o¼÷Ö»AOŅ9™€SÕēo? Ž …{‚€p;@®'—¼rŹ/·yä—W~&– ’  Ņ–€vˆśĆŒŽčX¤7ōŠ°7ōĪEæ|ņɟ©a©ĢĻ|¦^É­Tß Ķ0bģŸ óžūR™Č “–‡Č KšŠnfB§pŻÉx-œĄ ×*Ä LU‹DW«4yėiy ĒFÕ!2lаS GX®Š…“ėŲöč$1øSæSČźęf„>QĻČ ²f 5nE Į°"©«Xėf5Sų„51…xĻ{šÄ‚¼ē®Ŗ„ź*¶Ė˜ cØ. AwęĮa¾¦ČCŸ½[„RӈŸ˜$]Ū!ÆG“ÜYʼnvy“  hĆni'LslUåØĒ6*PšL£"“„IF&ɑMS"ķSĒ'Vr—ģ %)IMBĪ“=%3YČMN²S§ü¤m §UFŅ?œ4%,ƒ@^ör+ņé%Z|9Lbó€¼2Ōe2•¹Lf6әτf4„9MjVӚ×Äf6µ¹Mnvӛßg8Å9Nr–ÓœēDg:;orafce-VERSION_4_14_4/doc/orafce_documentation/gif/DBMS_PIPE.gif000066400000000000000000000445061501757153000241620ustar00rootroot00000000000000GIF89aŠp!łW,І’’’000ūūūTTTÉÉÉYYYźźźĆĆĆ222õõõ{{{MMMLLLÓÓÓDDDģģģ***rrrŽŽŽPPP§§§÷÷÷%%%QQQ ×××~~~vvv”””yyyGGGaaaooo’’’ÅÅÅ­­­ZZZįįį:::333ČČȌŒŒƒƒƒbbb‹‹‹fffĮĮĮ```¢¢¢ååå---@@@]]]ńńń¦¦¦www$$$HHHppp···(((ĻĻĻēēēhhh———‡‡‡xxxļļļÆÆÆ ßßßæææ888ĒĒĒXXXƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ”¢£¤„¦§Ø©Ŗ«¬­®Æ°±²³“µ¶·ø¹ŗ»¼½¾æĄĮĀĆÄÅĘĒČɽ1ĶĪĻŠŃŅĪB‰ĢÓŲŁŚŪÜŻŽßąįĪ1ŹåęēčéźėģķĄŸšˆņī½ōõųłśūüżž’­īmHˆ ĄW*\Ȱ”Ƈm%¼4qbÄQ/jÜȱ£Ēü2RŖ’”Č’(SŖ\ɲ%ؓ’Hŗ8³¦Ķ›8s¦„I¦ĪI< J“ØŃ\Ał<ŗ()Ó§P£JŚČiÕDV(ąˆ@ŽY©’ŠK¶¬Ė°Š–†*B¬Ł·p揯«¢AØ ĄƒB(Äh"ä+€ A7«F”‚€”4ƒüķܢ3kfyžŻD7P8œXņh¼¶™2āĆ"·}ŪaēĶøsėŽź¶!µ…T÷…ü6€±ƒŌōZµ®} TęM½ŗõė§|Nˆ2€"Ņ…?ąŖd ×Ļb.Ķ;CķŲć˟ž ī‚X Bܤ-€ĀĆ)[|żWknd} 6č PŽaƒHc†Å”M"š•dM€—e Żwm…Ö„_‚<חŠ5$Ž3£=(ćŒ4¶„ßaöōŁ!ˆEBųU‰õ$,šTpāc+6“ć{#Õ(å”T^t£•ÜHTY-Xå—`†©Ė–ÜąS]Š©ęšl"Cf–;–•’f›tÖY‹/jS !xęéēŸ€źēžžŚÉ›\Fi碌²ā%¢:‰iLq’5g£˜f*Ź£•%i§™Lź©¢š–jjØuŠ&#¢BŅjQ—ž*ė¬J„zˆ—n5…• ŃģŹėÆĄ+l3¤Ņj챿ٚlTŸ"ĖŖ³Š"Ė©ŖL5-µ×f‹é“·Je­¶+n£Ü.J{Ńb$’5³\ 1dj„ĪņķøøŽ«ļnån7 7“xf$A“Eµāģ™w˽āę»ļĚõn"<Š®_N Ŗex ĘAfüՙ kÜ Ēö5°_M8“Į_Z[„µĮ«!€8›1ø’S,“\ßwW „!™yJø–˜‡EGįwęéĒ[IĒVŽqĖ­ŁÖ@z%äs7T­¤mÅYŁ«)YŹĻŚ=ōÜr*ė/h#įpqĢI€o½„r)Hę‘÷މ 'H\Ʀīa(™į*Łå½=;±Üt‡>UтX$tŖéģ® h3ĒŠŖ!·_lć R{j\eĪ:dŖ§.Ką¼°5ˆ€Ģ±č³ēū‚.śóÕŚ}1"(VX‚)rՄcŠU’ĄÉÖēnżųēu]$ä’5! ŗJŃ4ėĮŸ¹ÕĢ‚ž6óś:żž.E8Ķ„nŹ…&d0ŹĻxĒiY‘ŚĪ·’”ē^³c@dĄ¶°:Ž‡2*'C_yŠ8ÄA°ķmĆJ” WČĀŗŠó⟠£‡-ę<©V5Іú )IŪ ŅsvŲ¶ éEKŲevČ@°~‰AQcø’ŗÉ8IčaŅņfčżqń‹¹œrŲ¾©Ā‹Ņ£‡ņŖ.‚JķŅ¢£Ö˜:Śń&m¼ ŁxĒnõQ[}V½ōFŠ’œžšłĀF¶pŽ’^!éHGBņn~<Ō!…‚ĘcY„’‚ŗ’$³ĪbŅ­'É#ž0¹ŖDžrc¬›J)IE²#•›,+ičJXĔ£œ„,5YGTźńVĆņU%—ÉĢ’õŅ—Å$ę0WŅɈšĘ\å3×ōĖZFR˜–ņf隁ĖmŅ©›žØ¦5I9MšD³å4'›Š)Ķp‚s,±Ÿ«t•M~Ź“›ļ$ś€ņ‹dØ‹ĘW a18XCĮŠ'RØ¢ĶH FWVO±X„ƒ” h#Ētbrg<ę?ÅDOC41¤ķ$‡öƘ”­ Ū»įwn0Ɯ>.€Ššiör*TUœ­D„ģ` KLL`:5‰JW ¦–ņ)Ŗž“ē!–tW¾©ż“ ^ Ūf˜°b Ø“¹(Z3`ÖtŅ2Ū§H ½š;y€­čµ%8 ¤G*ąĘŽh˜vˆ©¹¤ŖŒ¬ZĀ!Ö£ˆĄ^!ŠzÓ£>ŽŽ€P-{”N‘Øü,P‘ŹKC˜Œ sMWx*$Åpå5JąĖ–`ę6Ō(!oQDZd”fø ȶk8ĢŖb«ÄX™ĘŠ’o5„‡L Ńü472O;¬W%:Ž A#6½ījžĖ uN|ģ. q;ÉN8(ŹŠ›„‚m7Ąķ~£^÷7µĆ„Qqē0%w²žhm•·šøŚīe g aY 5ŲĄ„ŹDN+^[gW¼ć—ƒ:C:“ƒŻkӃ;”®nĘaå*ÜüJiæ=D-'V¼’ń*XWZ8Ó¶‚Ō8dĶĻhų$µyȇj¦’—ģLźa5-ŪĄ˜X›²÷ĘļŖ)jdĀ›ćōe9ĖįĶ“ĒLę2›łĢhN³™‘YW «Ÿš˜HZv˜Ā•±,ņtHĻ"™ĮCīķ“ģN­½,&# §!“-z¦*…ŪA…°Ń³ _ŗ,2»˜VŸ|rbż ĻӕB®ŠĮ–@]gÜ6G]ž®•fŚ!¹­^]w’kŚļUų•†ą©Z+lbĪ_Yn=†¤ė-‘2[kżéLM䄤.ō-M]ļŚfŲFn!·t›ĆŪÕę"Jm]ŖĆ>č¶n4Öe/^ǹрš—ß‘nP“¶ŻŹ€7; ­ķL–ŗß²ŗ¦§×!š{BÖ­ų=G¼^±g›įÜÉÄrĶK•ā¦R8Ą“Ńp–x<ŒH=ł¦@r‹'fć»vø„“qs؜åuł}a>5ū\mśy°p®©BüąDOŗŅērs/żéP’IӏõŖ[Vp¾ŗÖ·^“©gœė`{®.ö²›ŻJY?»Ś×žÆĒœķp{>Ü^p¹Ūżīåø ū½ńĪ÷¾CļØņ»ąo“_āBOü‹ģPŠńŌä ouĄc¢äßģśæENy¢[ސoĻüLDĪłĪ³üóeś:ÖmBz§›¾ß؏åŽG‡ĒĶ»žõՎ½»AO{ÖŪžźø‡ŗī~ł‡kųM%~š•>ü‘æ9!žč(ž‘›ŲŁ•™INźiģłīy“ˆÄ©čPŻyŸ…H™øQóĀUf0hEcĪuXėw~Šį?"”°¹.†‚µEüÉ_#—›‚Y†ü§’Śł Ÿ˜9E…»eč‚SDn€ę€)aŪē[‚P£’¢C²h©‘` ŠhŸI —‘E9¢„d¤ŗä¶ŽĮU;ö0Zk3H7 0¶VŚjbŽ£„‹Bzž‡öŽõłQ*Ć"„u£ŗ¦3„±ŽŁž}čŸJśmLڟ(dˆY2H9U„ö¦e…Z3‹.zCó$‰Šk~ŖƒĮ8GfŠez4YS8‰ń9„ēA›žh˜¤wŗNy:Š/Ø]Kó[Ę mĆ Ŗ*‡°‡•VÜåa-B«šƒŖTkq8§‘Z‚œš|?(_9Č9ŁcB­* šˆ2ŖGž9ÄYķV¾†k՚9µ‰7ą„DoStęS1Ó Eš£/•„8D:Ÿ„ īŚ"Ä#Y{† Éz<ĒŖĢЧĩ§Z‚ź§:ĘV\š€%IVzĆj“ų$'čŽ ĖlõÆåÓ„<ør½ś‚-™¦ŠP=Yö>Š% ŗĀpÅ&ėµ°KrÓ Ę]<ÅZŒ•üęæŪ½¼K—lœĘHAÅpL bģ¾\\ĘnrĘ~LĒ[’iĒD™Ē.āÄql¼Ė ȱšÅi ×…“ āa#Ņ} ‹Ę n«NAR‹`R®³ ÉŹns¬ČµĄČķVĻV·Ę:Dg`6rŚ» ¢¦ß4O•o³|ÄØ8¹”kŹ#Č*[!STÜźSꦓA‹ÉSb ÉĢwŒayÅ2ĶØEÓDś”3|ŃƒÕ1»%G„jß Ģ!»Ę*)kT­,_ūĪ·ĖR+§ƒ£ńØaĻ9ų}[Sc[NC"L£4[ĆĻTūĖK<;ål΁ŒĪ ¹Q±QTj%~ 5~6&ÄŻĢĘHĻˉ^km :$†38ĄõгŒ’#ŅŃqĖ(¹ÉPĢŠ!Ģüx¶ĮųĻ65ŌµĪś©Ą‰fQͶ3Ņ;D½ķA9’½įĖ“|Õ¼z²Ą‹gč€óGĢū³č'ÖȘ¾ˆ(ŲZ§ėe‘Õ2öøeŻ2b;2ö Ad" RĘCÆ#’aé؈šĢU‘Ų¦}ŚØŚD›Õ¹`Ŗ$}­mƒl³M·ė©ŃSėŅ£Ɔ=ζ“ŽŃAā·–ólŖÜ·-Ō^–ČzŻ9¬ķ½…ēĘI;Շ ؃€Ż‚»“x×ĻżqE ½Ó=OšlŻ’z޾¬iķÜß]·į½Üć Po씲 ßķ ØœŃéŻÄóMŸŅ]Ź÷ß4ŻĒŌMĘEśŸ¬ßŻļ½ŠŪ]ą¬ĖÜ6—ą1½ąeŚąģm’޽ -qīŻŽÓV,āutē{“§]Śģā į=aµ,~Õłć4nĘŃ]ć8žwvœć<ĢB7Žć@߇äD>ā?^äH^ŗGžäLŽÕ.ŽäP^oKåT®”O\åX®äOžå\nåCŽå`ĪąWęd¾×c^ęh޹~gä9<(Ö Ś®)œ3ą¦DČā˜s~ßuŽvž{;Ģ{> £™ēķčćy›„žŻ†ŽŸržē¦¼čķŁčS®čŽŌēN˜‰žÜnbćÉ3¶ĖŽčޮțN@ż §^āƒ>ź€\źBö‚S1šĶtÖ.ŽŃ.‚2•#Īc"éō[㮮ШĮ­5L3ZÓÆa5ķž¾ę@ģ%F8)}+]_, MTsɧüģ_ŽćŅ µs:¶ÕĻĄ‡DMKE8Œżķ¢>éš^éR>Ķ]=uŻf+Bį³Žj¼źņŽÅ³Ö+é4@‡ EoxW$¢Y•ż­ģ!­ōĒś0рŃz™é]¼_ˌŠ‘!¾ĆC ßDŹ-m†qDK×¼Žė|l—/Å0¶‰‡hé%óęŌņH cXó|nÄ˜Īź$ cńÜį¢zą=šKÄybńĄ ādDóĻĒH’"Jv6o}’õ²Y/@o”NÆ<””T’oĒXēh6õį‹žūŗõ:/čBOōw^˜^qKŠöc®ööŁõłõ··uU÷ŖŽvż§ætā÷AöĀó+O½g×÷¹į÷ˆæÜūėųĒ ÷olvŒ_cgąmoćn_”Oā\włœłłņłšĻ—FæÅ<÷ˆ OŠßÉŽ~Ré2ūČ'ł:ʤ¬ų–÷»(Éµķ Š‘ )üä·”Śē Fn ĪDBŪ;{j*öźĻ`ūöm½Špŗ+ ¹LøfĪśL²ŻČe'śęx<0‹dPkR``™š›h“Ū#£‡j8z£µ!³;µ£€ ŠšŠT1HČŲčųI’( Yiy‰™©¹ I)y“Į9‰éYō DHpšŗJØ$ šĄś tŠJT+K‘[[*8[{+ZŹČ,ś -=M-ķ\yķ(“ø™]ż .>N^nī}®™ķM”ȘŲĻĶ(TŠųQļĻėŠ’.Į»‘Ā Eż$„ļ!|‹1ŚĒHÆxė“ėŅZ„mĻ>Žś$€€ ‡Nø‘rå!%1ėēR‰2–ÆbĢJÉ4 aätĶdČ„L™*=))H(¤M«Z½Š5«ø§Z§qĶäm#šMÄ6* Ė‘YyńņzP–c„DBÕU“–’öŚø2=T^VrÕ}ķŚ4°æ`IUrūź–T-R|E€čPŒ“ń¼‘yåP™óa^öč0āÕ¬›iśØ uėŁ“kŪv’wœjKļjłHĮw-WEBū®jć Ų±ƒ ų^” 0D½€oÓÆ¶ĻZä–ĘčžŸŪ{«¤"Š©^j§ @ńBłā×.\r>‹nłŁ¦ Trń½–Zz ²Ęl£u³`„N˜…%©‰XŚ™F_ņ“—‘‡„ ¢‘[ƒeØHMÜ0ωUĄ!‰Ō'=ØŌÄv.’ƒž…øE²Ų…ļIŅt—ķQn 7«Ņp;|wÜ_[œwŪb꯷߂›8ƒšn[įcī˜Żˆ?®÷įOζāˆĮm9ånk•¼{oĶyی‡N:Ō™k…y髝®åčö:®ŗŌ®ĒN;³¬c•zķø«>»$·_õ»īY÷,|ń[”_UīĘ;Å;ńÆæ½<čć }õ›Kƛõ!Q!²œ* ~§ŚŪ~ģųę_LõVįÆĻ~ūĀüņĻOælŠ×žśļĻ’†„ļæ p€, żø1*p l +ĄJp‚¬ gƒĄķ]pƒģ ?x½³p„$,” %˜A¤š„,l” _HøĀp†4¬” ·¤B.Żp‡<ģ”'Ć qˆD,āš`gÄ$*q‰LÄR›Å(JQ‰9üßƈÅ,ްŠSÓ¢±‚¦bč‹d$ĶqĘ22EĘJK$Ųč¾8AÓS£ˆDpĄQŽ|Ÿū×;¦åńyž»£!-”Fēe/~‰¼Ÿä¬f::>ņ”¼M#')F0|¢ļYÉP&Ī“^‘ß%±WČ2‘rcu„+É’¶J'jR€œlÄ)SIČE¾r—«‹eµwˇÕŅ5¾“%(y‰Ģ#:R—ē &ŽŽŁÉAķYc”d2ÆY!iRƙŪ¤—dMVn2˜‚ƒP·Žt)N{6ß©Cm–reȉrRųüb“ØÅTŠV¤œŃž¾9Ä<Z‹C ”hō&‘Ŗł9A–ƒ[ņĀ©±Mžķā2æń¹åQ”ŽQāQBT`(B‹ŠöDnD¤eę"iCi9ÆFyķ“’€…€s‹" ā§cI.–0šńĄ„Øoég1jĮĻZĒ<°vŚŃ¬¶ņ£?‹ÄZĄõ—¹E!ńšP‹ 3’›>K.¹ėE2š.\ņÆak\U!ń‹|hė‡Č+i” ›Ą%9 O ą¢8D«SŒŽõ픬V/›I®n“ccYIįQ„ <¶ °z+}Ž¢ƒpD:Z-Œ$bÅ*ę@X'$Ä®[Š«2·øŒEZŠz5āC/vq$ÓŒŖŖd'8-‹Łč27^w ©p‚³ätؙˆĮhKÆĘE”ŁżcF²+–… åõØ’ŅNV¢0w«SFć_R]É~nџõBfĄ௦ ]ś:¢²“®ƒÕ†Jrv]©ķ–Šõ]G`D#øU«?īDÓn©ƒŠ”|¢m‚#čģuŠ"ī•,:‘&:0Š1DŖDZˆÖv£øź‰ d 3ŒĆņ*G2pŒĮĢĆO/„‡št°ø²÷/nm„”AŚĒ,k™®*Yʤzz $·Ź[Ÿ"Õ~d4]P'¾+D/#YԘĀH¹”¦J²å<ėyĻ|’ hI’Ó~ęĘÄb2ćsT‹XéXöZįJ|6Äē•/3™S yUų‚*__ŅéRČÓó! r„j%e¬„Żń“¦ēėŅ_y֛¦īVÕ"—D`9J«Yž„Ó9‘•Q¢³ŠÅ–ƒ›¶› \m[ [ Ó¶¤eßüjZk»sīź,eė„®8uµq7,×mo›Ł™½4kr”¦t§·Žv·a½Yuė›Ū"ÄdōŲmFhsŠüöö¾Õ pY·Ū| ’›Ą‰)O{üąŚn8“'Īp§{ąÆõĀ)d‹OW–šyė^paž8Ū —®ÉW>ņ彑åĆF ‹õšš·|Ö3·«»¹ó  iÖĶī«”+}é—W+:ӟõ$ö<¢QÆŗÕ„īō«k}ė-œz.¹ö°æŠė<»ŁĻB²ćķloūÕŽ\·Ė}ī „»ÄéŽ÷¼ēĻī׻ߒn=¾Gš„/üæ³nųÄ+^t~ˆ_¼ćÆŁgB~ņ”_›ą9^łĢk¾ß‘ß|Hˆ<,{¾š—‡ųę÷8,óžē£7|éS Ō#}ö×}/ŹQĢśÖžõøĻ÷m_ļ¾+\÷ē½ņęĒū¦õ&žāļo czł˜Ļ½óõżg|śŃęõóž}ėK®·÷ž÷é’žę’žūڇ}Ś.~~ģ7¾ģ%~Ӟėó»'ŒåńŸ{ś1~^õ“÷¤R:3€tc ¾”z •^ÜpPٵk•lų$€ź·?ķš~;Ę|ż‡~ó‡o‚2R{RS1‚›āaĘZrŃZöš(“Ę )€ųÓĀsįcłēx÷¾‡kˆ×"Bą.0Å-ŠR_„öJ–k0ŦtghzĄ`T·ƒr׃óSi"j•‚ Ń ‚Ņ‚"Vi…6¢sß&†nś÷T˜…l·…7l ˜‡Ąą/Ž‘µglc³PžÅ‚źeT…hµ7ˆ–sŪ lF‡½·`āɇu؅ w"Fa)ø‹¶2‚ČV&Si/Xօt6ƒõ3[Ć'‰…‰–(vwHr?Hb6eް\+ŃkF…·č ”@'ф…į„‹`‹Ø?\…ƈ‹h'‹²&(‡ö…*5.žŲ…œ„Rł€ A^.X0x†‡Ŗ˜i‘ŲWˆ…ĻhvĘz¼bd@’Q€ •lJ0"’Ą€JRPheį˜]°‹(”ˆ%“‡‚F$ĻVg É'lč; )‘I‘i‘‰‘q~„‰r8~nčx{ģČuŃ…ėočpģ'~ę'’[G’ÆX=É×ęĒ’-yu/ن1iķ׊\h“g‡“ŲL;¹’!ł“U”h<2‰:åg”G uIY‰õ§’Č˜:•a'•ß“‘€ö^X™•ż·•aI–Ä7–e‰–›w–iɖ“·–m —Š÷–q yļŲ+)G—ŗ7L²×•H§z{·‘{)—Ē”ŹG”œG˜ē7L‡9“ōÖy‹9z©q䧗’©y” ™U©r˜ł}š n”™ž™y ™˜É8˜¤éw¦Ięäņv ż¤lmöކ°$š|£šĪǚć@QÜQn–ąš1,v&Õ‰˜œ’)y»Łz½éĆ 3ʰžQgF¹° ćA%ĀąTŌŁgń ĘA ł2žŃ$”ž#–›÷꜕ś•X“`3” {e%8”PĄį ˆõłł:„ĄRA`3ņaN§`PŠXFh™£9ŸŽWŸ«bXČE‰s٧.IÕ]š„ „ö%#š° ų°\š0Ę ©°ś £f£ć%ŽZcv`ģ"U;aTzźŒ)Ÿ©śk§" 瘤”LĀ's© ­Q×透Ō5²IŽ:Ź‘‡w™Ū «ź“ĶJƒkxڊ®L×­?ŗ™ģŖ“čēÆfć—¼˜ń—īÓÆÕgÆąZÆ눺™Æ”Ó”„£ó ¦Õšé±±…° 9 K: «®å¦ę˜‰C‰ÆI›­ėč`i°Øł±ū¬"k6:»:’šīzÆź²#‹I˱);E<{S8›³!+”³:ˆE@»lš:“'G²’Š ää›ĶŲK&EJū”a‚µ9Ū”/V^KtV E[}ד~SŸĪ1žāßéjżżN‚¦:JbŪDdĖ“f{¶ō“x .Q ŹXŽYEŹioA"®ƒé!³_¤·ā’Ē·}ū²ō żq¢;¢0Óe–”\«š%.!µ ņø^¹VŁ™”[¹Ū$ƒ€[V& iĮ$A/Įy·_—“ė'“ŖĖ§; $ATrc„Å.iA\0S%ىHH{E§›Šæė»QSŸ÷U†„ś ƋĀÖ©ć©C!Jœ^4¾TŁ»Ó!ŠŚčel " ąŃ«”‘¢(ök zæv›84ėæ’‹;8؊¾¤®ÓŹrŠ‹·Y„Ą°×lCk÷­ \²“ÖĄF‹GœĮåJĮK¹n Ė“¼;6K°ÅsĮ‚™±!ģÆģgl=ūŗ+ Ć’ėĀa ³œsĀķ:mDŗ*œĆØ ²Ż§³{Úóü»²š»’+¹AŒ|N9h ¼\qŗ«Äøy¾S‰ÄR¦üĄVģÅ%,lʬXµYģ¼kĢĒEÅ"Ģ¬Ų “™Ę{ĢÅl½a<¹$ ȉŒĮƒÜ”…lµ1cOtŅZėå&ʱOXĒšÉ7#’žÜʧ Åć›=vN«“wÜČWģ³=;oąP5Ģ<žęŸDqVå±U3ՖĘQ›¾ü»üXÖX‹iQÖ‹`¾ŲÅĪśāuƒźš›0–Ė`˧܊˜“„\ ÅĄFŒI1Sæ|(g(#u ±6ņĖ’0Sö¤ńQ4Į‰“ü®śČæ6Ū>Tš Š·G•Tū9øą¶ ÜOćjČpüĶ~l…£ŗĄ‘< +Rų˜FÕõTŒ“!̱²VuĮX°„õ%1~įŒŪ€ŁXĶ’ 6X“ģWüŁW2óW‡[ 2,J Še ĖĢ(%łČ½ŒS8Ī KP]óŃÕü/ ©…hō¬é$Ōį].cČj¦­ĘÓyJ(Šņ"a Ī4 6T;ĖaŠ[³[ŹÕ[t§ĮYÉk\Öś©ą›“d<™ŽÜø±Ņ Ņ ©ČŻÜĝŲ!T†R¦Õ7ŗVM ",²ŅśXc’H#:8¢#1½ø®nčˆ}Óaj_ŻUś% ȑG „CźO.J`&ŃŽLŃJ-Ė·-¬\ŲĻ`Īu’3՘Tjæ(Ž””Ņ‘-šœ"ā΃r Rq(«Āś G³ĪK뱐`¼„­*v,.f^T2cŒPcÄcŪŌ€ķy‘Žų7Ńy¬ =Į›Mķ·Ė0“„‰6lČĢ̟ų-—mĻטØę’„¹%+ČZ„n]Śl=Ś īÅšfn Ŗ±b* ©fŁė©n& „pĖjŠŠ+ĒŽjéĶźhŪņ PĄœ vÉg–@3¼P2"xšü‰-87± 3ŽńÉ5#Źx ;>›ŪDĒyĘŌF'Ø5j…zŚ’/ƒb€ĆM«¾€jŽ¢jŹĄj ćGīå_ęažeQQm¼ĮĀ ŌÅT¶N|Ȑ`Óć& GÓeŽÅ•PøMw¾±øĖČäŒ ­«Ü{;D^Öoģą’oÄ0|ŽĪxžč”…Ń)¾œ™šX źāäŗŲ؜Żģ4éI¬Ū_ 鵬x ꭁ,Īƒ¾éÖl¾<™|%•5éēœĄŃ‘ÅźkĶę¢ Ī±>ź‘Žź# ÅzžęœŪm®ģ½>Äæ^ėŗžģĻPŠ ¹īČÆ¾ģŽģėĪ®āŠīŌÓĄāÖžģ¼ŽķĢ®ĀÜ~ĘŽŽŪß°"Oāīb¾e4(Ēqęč~9óģåœļöĪļDDĄżš#ōļOš4šštš Ļš “š ńōšOń\*½ń4ńĻń}Ģ£ņocwī!Oņ7ĖÄ%ņ?ņ)Ļņ±³ń-ó),É1Oó&¼ņ5ó8tó9Ļó««Ē—ćš.ōi‚˹ōŗRĆGŸ+¦Žó4ń²ĮZk”“Žō(äĆc»ĮMLõUļ@Oõ)¹ę[Ļõ ’äõy›õŗ.öcÆ@eĻD=W“iÆö*?ó°ÜCn?õY÷kõfö„÷y_°©›{Jh#˜|ٲ9„oʐ@ÉBn¦ʾˆų22›.’#²—śäféŹ”Ż¼•€āŒŒ6Lo߀Æ÷sævfx®„ÕA@c”ĄśČ] »|‚Él‚aū½Ü2Õx20•3Įæϼ€œĒÜτЧ®Ū£ßēØ/÷?ĘkQķ™ŹV‚_Ų/ąD2„ N‹Ž2„ūķd@‡błĄž1®"c5ĻzķakUtNś–ąč‚ ‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–’—˜™š›œžŸ ”„¢„¤Ø‡Mƒ¬M°A°°E…B°Æ­½Œ1…Ą„†DŽ·Ćʬ7“ÅŹ­³µ­µŠŅE“JB±Ų¦‚Ŗå”ē†ā“źˆī…Ö‘ščõö÷ųłśūüżž’éÜ$°’ĄbMZ%tõ ÉBX“+°pŠĆ 2 ¢Ø€Ę×4ntĄcF‚L ¹°€ÄAA”TŌ6ĶĆq®”)©-a\ üĀØ‘£Ø‚lŲ®R’&JµŖÕ«X³jŻ:H*×E^ē%*f ›Ī²M\źāEīĪH¬Ų.ŠK¬Ū“/=pf6HMA½”,éõ@o$Ī Mü%Y.lVE˜EuŗHšäƘ3kŽĢ¹³g~Ž=‡vTp׫aĄdPČŚU^LMnXq‘Z˜jŗ-ho³z±ÜZź¶„jõrÖĀ KG7ŚŖĄ&1Ÿ¢¬ŖŲĻąĆ‹O¾¼Öź’›ŃƒUt#—Ž%n‰ x«$;Œ“ ¹š`ē3F åwß]†T  ]÷H ó R|Ą°‚œMņĪn×RmøßśC®=×f;m¹ģ¶ėī»JUĖɹš¢;©¶ń®[ļ¾üöŪ,½éėof7†/¦ ¬šĀ ˻⸋F,ńċNjØS7¬ńĘsV°¹‡,ņČ$—l²%nĖzņŹ,·ģņĖš¦l,Ģ4×lóĶ8£(³Ø9÷ģóĻ@ ®ĆBmōŃH'= ŃJ7ķōÓP¼óŠQWmõÕX³;u>[gķõ×`‡Ķs‹]‹möŁh§ŻŁj·ķöŪpSĒtÜt×m÷݇”m/Ž|÷ķwŪz{ų÷ą„^uąr®ųāŒ÷ŒøĮG.łä$?nŠå”g®łęa~ē-ĘP(®ˆ1:čØķy:žˆNńė°ĒžŗQ ¬ķ©ēN󼠌‹ŗåér—ŠīÄŪĢūĮ ƒ<ņ2_üó'ū%ҽüō…żöŃĻMżļcæ“ųܗæpõó’ĻųõĆēŪ¾łšo’Œ~ņé+žū¶:’žżĪƉļ«hKYT‘Š ²I‰F˜QŒģGŲŽbį*i„1OśŅ«T"2‰äU¾@$ų€Āˆ$Ø  8³Ś%Ā2›j"(—\ńļ†õņ_&hŻ\¤A;šQR„Š K½Gmö‚ˆ„ģē栓ƒņŽ) ¢Š‚("­™%¦Õؤ$†C Ίé¢P 짤J‰XĘć%ż)#™jG©‰ŠČNm°øSäT¤+iĄ$É\(%ŚšJD«SY¶E6`¤ę„>˼ŗ¶@Ūģęķa¢: ö¶»"l;\'ØiÄHÅĄRM¼DÓØ„mĘ6Ėā––É‚'‰Ņ’ˆ%E¦2:¤s›D”īn·IŌ…$hdē&Ś~ÓVrJelĮBŽöŗ÷½šÆ|ēKßśŚ7OwœŖżÖ؈J­·Æ2¬hSłŠŪG“J·J„U¾»¤«JRüķĪ_mKQ½ÖĄ>p~/¼ß¼žO¶;̰ˆ¶įSj.›®pŠGĢbņ 8†!īškW `·ųĘ¢)q‚O Qø~8²Ēt cŹ”8ĘK…„—¬™Væœ^ĘŲ[(&[™TD>Å}·Ģå‰]łĖts2…ĮLę27MĢ6³š×ģø,³łĶpQšAē:Ū¹csVń÷Ģēå9É}“ ]éęAśŠ¹-4¢Ķh¶9ŗŃŽō`-éJ[š`”¾“¦7]•?טӠõc2-źR›śr¤>µŖWm„ćyšÕ°fó«gėZŪŗ£:»µ®w]Nóś×ĄÖ³y¢ÅŪ.ūŲv’(ULG(eėātĮ&ó¬ó¦¾»éP{€ęh“æ)9=ł“B©8lA9”FɎ$x”J ”¹”Ny6Eł”R 8M9•Vy5Qy•Zł5YigÅ(ō·Bж•ƒÓ•‡š•™–®Ųz=Wqdi6fy‹ŗ³3÷†‹Ś—䘔żXˆA(QyŖa“”‡*eøv zBh4K Ŗ’€iŠÉų–‰°|cę ÷pž‰Į |§zŚ`JAųˆėI Ž {„IÉ` ¤³z̤ŸÕ@¤y7M Ošz(}Ā–mYŹp z™„`Q=ź£ڐōØqex¢ĪysPĮ†{•Ś7»B1§1ž4~(‘;”ndR"!¦d'§Yź|j›Eį§Į$“ЧiHU£hŚ iŗ Ǧi›ŹžüŁN5h "!„õ$šń ƒ—‰qŖŌ€ 1€½°]2}qŖh ˆx…“‚ŲІ–j «łÕئŖb#Ŗ:ŗ«’KX…Y;čSBPĘ Ų@mT ѱ¢0tˆæ‡Ś‚=ų†HĖį‚ŁPSŠ”Yč2YD•özzx¦±y~č„Ģʘ’d#†Š”Ÿ©‡…5±†\D^XFśˆ¢%«ņ9 ŅY vDšIŲ@°ļq š$pŖv±x†XB–ś:¢¤h|,«–0³2;³4[³‡¤†@$ #<ā#‰ØAa÷§»łŖt5NŅ`,]œØHĉ“ŻŹ„³<Ū?Ä] #ŚŗtxÆQš:Ŗõ'GkśÆŽ ”yy˜É„©¹©,؁f °n:™Ä˜7…œ r©6*¶}·V欎i2|+˜ūjø€ø8K<…ū¦śŠ¬‰ 6‚ū™Ęźø’”‘+·ā™©Óøt{¹i›¹Y3¹¦‰Mł(§+ŗXCŗ4©ŗ›&ø6»[溚Bꬓ{»ćT•ø»»Ļb»¼ū»„»Ą;¼¼ā»Ä{¼“†¶Č»¼Žb¼Ģū¼*ā¼Š;½.&¼Ō{½Šb½Ų»½£½Üū½˜`!½ą;¾Å·¹ä{¾œ"¾č»¾=ęjģū¾ę½š;æĆę½ō{æ^ė¾ų»æŻ«¼€ˆ–b¦üėgökeĢ6(ŠŹ©˜;ĄxV•,» _ Ü;€yø–ĖĄ ĆŗĻć¹ üø ŠĮ’¼ø˜¹¶ˆū¬ Āü¢Įj›æ¼©”‹Ā £ĀŒ[¹Ÿ«Ą/ Ć #Ć#ĢĀ5ģĀֈĆ1,Ā8Iƃ@ØmkĮ?%Ą6 Äū¢ĆCLĀĒzÄ~ĖTĢÄ),Ä4Ź µ)© sBKz#@Ķ (AœĀ “¹™īAĘ…‰Ņ¹r*ŃK@"ł®€~ēEĮP<ąĶßīMą޼®ąWķą Kį¾- ¾ŽŌ\Ā7{į±<·üÄ’ŗž36°ėŪ(^1%Ī’¼ā ¬¾.ŽĮ0ć<ć4¾æ6~ć÷›ć:>æ<Žćļūć@¾¾B>äē[äF>¾NHžäß»äL¾½Nžä×åR>½T^åĻ{åX¾¼Z¾åĒŪå^>¼`ęæk»œāh~'\gŽ'k.mĪ'åMę÷"ßó½8³™¹tŽā’3ÖŽėašYĮ}^ævīĒ““ē„~Ķ€^čÕ{čĖ9Ššœėč†ā!Ī”Öčzné—æ%L”‚^é ĪēžžkNg7­œ\\œĒ\$· '×)§BfģÜhlœ6—ß#uB;÷°F4Té×i£ž·~źća»ōÅāŁ×ä™EŠ ŹųČNŌž± J^gŁžF™,v_”ƤWLįüvżēÅŚŚģĮ×1ēŒŽģŽé7|Óźžøœ”ÆÕt@…·H]ZŠƒÄ\ygŚŗz°ĖÕ,m‡āRģVŲ2=ÓīŽæšNį4jzĪ~°Š|¬µčÜ¢0L x{„ ņ§Ń‚UŹ Ā—)Š Ę æéCčš„xŲ/æ©.l7Ķ‘H§ī¤ ŲW=«Ż×§ ¶OŻ`ī'Ķ»>ģÆjrąw īåņ+ÓžŗÕ<óé”»ĖžĶ’ÆBERLQ(µĻĮRą:« hԁ!ŽšŚ±„Óõēnīķjąķ®õ˜’VóIVUŃś„ĖįŌw„Ė1øŌ48Ō9ˆƒ7ØVCx®œģ]˜OAąIt?ąEģÓ÷§Ž|Ÿõ~wTųGVx°>›%[نJgYgŸY¾—†CŚp¼å~× ?õ¤łwH5māw>+{’łXśŸ:……h‡Āõ³8Lj üć™ó77‰Ā –h]-—‰KO© ųyP*}ł ŽŅUEõ»hõĒOü’0$žčšµ²óPŪž’i^’ö’ųæŪZĆh߀ 8HXhxˆ˜H!ĄŲ(P)9IYY)`™© €©³ÉIىØ: šŖŗŹŚźś +;K[k{‹›«»k–ˆŹū+čū* \l|¬K\¬~ŽkžL»¾žœ/?O_o?ųžÜĪ’pß-–Üłˆ0”Ā… v#ˆ¢(‡½I,wPŅE;zü2dƍōH&2)2eĮl(ÄØ2¦Ģ™4k†ٲ—Ķ«r²ņm"LžD‹=Ś‘č8„Į9} 5ŖŌ©T«Z½Š5«Ö­\»Neé•ŖØ°_‘š=‹6ķ9¦ßŲŖ} 7®Ü¹tėīrūЮ޽|ūśż ø^nƒ>Œ8±āÅģ>f 9²äɔ?fY9³ę͜;¾Œ “ēѤK›>'źÕ¬[»~­M“5ٰkŪ¾[2ķc»sūž `ŠÅ’4<ŖÄ“V¬o!ą± &ƒ¼o?Ąņ°„kQŗ‡q¼ī²p»ó-’R½F3zkĖĶ6[»Õ:ż° ĄīĪŠ:œĮ¬U«[Į PpŖN‹[Į±|Ŗ¶ÕXÓōŗĶź,ɬs*¶§e÷J÷Ó£M÷ÕYć=öŽvs ’‘½ō£‰Ż8Ņ’S¤“ŠĆąėt¾š łæ- I„ ›ZĄŽ…šūµŗBd`*ė9BćƒÄŽ÷4£`2ą•4Ģ/«·žĮė…ŠN©Ó¶Cīéļ0ĻšēlM˜Ļ…¬Ū÷ ŅļJ“o_Qå™:½ńfw{·S;5oņ©ˆ7]Ą \ź“Æ6­²¢Ä¤/7ö9ĖRÖŌā7æŌļ[÷{Ö©tÖæ’I’ķyņ£©Ģ‡®”¢Ōž AĖqo„ZŌ—"–¹×•"eg„·„Ąš™¢+^‚Š„x®z„Żéžē0GōŠøĆ_œįP‡Ā›«÷Bcq.‡½“ŻZ®·Æš‹:T ­GĀ0ĄhŠĻlg70ļpāŹä€7¶įŽ Ā‚0µ¾„OWŲ£ nŠ57š*uZcc$ģ–G;āq|…šćķęÖF>ĪM‘yŒ‡āšeERIČūž?Éļi’i?ĖÉęh@_5ÆoJŚŪ2€°h±a1+ ¬ °CC¬īo»D«ZłŖ\ŻR°*ĀĮęÆńŻ2—¼…č%ąŲ0`3W£ZfÆųAIF®‹‰Č¤£@ NK‚$F5ŠÄ®į?Hņ[-$ݐ„?YQM‹Ģć"0ųLü ¢XpgŪ²e¬{:"hœ=8PbéSwó{ēŚĘWÉt\吋U¼xŠit£ķØG? ҐŠt¤$-©IeTQ ‘š’‰Č7©®”r1œ4mއŖ­oąt”~aé”`Ś©š õ8¢ōŽOļ5S: u©Ź)jwŽz¹¤Š©TT%źJ„Ź)¬Ś«Ŗ\ĶSµURõ§]-+l¾š$įČ¢62«[ĻzŅøŹu®tŹ[ļŠ×¼źuÆ|ķ«_’ ŲĄ v°„-¬a‹ŲÄ*v±Œm¬c ŁČJv²”­¬e/‹ŁĢjv³œķ¬g? ŚŠ66;orafce-VERSION_4_14_4/doc/orafce_documentation/gif/DBMS_PIPE_flow.gif000066400000000000000000000303571501757153000252100ustar00rootroot00000000000000GIF89a!Øp!ł],!؇3f™Ģ’++3+f+™+Ģ+’UU3UfU™UĢU’€€3€f€™€Ģ€’ŖŖ3ŖfŖ™ŖĢŖ’ÕÕ3ÕfՙÕĢÕ’’’3’f’™’Ģ’’3333f3™3Ģ3’3+3+33+f3+™3+Ģ3+’3U3U33Uf3U™3UĢ3U’3€3€33€f3€™3€Ģ3€’3Ŗ3Ŗ33Ŗf3Ŗ™3ŖĢ3Ŗ’3Õ3Õ33Õf3ՙ3ÕĢ3Õ’3’3’33’f3’™3’Ģ3’’ff3fff™fĢf’f+f+3f+ff+™f+Ģf+’fUfU3fUffU™fUĢfU’f€f€3f€ff€™f€Ģf€’fŖfŖ3fŖffŖ™fŖĢfŖ’fÕfÕ3fÕffՙfÕĢfÕ’f’f’3f’ff’™f’Ģf’’™™3™f™™™Ģ™’™+™+3™+f™+™™+Ģ™+’™U™U3™Uf™U™™UĢ™U’™€™€3™€f™€™™€Ģ™€’™Ŗ™Ŗ3™Ŗf™Ŗ™™ŖĢ™Ŗ’™Õ™Õ3™Õf™Õ™™Õ̙Ւ™’™’3™’f™’™™’Ģ™’’ĢĢ3ĢfĢ™ĢĢĢ’Ģ+Ģ+3Ģ+fĢ+™Ģ+ĢĢ+’ĢUĢU3ĢUfĢU™ĢUĢĢU’̀̀3Ģ€fĢ€™Ģ€ĢĢ€’ĢŖĢŖ3ĢŖfĢŖ™ĢŖĢĢŖ’ĢÕĢÕ3ĢÕfĢՙĢÕĢĢÕ’Ģ’Ģ’3Ģ’fĢ’™Ģ’ĢĢ’’’’3’f’™’Ģ’’’+’+3’+f’+™’+Ģ’+’’U’U3’Uf’U™’UĢ’U’’€’€3’€f’€™’€Ģ’€’’Ŗ’Ŗ3’Ŗf’Ŗ™’ŖĢ’Ŗ’’Õ’Õ3’Õf’ՙ’ÕĢ’Õ’’’’’3’’f’’™’’Ģ’’’Ø÷ H° Įƒ*\Ȱ”Ƈ#JœH±¢Å‹3jÜȱ£Ē CŠI²¤É“(SŖ\ɲ„Ė—0cʜI³¦Ķ›8sźÜɳ§ĻŸ@ƒ J“ØŃ£H“*]Ź“©Ó§P£JJµŖÕ«X³jŻŹµ«×Æ`ÊK¶¬Ł³hÓŖ]˶­Ū·p欝K·®Ż»xóźŻĖ·Æßæ€ Lø°įƈ+^Ģø±ćǐ#KžL¹’2Y˜3_p3FĻod²LšmfŠcŒF]‘õ>фӢΓāg b±s—€{mŠ7zƒ¼­»¬2ŌŠ@k˜Y™ĄåĒ•Å(&ge7Ä`ż@ŒĪĒ,^9€°÷-W_¼½UŌĀ/Ɨ};sļŖļĆ®wõų…·tę”ĒŻz®¹Gj“L·Ou¾9܀Ž–‰ƒœŻąœtś)³ūÕVį€zvįsAxÜhžØą‹RŻą A-NwÜ$!¦8ŚŠģŻ˜ćˆŃ1'‹ž©č߈™ÜcVće6£½°O=¬A‰"•¾‰įŽžy–ŠMųœ€²'£Yię’’l2Õdxjv)Š—kŖ†„™t‚&¦zdŽ šūÄYO›ļ•WāiŹ`WŠi8w–^ē–ŅQGfs(ź'«!Jč§K5 ¦Ź•¹øI*Š3Šq)fĪ}©é©b jT³Z7Ќ«²Ęk™ŖŁČŁyīJfySŹyęhæŽźģO•RĒlAšj Z~Ć*MĒ–©ģ>€6ūģSØÉø©–šĀ¦Ÿ Z;$8źGēh“+j™•ŅY”n‚ć¶bPG ރķÖ¦)½ö®¶šśK"²ū »iƧž0¹ƒ®śaw÷Ž*yeR)_²›ƞhĢw-~ĀjźĘżÓiDĀŁ Ą tī~ÄčGeŹ÷ݰg“¾ü]Ģ¢ĪJ³^6?-õšjE=ub7ŲzõÖ`ž•µĢ\‡-¶dāŽmöŁh§­öŚl·ķSöŪp&\Üt×m÷BVß­÷ŽkēĶ÷߀oķwą„īlن'®ųāŒ7īųćG.łLsOnłåˆ Žłęœ×„yē ‡¾Ö碗nzXˆŸ®śź¬·īśė°GĒ.»I•ĻnūķE‘Žūī¼Ć¤{ļĄoŅļĀov±—­ģf'ūŁČŽ6³”=mi;ŪŚŌ¾vµ™ %Ģtß÷„Åķķq›»Üč÷¹Õnr³ūŻīŽ÷ŗåš¤Ūްj޾óĶļFķŪßż~ćÓæš¼ążf"£šJƒ–Ŗ™Ź Œ fŁ.qGC|ź£N[Y¤šøł˜'ó§QŪ᳜—87Sʝf…[EžLk„<—j="$ö ЧZŽ˜ÄŠ›ƒŁ ŌōŲ„¾'%]…Š-žœO6v(NQ¢ķnśŽUø/wžņW…ė³Ć½łmÜ?ńŗ®śė Ҝų:ųĒ’/ ĻžżŪÖrūoģ÷ū·1™‘xX€CŃ˜€H!Ȩ€kĆpµē€—į`Xx T3ØT4ć…B‚"8‚ äČNÅ€ųg‚,؁ģu‚؁.ų]0X’5x_3˜ź78=(?(AčChEH„-hWÕ$r^ęQ^P=UoNŲz§Ak 70ż£r¾¦G*•ń…L!†`˜‚\§2/5TD-†“q¤5JuŠ…¤%QMA† †IČb ”ZNå3_åF*eąĮ\|ÖN#™D5¢VOg„)ȇ qWNØDM“D[8…ށĄE5G”?t… Gż³*]Xt}ŲLbEGŃ O7rµq(‡R,5P…XŖU†Ö5 %c'‰xԆ͔ įRn43B• ³QR¾³Š+µEŠbžVoŗå$!QĀO\’ČUĄ]Ąuįø%yų‚ųM„HZ”‡µHH‚Jȱc¬H`H ±dŖŲS-⢠ŌS]5SøRÉ88ĪH\€4j±]¾;6C]Ź‹¤õL8ēŠ ‘Œ¹F¹xŒ¹‘9".”‡I0_ŌGdāxCÅx†(-åńZ~“SBć[…Žc(ƒ"”MbŽMČ(3āpŌŌ"”·8äØä%,ŒR\Ų8TØ(¹‡žų’Ō”†å2w‹$D• ŃPŲ$–qŲ‹^ȓÅU£VU÷RįR)’¶ų3‡ 9%q¹†ĶSCĀ\żˆ–¼(DŚHO9 N(kŖŌŸYVЉ—SäXgPYDq™’€ *”Xyhъ^U‹ß(ŽÆø¢U÷XšÖ([³1•)Q•GŒT‘Y*č™yaĀ•VÄ»’QL¢X»¢… ‡hepõ¬)‰ ‡-į„®W³É]§e3×UĢ‘gŅ\ĪaŽćZKõ‰9—[ĢHN‡©uf[žų4Éi` Qщ°É‹ķIõ‰ƒ:H‰vå~"įœzVš÷) „•ł  ś J.ź ŚŹŗ“~‚ŅX›¤Ÿ(””¤A‚":¢$Ŗ@źøž»c–Ų ;* ;‰%:£4J¼ó¢õ':Ś98ś~:Jd=J}?dAŹ:ŗ7;Ź9Ų·¢ŲcEʤ逤Ų:18Iŗ9b š>vRŹc\J¤SŹ:WŹcz9OŖ:GŖ7ej9g „Y±¦“³¤nŹ$ƙcmj:UJ7m&—0v§„§qńi#٧Z*¤“s^A¦^J.5ŚØŽ @]j;iJą÷'W[D&§+Øat‘Xb~`œZfŽqEs‘š~QaxˆĮ[£ś8YŗØDØf턨Zę FvŖh«–™©a:a©śŸė夽ŗa£×­ź8”Ź_‹ ”@Zج“§ø”–Ā «MQ©Įj§Ćz:Gx¬!Į­Œ£©9 Ļ™_“bā*­9ö|+f­…į­‹C~*¶¬Ę˜š©Š9õj°Ē¬AĘ®¦³­čZcąŗ„O”ŖśŚcš*°±z«ū ¬§3©3™ģŅ2Õj*v°%V¬żuŠ{|=&Ɖal‚Zcū¬Qį®ń”ézƏs„ü³…ž9ö²CJ. ^›ckØOA³€a~¹®,ė8+Õ÷ØH›“Ä;>‹_ė(»šL;“;¤±Ś¢’Æc|.v²{µ(ścTĖ8žJ Xė:ź®={³4µ(Į¶Ń“¹w²Cį¶ĆĆ;;k¤'«¶ēT¶­S²v“q^āµV䵑•'ŽUKU\½•³„;²‹›WL«·ü·'‘D6ƒ†§ o[œ³²³q&ö(YrŌ\Ū8”ŗĀy3S»µāJ¹)ń•“¹”Į®ĀF-™ ¬²K+0KœŁv2¦&Ā»ņ‡kk·«MAg:ńrg÷t|†•ņYnÉOÕøįä˜ŗUy›Ö8Ŗ• ńø·»ć·>v®ÓėO¢$ާĮ>4QŪ«?“lŹŅ![\t»DU)Ū{‰µ;g‹°Mń“ ńØYƒŒ1O%Ž\Ÿ·Tź±-Vc2œ%*i&Mæo6¹·S“*«‰œųCL-3rMk咧×ĮĆĀ6É+œBSĮ)ĖK+‚H>ēµøs·ĘĄxƒ/'³šč™ DӁ†k¤™.bT„r匓5EĢA M<!Em'gtŪģ{aŗFY¶Ė‹u—ŽŹō]™’Lt(2ć—vŁ8€Ÿüc²Ū9aFœĀ'A=cL‰¼eÜÆ'‹Ā-|’—ė?<_ĪK­Lį³ļµČ"ĮÉyŃČʵ±É|+¦?š¬ž ;ž¬¦|•ČYŹ«SČ%F˰,É_›aƼ:ƒ ©˹l;Ņ[«N‘Ą‘ÜJ›ĢŹĢĒ»ÓŹžƒŹG׏Īl7¶¬cQAÄuś”Afµ¾‡Ź”+ĶD²Ķ+øĶDöĖ}“1Ķuc¹›ÓĖ/Ķ|šźL7ćŹ³NʟśĢęŒÉKĪdĪ%׳äL›DVĶhzĶĻ Jå¼bœĖH¶Å.ī¼?ų̼v1Ļnć?»\`ž¬Ķ0³˜”æ&  Ī9¦²¹ZĢŁJœPÓc"kĮö\­ß¼Š5F¬ Ķ£,Ó=ŗęš¶7MŠūÜcš¬ŅņĢŹĖ\ŌF-@^6Šé’\Ó9(‘ŽÜÓK¶cџaÓqŌX]@L-€«ŒZ )Ø[=Õ]}M‘c=.T}&ģĖ•Õ \_I­°q‰šhsÅ”Œ"JŲG‘KGųTK„82›ÅĢsH&MBix- ^–ŠóZ:²ŗĘ§ ‰hœzyK“€WDå7²“+uøÅCrG½ĮG…ŌH”‹H$¶ÖŃ-qÖ8=e»Ä‹²›77Ŗ!–ņ2#W““¶‚½Mµ‹1§!ųŌ½_”¾Ąœ.ūÖ’\:ż!|’QøéÅā²U·ȋÜĢŃÅM¬wĪŌ,ć«qՙ 9ÉŲŹÓ»źÜš»Äurū‘Š„ŲtYāZšX”‘ükQĻ…”ŁXPčUæŻ8ĮTĢßF[ÖFŌą8ŠĄÅ ž N õĀ.ī/Ή޶ĘŁ,ģÕ¢$~GŃv‰ĮßøG$I¬H¤¢^ŗŃÖ/įŚ>ŻVåą2žą>į6ž8žć‚&@8.#>¾21ĄHB.WœR“@SŒ’Øo‰š7g+Ćǘ»ņ˜ĀrT`řŽŌUŽ“’#ҽB å­Ź}ĖÜż¶5Ž2¢ć:>@?ŽęßAäC>äž(VEēAÖŃrwĢĢ” P¬•§™Pė7śQ[*…ÅŗŁuŗŁÅāUudYąÆćāpæq>ēuž(Aó ¬ŻĀ6d™[gRžy}F»Õ3ųŻĒEäŠuEźPč)Ō¤˜.žb^¾1ąŲŒ”ĪźąŁ,×ē}Ļd¾Ņ<8:;᜷nŸ^”ŽÜh]5ģ¹ģDĮĪĪžŚ,ŌŌ²yĶx^ģÜ.Ń>éÉīķŻŽ‚Ų>aĆ>Ōć~ŖŻ¶sŽĻ.ī\ģMńÕźW£“Õų~ŌŅ>Ķ^ę/~Ń-ģtmķj³ī¦aÕõžīlcškƒąö®šf°ēŽ”¼>AēīäžīĻĻJAķž^éšó¾ķ|įŃ~ ņ /ņL‘¬dLąÕņŸÆŚ&OņmĮš*>­Ž‘Ä,Ž8­Aęš³6ó_®ń3=ļóGOĢMĮņ~aEoōpóóļ3Æ ł¾õ"(é¤ņKõÉ-ļČÜōŠ»ņS_öĮ¬ö_ōĪ ōū>V’ĒŲJ¶k’OŸf_cbĖqßÉy}P±÷lOöx_õ`ÆBoŽ}ß­ŸÖ+’öŅIG‚DĒ17htņˆū¹—Ÿ‰—³C–ŲŖ^Ļ9ö0ļōho÷¦!µDC„ŗŽ…OģŽō‹!³Hb€O”»Q4F_s/¹HµĒÜ(ÖżJĢX6²“!Ś”™p(üX$…Õųƍ®ütĻ÷æĆ `‚_ų1¾øĶ҈ķhßėąW¼żąŻ,z¾Éµū^_żįyżĀ#ćaåėņĻąą;ö_’ōĻÅ󏑉X¦}hÄ ©g”Ā‚b&Żs0”D…R”8É 211bėų1$H$E–™„Gū’\¾„© ĄLeūźĶĹĀfĖ}7vīƒĘ󄘚0]ŹäøhK™8g¾l  č¾ØE3‰”#«Ń£NčäVģX²e÷ 5›V­X“kݾ…Wī\ŗuåņDć«]¾}ÕBHlŸ@‚Üg˜pb‡ 7^lų ÖÉJ Z¦|¹ņfĶ±zŌ zŸhŅG›.õź–8«ŗ†M3¶ŌŁQĻ>½aśFīžŗyēÖŗ;øļįĮyOŅø9åW•£™$ęFņåŹ©Go޵z&čŹ¼¬ šwńäĒ{?_½yņT½· €XP®ō‹”ÓØ|¶•žu >£nšź%žnp*Ą®fL@æ’ģršAµ"”°B /ÄŠBņņ*č 9hhVˆį†zR;M5SdEnxM6i›1Fo7W[qĒMƒŽ¹ JnH#‹DRČ$SF°Lš Ź'”²J*ƌR°öŽ¢0C/]ŗA°/%tP­†"H@”ÄȤ%ūŽ:3¬–bŽ)ųĢ„ |zIĻū$(‚^Š”¦.Ē$ėPDE“QG…°Ķ”#r÷jzSļ¢Ō“SN?ĶōÓ& „“TSOķÕ ŁT5®täJ¦z\ŗ©„›n 0V£d¢J¾ nU3V©Ī2V™Lb%F+¤ŗ"ŲV曥jÆÅöQžl$iÆlæ7\·—¬|-& Wp-@ÆŅ„©Ķ`Bwæ`Œ §AšŠß’`*ŌŻ§€ņ VlÉõįt^­IbĄ[†'¦øb‹²Ųڌ7®Ka =ę8dGįćNd“OFłBV-¹ć‚IM™ėĢj[޹fmĘ9gĶZ¹bšw÷ē…ŗh9F:f¢Åķ™ā„“Võé›”¦ŚÕŖÆfyē¦'–ė‘gö:ģDÅ&Ü®³Żšį³Ėžl¶Ł^ūm¹¹ÜłÜŒćžŪ/¼įŚ;oµż<š·Ņnø`ĆGųĪGŽĄŗėMžīę¹*žł©„Ļ=z g§žŚģÜžīīæß{š•ļŽśń'č„åKa %(CÖ%€”÷jØ­^-‡n±[č³~­ˆP¢Z^HĄ1aNLZÓ²Ä6Š’āגŲP‘z\L›'F-zķ†$cŠŹŲ¶5–b’ƒcå8G:BŽ9ˆLlćńņøG4Z‘ūcĶŅXĆA~«¼;äÉĀEŠ.tiä#IĀI®š‘€¼äÉ*)D?fŅyžåó6yŖQr®””Dåa˜ŹO²Ņ•§;%¤bY¹Yī°–ó»e_‰¾]r­—ØŹ„ī~i–`¶°˜ķėä0ł§Ģrs„«dęŃ¢9Mø%3šĪ¤ę5˜­ÉLlfS™ŻŌ7—)NG’Sx$'89iN6¢sšÜ¢;I)O,n³—oÄIœčÉĆ}Ź šŌ„§Įś9P Śóžł$hB9¦Nz“[ThDÕųĻlBLŸĶCæhŠ^¶ ¢HkĒQ±ÕѤ'EiJUŗø"jTz.ę`ZŠĪ4y6Ť’B‰S‘†Œ§#„åN{šIŽ\!’ŹFƒ ʟ•k«āR=ŁŌy:uŠ^‘Ųe*ԚZuB ŠŖN™ŚRƦ…Cr'ą^+i½,qŠ‚œrQåÉ5ŸłbŠY¼•±Ųu&+€HŸ“ā•;¾,k]-+1V²É¤^eZ,€¤eVቁ\ŃįoA¬,By–2Ą‚–ŹdTM,Ó"FѰe&–ŗ¬ŗ,;,%4Š€ …Ž4ŁŚ(© ”oRęšö\¼ŻjS;Ń“† ƅ‹~Š ż¼É(W¹cla’YīŻk@°"ȲŗŌłÄ “Ēā¢r—ū-˜‰gćČ'¢,b A!“Q>éå ūh%?zÉM’|…\£ģ¼ŗ X„Bђ…».ńč‚ōµ“¹źŠ–ėķc£č+ß'Åæƒ€ćė·`/Bq‰ĀåL"..¼Ru•ź:(L|Ā…ø;Y‹9ųŃ-|„RŌŖČ4½0†÷‡0eÜwÄ%2h*—:YĪ‹§4*ļCLCĆ l{ą5ÉėĮPŃŹe „[±„_ćä_v•({×Īd>-Y• µ@„Å™Śr—ŠV8Ēä¼nRÓ ¼]“œ÷hÄ@/YÜhiśTĻ{ŽĀ"™ÕīB/^€F®œņ1g,g©³§»ŅÆwkXAa3[b,ųW1>,¦umé-ś«»‡v®Ó2ĖŌį5Æv16Tlf;m\¾+b›ĶڱŻīׄœ6I;ÅkÓP½Łęeø‘Ųm~ÜÄ|¶µ£}nvOKÓ>\i¼å=oz+®Ż÷¶ä°Y0|÷›Śņ#·æĶķļB–•W*Į™nTņ[įc~8鎝J„æ4āÕcx(K{qŽÓnāØuĒEq.ńŒƒņŌ#G¹TõMńY¼ā./łTS-š”‡īćļ÷ĖiŽėT:\į:ĻyĢ3y¬š=o77¹Ń•.7¤OµåK‡ŗŗÅ JŸĆ<ź~kśŠgō«]č—¬śĪ»ĪōÆ?2ä:¾³~É0Żķ½+{ ?ņvŗ}æ/ī {ŻõŽä•7¼½jß{IļĪĒ ><ķ÷^ū#ēŽöĄ/›ē~æųįŪx¹’½ń—oŲą×˜F̘}35_F1@5ō§å©Ć£žŪ÷äY%ļq×oōeuv­^{ ©~Š<ļ‹ę{ErZųĒ—åķµX_LłĻ’O>ģ’ØŒ‡ĄCŃBƒEŃ`yčwuʧ!4¢c€ˆ}°Éģš÷u=ūsŸ†Ÿś3±u±p§[™xśś½/HšGłÖĒæŗČ.°>/Ā(ö7÷[ Š>õ‹ €p¾=CĄlS@śæX0Ą· IæżA€C7ŗ ō›S1*‘tAˆ#AśæéČæS©‡L@Š“ō¾ ¤ž&³Ø¤JńÓ¾/‹Ø œ6DźĖĮ Ģ @#ģ'$l6%Ģ«€˜ü–«0Ąz’)äA¾+ĮīĮBt@‘ŒŌĀ© C^›ŗäłæ˜„3“™ “>'lĆ®³ĀĄi²Ņ 3€IBēŹ¾;¤Ć<’d<éce)½XC ©/v”B4DĄCDĪŒ+?Ö1*FüØK¢BfŪCÆ‰Ćł3&,ĄNT¤I¶1ōI$źk@6TEg«D¶QDąĄ@üŽ@æ9 ¤O ¶PŌ£ŹÄ2F6ÅZ“*bŒް(TģŸMlDf(g™8Ü>'R–"“F%ĆF‹1ÅWÜ#b˜ņ^,!a¶p\˜\<ĘL ņsˆe|¦o½[L™2¬Ę 1¶±X“¾H‹YA1ˆJĀĒ0źæ…E{ä'ƒ, ȍ¹ĮĪ3ČbĒ]sĒVG!däŠÉI0H늬€3)=²¬Ńx™ŲמּėƒC#żŃ·IXUĢS1Ǿ¬RĄĒ—õŗ“•Ķ”yfģPy՝ÜT©ćŁŹŒŃÓIʃ|%9“=Ś/™Y¬Y֋Ě8ŒŠŃAŲØÕ%Ÿ]B—ZqéȰ…gåZUņŚēńÅ.­¢Õ*Ø=ŪzJŚģįRuu®lŠøU¹wŸ·*@²ÅQ“ ½½µ¹… ž[eŁlŃLĄ œ˜Ä©ÅATFUYY»Ż*ø%ܐš[ĀĮ,,Z¹ĄŪ c×Ģ §Ķ źŪĻ- žlĮu]ŅmØh=¢‡ĮÕŗ@ÜĶä ­…ŻŲåŪ#ŖŹtt SL]lŪŻĘ5\ĪÅÄÉ­?µ\‹+^µ:ŽjŲūˆFĘż·ēżœč%”ד¾¬…"ŻÅŽé‘]Oj^ 2Ūš…$ķU”ņE&ĢE_¾Qßbß{”Õ÷Ŗ“å£ł\ū-YüŻ#żÕ6žŠķ½ų%”éą#Ē5DČķ¾^ ąVźŻGbąęrĆV>6!ÕĶŻóµ`’Õ®Kšą¼­ąßjC„N86ڤ¶KE†6n£ÅĖ# nCޟ¼»"š…aƒ3ݾYi«ß6įf»O8`&āJ3bÅ ā${Ż%N޼'&^)†»^#ž^,–¶=-.£d•$/Īb*v#+ö6%&ć¹dāGāčˆūBcāį5Ž6ö$#ŗ2Ŗc;Ęaõ (ćc5&ć?Vż²Žöµćœ1äōįćėāEfd"šxaI¶™FvdB«aBöbM¦čåQ&e9²;÷-dJf.£įÓü9å(^dP®*ZteTždU¾ĢuĖdL®e3†e³{e^’¶å6žbZŽeaödb.ć” ę<ćeYnœbgĘdhvW{įCÅĀ‚‰c5“™hM“¬Z‰Ą>±Č˜FÓQ—šęÜź k±€äŒję ]ck޾°ą­¶r“Ś’KŽšĻ,˜,’e oOˆØÓD‹€V0.³Č4č®=ę_¾g\6¤".JAį}‰ " ŪcÓĢ,‹H*ްQUKĶĀLΟ\JB‰•zš sDžāŒ>™9ī`|žOnU—³ŒSU՘óē£^I˜ 1ž•Y /HKUH„+ތ ­XįαЉŲY$C”FŁ6ĪŃų ¼”’’Į“¦V—,”“S õ wŽćŖ€0¬hėęüGūœddf˜NĀ Ā@ŖūŹ/ –Č»µĢ*™_… œœÖgDåä£ł±³Ą­.9Ļż æāžØ •Ō«ē Y,vĘ&!lĀF싁(Sl–@œ±mĪcÄ Į² ‰–h!h”Ÿs–2ŪÖ_Į±O)P>Q—ØEfL‡ņIGõ-æō;Ou&õ#ĢtF_uDWO®Z·u =õ”‘s"Žu…²ō&wuVöHužõ„śsZö\×õjvö[ov“éõsQVW…j„•Ō ⷐˆ}™b™töŒM:ł$”QŅ• _Ebč`‰””pÉä[q*éå†*†"“RÖTœšmŗł&w aIP `Y9r[•v_xt-™‰s•ÉŠ~5†‚õg˜˜p‚ŌØ£‘Jźfh‹ŹG—’ųą”„w•óŁ(j[”:^—9˜V‡iNz¤ÆŹ:+‹”ÕĆęlŖ1J«I±ņś+°Ō±(NméÅьÓ’Ė:ūlv¾Bū‘“ÓZ{-¶“U›-FŪrū-øįå­ø+•®ēŖ»nJä²+ē» ¹/½õgoŒų-&Ŗ/æżŹėo·w*0Į{0Ā +¼0Ć ;ü0ÄK<ńU7[0Ęk¼1ĒZ{ü1Č!‹<2Én¦[2Ź)«üä¼+»ü2Ģ}µ3Ķ5Ū¬ÓĢ7ė¼3Ļ%]Ü3ŠA =4ŃE}4ŅI+­ŻÉK;żtŃ9C=5ÕK]5ÖYū{µÖ]{ĶīĻ_‹=6ŁeK›}6Śi«½öEM³ż6ÜĄr7Żu8·Żyė-Ž{ūż7`a>8į…~8ā‰+¾ųBn3ž8ä>õ9å•c$Øå™k¾9ē{ž9č”!‹>:é„›~:ź©«¾:ė­»ž:ģ±Ė>;ķµŪ~;ī¹;orafce-VERSION_4_14_4/doc/orafce_documentation/gif/DBMS_RANDOM.gif000066400000000000000000000174621501757153000244060ustar00rootroot00000000000000GIF89a‰p!łR,‰‡3f™Ģ’++3+f+™+Ģ+’UU3UfU™UĢU’€€3€f€™€Ģ€’ŖŖ3ŖfŖ™ŖĢŖ’ÕÕ3ÕfՙÕĢÕ’’’3’f’™’Ģ’’3333f3™3Ģ3’3+3+33+f3+™3+Ģ3+’3U3U33Uf3U™3UĢ3U’3€3€33€f3€™3€Ģ3€’3Ŗ3Ŗ33Ŗf3Ŗ™3ŖĢ3Ŗ’3Õ3Õ33Õf3ՙ3ÕĢ3Õ’3’3’33’f3’™3’Ģ3’’ff3fff™fĢf’f+f+3f+ff+™f+Ģf+’fUfU3fUffU™fUĢfU’f€f€3f€ff€™f€Ģf€’fŖfŖ3fŖffŖ™fŖĢfŖ’fÕfÕ3fÕffՙfÕĢfÕ’f’f’3f’ff’™f’Ģf’’™™3™f™™™Ģ™’™+™+3™+f™+™™+Ģ™+’™U™U3™Uf™U™™UĢ™U’™€™€3™€f™€™™€Ģ™€’™Ŗ™Ŗ3™Ŗf™Ŗ™™ŖĢ™Ŗ’™Õ™Õ3™Õf™Õ™™Õ̙Ւ™’™’3™’f™’™™’Ģ™’’ĢĢ3ĢfĢ™ĢĢĢ’Ģ+Ģ+3Ģ+fĢ+™Ģ+ĢĢ+’ĢUĢU3ĢUfĢU™ĢUĢĢU’̀̀3Ģ€fĢ€™Ģ€ĢĢ€’ĢŖĢŖ3ĢŖfĢŖ™ĢŖĢĢŖ’ĢÕĢÕ3ĢÕfĢՙĢÕĢĢÕ’Ģ’Ģ’3Ģ’fĢ’™Ģ’ĢĢ’’’’3’f’™’Ģ’’’+’+3’+f’+™’+Ģ’+’’U’U3’Uf’U™’UĢ’U’’€’€3’€f’€™’€Ģ’€’’Ŗ’Ŗ3’Ŗf’Ŗ™’ŖĢ’Ŗ’’Õ’Õ3’Õf’ՙ’ÕĢ’Õ’’’’’3’’f’’™’’Ģ’’’¬÷ H° Įƒ*\Ȱ”Ƈ#JœH±¢Å‹3jÜȱ£Ē CŠI²¤É“(SŖ\ɲ„Ė—0cʜI³¦Ķ›8sźÜɳ§ĻŸ@ƒ J“ØŃ£H“*]Ź“©Ó§P£JJµŖÕ«X³jŻŹµ«×Æ`ÊK¶¬Ł³hÓŖ]˶­Ū·p欝K·®Ż»xóźŻĖ·Æßæ€ Lø°įƈ+^Ģø±ćǐ#KžL¹²å˘ø3kŽĢ¹³ēĻ C‹Mŗ“éÓØS«^Ķŗµė×°cĖžM»¶ķŪøsėŽĶ»·ļߥƒ ’€ńćȓ+_μ¹óēŠ£'a±øōėØ'“޽»÷ļѵäž¹ųᢀU_‘}G÷įG•æ~Fūč;ćĒŗæa’ö ż§}NT`~–(•‚ń}ŌƒEč ‚é­g„=X•„aHįc6¢@#h"U¾÷!h%xį„ µčSŠÉø’āaų)Ć™ TŠüøĻ ÓéHŹd$AFꈜõ%—d‡/&”É$ž™Ōs“ųŻ0„Šķē%E6ŽXŲ~ź9y$‰oäž2b !§Aņé˜dš •Ųßyi’õ$ʘLŗe„D|Ŗ)›{£]“Ō£äœīÅ Ģ—ūIØÅŠć’#ł™=fc€Ęµš‰qā͚Ż@hG {ž D ØbŠŖ$ØT–٧«’j†ŸØźq g”wF»ub³4ņaKP&āEś*€(čAh`Yh&+tƒµčŖĖnŗõi‡†µC&éØ@uī3‰¹Åƹj«&»’~Ś.ł„Ø&ĢŽ$vž*šī£0rŠj¤źAg¢©„A»>Z4¾~IØÄ"O9 Ø ļCŒĒ„ģ,Œž"t%¤óUžs-¹0˜śÆČ]›§{<Ę<čĶ9ŠūÜB¹*³+rė)^¹JR'&¾ČõŲ«ƒĖ-toDH‡-öŲd—=6fW/ś*ŖQ?+ō@MĖźˆ~¼,£*ŅÅeŒlƒe‚2Ļ€*Søx¦ ä„ᾊ·‚2~÷+­Ģü>ä-e—ė½#„°{?¶ śčśü)“>«lž%ńĶŗĘßrĢŌ—¤ž¶KŒ$īĮŽiܔʬ¾O®*+¹Ū±J3l™ē•ēvēa«)|³ī9ōa ĖõŁz\ ŚI±“YĆüwAʟo,B¹š(łp7­bCåķ ĶĢ 1jš`‹Móš²¹Y\©˜66Ÿ×Ɍ{ f¶=ÆøĪ )[^ø6äĄ¾)!„LķR@µ}å‚ÜTüw ^ękį «D¦ ¢Øƒ&|Ķė².΁>“į q˜ĀÖģ.””iD.ˆˆJtĶēŅĆv…Q„¢SXˆ‘).ʋqIb»:±ė3£'ȹū˜ķpģZ{ā«8Śø„;nłzŲW÷*ž4­łZBњ’Ómź”D–Š–|DW¦é*T\²ē­„ž«ŒF•«E UĒĄńU/S1ˆ/,Įg«3\&z“ZxMkxęŖ¬@Ł4Gœ%d^š­nwĖŪŽśöŽ’©A–DAcečėŃtŗ „CI_ ;ŲČ6ŗ×ȝ5³™ˆėu9KŅÉ,T„qrTĮĢ CQįNÆv‚{Ägœ·­uÆzŪna·Į‰rwØ=M)fĮ4jķhTźŃ–[Ł£­F”ĖHõĻÜ*ėPŒ™u³ŲėTļŪŻh"¼ŅrÓ\‰f'R I;¢³Ž$LG5³ĶlśäĖŻšŠEŖö-ˆŽfæXQvT+ącdVS–-—¦ >ȊY\į"ƒĀų…Ģw÷+¢ \`r’³+eĪŗ8,0>rH}i„śj°>ņkŠ)|e°š3©K±,X]J]Ā–ł+Ys“Oü^6µÅhū(·|S Ķnīž”¢f¾j¶Ķh}³WĪģg@bt͇¾³•}”ßņ– z W¦‘¬č®,ɛģ4Wā j?Šz+Œ.µ%rO­R«:Y¬Īʧ_­ČXcÅÕ“¾‘­Æ¢Ī\‡šŅ¾®5Ś.lBīŚ*ø.v~Ž]•T+ŪŌĄ~6“›)ķG2›*É®6p®=•^kūÜ–J¶æŻ›pGeÖ䞐¹”2ītėfŻOq¶»)o§“{Ž·©wSŠļį’č›)÷ī7mž½oÓŌŅ—ŽŪ¦óųŁR\)“Ré|X; —ÓĆ®³£¹lh¦ŖśįI‰8Č’,éA£øŹ¦(±”9ńGw¼ĻEłQD>D—kÜćĻxÅ7s–[Üäd޶ĻyéFKč÷•¹Q ŽfņÉļHĄ@EW¾ł§U:ŚŖŒFŲ*v¾}5śS•^š§•®¾¢‰Ś*ע͵[ęZĒˆtń–&åG÷ś×ńLķ6/v bź–ąĒŲńø“Mx,¶Nq‚¼lļv-‘Sn³÷“ڹ{hļÖ#/Vʐü“”K ÖīŖīkWGÆē]åļ Ż÷ę%Ę- ³JŸCčĶŹ„ŠŸĪ¹Ø‡Æ˜W’ē N>јių“ŁsŽ!!gznö>ļ0‚pA¹wĖžÖš³įĒhiV’°Nžņ›’üÜ”~}nUęO ūų¢±€7%Éė ¶vb¼ĶeōžĀÆWyėyvŌ±Zń+:1Qņ0 (u&'X‚) —)HĒWŖGVńx˜tlō^óWܳ4fuŗSulåv…rXg؁I¶¢7V ŖFvDay„Öxa†wū”wĒ7v:‡hIĮu !X0XdŒƒw@ˆR7„:|$§„1÷;ē„ū‡h8WƒByiö„-ųs€†|}WrDghż×s0eƒCƒOA„–…{UˆnųrE7…Lø(č\ §|ń±pųB­'p¢†Bq„øGr˜ˆ+bˆA± ƈ˜|‘(‰ō†Ą€–ølÉ·‰ź†ć‰…H‰¢Č‰¬—1ƒ„ųŽĻ•ŠĀ±Š?Š®°8#³ųŠ˜Ø‰·ČµŲ­ø‹å–|ŗŒ¹Ń‹Č…č1Ž6į’b ”#Ś52§c“Q62hš(÷2YX;ÕRič§,[XŒv[»“Ī5Ix7qu:[Ó>6&Ł:Dy0²'9W‡"z‰Åī¢$\P}”W* G©YYm)ӕ‘®Ē_wƒ%p;„B(z¢#֒+œó;Uƒ5$ó…³t•ņŲ’Giķ*š“‚)ēq?†bĮ¢/āw„li˜•ˆ§±•ēčo9”™Jˆ9—FN£© šżhž ¤Ł‰Xrvšp©™”QŽrłeV›³ł›ž–˜…]t›™±š-Į™¦ńššX˜Å)›Į9~Ź6ÄéœٚŠÉŃI€ø–kbPfóĘÉ&ęÓˆ†GםÜ)vdž+Į†/ŁIęɞwrCWņɜsŲJšy‡Q8)ÄG˜ö’™|Öɛ7”hpX›8ņŸa Ą)„¾Y ńéY ŖžcįI£•ŗ …¢¹Ÿfƒ„ŃTł“+ń)w…  śžü †:”U©•*,šwŁøsA³vČa-Ź”£(ųƒ)ŗ-—‰ ō ź#FƒlF“5™ć‰'ōBW÷i?³réł£„ņ¢÷ł†]ö¢d4»rš8šś…Uzh÷Ø7Ö%œnyYõ锃Q¤p fNJ†ƒH£y¢€f€PdŸĒ’Ŗy„‚Ź¢qŖ øØėI*vaQ£ˆF>x™N×^ńE•H ”F”„źŸÜ¹’lj¢!‘+Ś5¤Õ—!iŁ7¤’ERq™!¦š1„®z,øš«Ųu^Ö'1p«¹¬Ā:¬ÄZ¬Ęz¬Čš¬ŹŠ¬·j€ĪšĪś«Ņ­Ō:­Ö­ÖA ū4 Ś”œēa7Vʕ€j9§ é9Gś©¤źŲB Nzīś®]¤ņ®öÆų ÆśzÆūšÆüśÆž°ż:°K°{Æīš°Nƒ$ Ū°ļź°ū°Nó+Ņ”§Č9wyhąŖ;aƒ(¤ÓŁY.ڟDŖ Cv©jBč’®ēłC6zÖ2©<‚-É”\=Š™!›\Z*”Ü"ņ¹CKZ_£éžmZže;ŪrźV£Š³ J2ŹØ_J†Pj“ō¦$ K{w^ź²$ øźU&Ź­#{®VŪ„ęŖµeė£š³©\Š Š„ŗ¢-[ØƒŹ¶"Ŗ¢š§•Hµt›³šµ±“(ڶ,Q™’hᨀ«Ÿg¢wĖ©tŖ”fAJdk¹āÉ”hKø~aøs‹ø–‰5ņŖ7zIŪ9¹±¦ūŖr+µå[z³[sŚŗR»“‹‰—«ˆ·›²¦9ŗKPīŒĮ[§æ+Ćė…¼Ø® š¼‘±¼W؊Ī{¹‹›“‘±Ļ ½Ö{¼Ń«‘Ū ²ŻĖ½ Š»mՋ”õtC²HŽ+BŌ¹›ā‹”XE4v–‘ō¾åĖ„ɽ ¹aéY‚šįci)|zŒśĖ³ r¾Ōė½j§oU@o„+¤_ӘIx‘Ē-µ¤Ņ¦{Žēyī…r}|> UP=”A]M~ķĮ7ž”¼ŒØwlэrč5]čR›ęˆ~X>\VžŪZ^Ø­Ņ+ĪÓžĢŠ:mҚѐŽčqšĘ«¾Ó»[ź@„Ł3źm„mćŸN¤Kԁ.Ś„ié“å˜«ź€¾åJĖҰn/ģłĖā›=췮ܯ~Ś]ž™V)ė|¶ģĢī¾ŃĪč¹Žźģ׾гžäā›čĪ.ķŎžzXĻŅŃĪų|Ōī^ ×Ü÷<ļ7Ó'ņ]äEmĪŅ_Ģ»žžčŒ&®šśa¾Ī¢œšÉ š ?Åæüš”1šœߢŽ|ńϜ‡’?ķ’½X)ć!_²_ņČ\Ģ(Ļæī+Ÿ-($’ņ6SĪ4/ņį|ó3ÜĄ:oó’ź=ææ)ōäĢæķŽļ ēe£ō˘s—ī[! Ś~źĘ¾S1’@’ķ$ĶēĪ;õb8ō²ķµ5}†vĖQWļd­õ¦īŲTMŠuöžńč.ŃŻ®ęnßOpB_įQļķ8ėõKöĶRßÓwOyæ ŌŁ!³„QāDŠ-^ĘQćFŒ=~RäH’%MžD™2$•#Y†¬÷rŸ2™_ŅT&0ę>4ūÄģc -čĖL?_ĘH8p§@š-UÖ u`S§RmŠ,ŚŅŖS®]½~VģX²OĖžE›6lŒœb·2Ķ Ē„ū2½Źs’˜¼;늹;óĘ@Ąpå |;61bõW™8Ó$­j-_ƜYóf—œ=»Ųlä©Ró¼cßNbr²lzzęĮ}“2M} “4fŃoEÆ$²šhŠōGžł’wrę› ŌSģ:b…·LGlt__×ŗcbüÓ&1ÄŲŽ.Ū[8zā/÷æł|śõ‹Ė·ŸlÜ趑« . ¤LzŖĢ?dš,ü„02ģö‹Š3 /„÷SĄ ?1DĘD$‘¤;+Q­ ū‹ŹĮ_„±¹cō-itĖD $kF%ƒ”±G")DŃHo<²I'5|ÄīrŒ2Įą”l1½*·ä2¾.ҽ/OZ‘Ź,±3Ķ#ĆTÓ²ēć(N9ētČD:ŠģΤŚäóG6ūÜPA%“Ķ? ŻÆ-De“QuŌŹH'„“Ņś µ“$33å“SO-ĆōS1E%µTS…<5=ESeµURCMVWg„ÕIYM}³V]wEōÖR}å5Xa!ĮVŌ)‡E6Y[•5©XfŸ…v3g=]aÕhÆÅ–Įi;å/[oæµo[Ns·\sļ;W·t×eŌt«m7^yCK·ŪyļŗĢtÉĶ·_ 7Ӏ’%ŲՁ+…·`…ń=˜R{NKO‰ėtiāÅ,Ęų”/žō:ˆŻ­°LzÆ$‘ććLvå{U–ōL&½L‘åĻdFtÓŃ¢Õ$_ųŜ„­÷f?É%EüY³¤=Vh4ĮŌQK’‘Ž8h§%6ź§a.qiޒҵłj3³ŽyģQ»®ś\ÆĶR kæ.{ä£C\d¶ßŪ«ŗēęšē«bN›ķ¼·&H™&9H¤nzģ†ÖšĘYkæē Éš»\[| 4źŠķŁšŽ¼Ė½ÕLxš’$IńžīŗķĄ}ˆ”¬µĮ&»l"#J=†ŸX·‹²L:ļIq ŲćM"ā}®÷0Ó%?ū#1ă2Ÿ(C£õĒ~Ɲy¹]öčy¢’AĶ„#é•Öšsł]žļæAņ|ŸŚņÜqžČ«ķx¬¹ß¾łīۚß÷r²9„ {œ)ŚŌÖ¾ÓÅķ}+ ÷!A €nr”#ÜūĪFA–£CĢ M —=*Š\ū„c ’z֘ĒŽ)Ŗq” ņĮ”•Po6t SZؚŠį%Ȅė€fCŖ©My)ō_ß "¼™th=!Fš:DŒÜŌpj+lO§Ņ!&>Q ō!P¤‡B^Q}ęb5ØE%š{R!ŃŅgĀrNX“#õ×,"’ĶŒtՈĮ8śĒ]ĮćŻW²ä ’„„ZįųČ’nõšŠW2¶IŚüĒb}“£)ɕDr”@łdčwĮ6&GV„,¤~,9IQJiŽkģ+”6Mńdū«%.4Ė–3d·„d.Ķö­P…2–蓌"©ĆI‰Łib£&'‘9¢ ’­Ž,¦óJI:²—åĢ¢.ŸÕL_Ž˜X4§*„Iʈ œé'ŗ¢łĢxŽP’'øŲyÉ’¼S˜żT&<—¹Šl‘ ¹{rˆEI„&TYČ=·©¬œOgóD(=K8Ńp&[õČ$Ī—•×”AuKĻØĀPŠ„†ågHKzP»d Ŗ ś’Š'L” !…”ŗ~{ląu:T©Ŗ Ÿ&½ÖĆĪłūķƒ‹ŖAy`ŹĶÕ „›C<å<É0d†u§[­c5 D/öīuzM°Ć„ÜT+ŁÄQ«Ø!ĄÖ°‡E,b±">!e,…oq”QG›™r'£Iõ¦>=RٟNµH!aig={Uvˆ¤…ń˜M Ռ®š-II;Ś™uō­“­ź^DÜø Œ‚š […ā·N}źm;Ź)Żˆ é =&Ŗś*hr•»Ü2¦Õ»Ü%ė1³ūѼhõˆg{^žӕXń)vŁk!‰t¾UmåxÕy߳ڗæß½Ō{÷łßīŅōæk5&z LąžšZ—Į.nmĢązN˜Ān/4LįĢb•扄“+SÉa˜Ä'FqŠU¼b·ŲÅ/†qŒeŖļL“ö‰N>Ó¾LĻŃŲŗ¾½¦¾é·é‰ß>hÄ'†2Šżē`k -øĻ NX”„żÅ”įƒ „›xYā@ē5×`‡(>õ”hʘhūĆ"Œü„hcOꁆ|1¦GŒ‰™ #sЁ¶7& Rz mx”“*)åGŁAY”VN©eAUžVQ–[†ŁeVX†iꗁé!šg¶ јR¤¦›7ĀyU™t꩐ŽÉ©ēŸUi䠄jØglŖč>s–Õ’č¢ž=:–¤vGir•z)X›fz\§^Vއ–jꩨ¦ŖjŖ‘ŗ*HF$*u¹ŗj¬*N‰gG»ņŧF³Āģc½nT¬^æf4¬KĖ6v¬²‰śš&•¹é­±×";­GͲŌķbĻbī]Ɋ[­”ćZ”n]å^4'v8}«Ųŗ~ÖŪW»źb$eń&„™÷Y¶£˜ T‘-GސYBąUĘe…Œ$ØÄ>,ĆE̚k70iŅŗAJDļmŪ„ėCYŠ€}ņ6ō!m“Š@|š” ‹0ÉÆ@Ä$Ų1q“°Vó@A§—ó@KļIŒ@;3-[ŠīSō@“ ’kć©”®2"³œml)„Ÿ½-pÅ7łF›lØĮ½Ļ‹Ö£°@ĘJĒum”‰l/,3A<½qA7üH"ÅūtŚ £”®‘‹ö^ų:¹!1°rŁļAMĖ+äM1öe’‰ˆ-8pčÉųŻs”o]ģݰrÓ`»ćī¦Å`ø×c$¢Éœ[¶A"ѾŒ޶æ–5§8AµcfsI#ņ8čāt6ˆŒÖćyC3īŚ$B¶Žz ”•Rŗ+~¹¶ś#’DėqYåH¤[± tS+Ÿšr† Į‹vl#•Ō‚>ƒH0tø£ ߚę0ˈń¹ŁJ’P•ØšU(L” WX*…šČd„Z[ >7Ćõ0pä! ~žS¢ŌNz YćĘSĄeĻbź£ ’&10׊({Œ»AG¼ż$M²” eh9…@cH¢æhx;Śäpc8sāsąÅ9eĄ‹‰LƒQuĘ1ˆFuqi’‚”ńŒ6"“B˜ M·Ā†Uö4žg’72 jŁ”2c^&ÄXv¤Ć @1˜g™ę¹¹gI\¦™c yÉØBŻ}©čNATd†~1xčˆ"Xä|ģ§Łt]~‡Ł‡ ž%R¢ē}ų(˜ Ml‚ćCŖÉ'%B?J6Ł®±(ā@ʹO ĄöøĻ‘nzŹ)®’XŠ Äø¹ĻŅžčŠ®~%ōɘ™aĖ×B™ÜJ«a¾YwЦpĖ™£Š šŗ)mAbøŹa»š *1žKć«“.$+ĄBʀfl’ę$¬…NVˆf…s–ˆh~“°ß‘÷+4+HĢ/™ ņµ ± kByžYµˆ"„)½Ģ1oŽ:q‡Č–Éz~ŃHßœ]|_’rÄŖ@„Ž\ŚBÜ.*pбL’ŌZķ¤Ź$+­ß¬?éŹ Ļeõ“öfMšyX›ķœ¶\c÷ėōgåI#Õ«^wöirÓMуņ½WÜZ·EMNØ÷ܾ÷CSŗųÉ~?¾ZeŽf®łęœF[ē}ŗŖy•nśéا®śź¬·īśė°Ē.ūģ“×nūķøē®ūī¼÷īūļĄ/üšÄoüńČ'ÆüņĢ7ļüóŠG/żōŌ;orafce-VERSION_4_14_4/doc/orafce_documentation/gif/DECODE.gif000066400000000000000000000064751501757153000235460ustar00rootroot00000000000000GIF89aÄb÷3f™Ģ’++3+f+™+Ģ+’UU3UfU™UĢU’€€3€f€™€Ģ€’ŖŖ3ŖfŖ™ŖĢŖ’ÕÕ3ÕfՙÕĢÕ’’’3’f’™’Ģ’’3333f3™3Ģ3’3+3+33+f3+™3+Ģ3+’3U3U33Uf3U™3UĢ3U’3€3€33€f3€™3€Ģ3€’3Ŗ3Ŗ33Ŗf3Ŗ™3ŖĢ3Ŗ’3Õ3Õ33Õf3ՙ3ÕĢ3Õ’3’3’33’f3’™3’Ģ3’’ff3fff™fĢf’f+f+3f+ff+™f+Ģf+’fUfU3fUffU™fUĢfU’f€f€3f€ff€™f€Ģf€’fŖfŖ3fŖffŖ™fŖĢfŖ’fÕfÕ3fÕffՙfÕĢfÕ’f’f’3f’ff’™f’Ģf’’™™3™f™™™Ģ™’™+™+3™+f™+™™+Ģ™+’™U™U3™Uf™U™™UĢ™U’™€™€3™€f™€™™€Ģ™€’™Ŗ™Ŗ3™Ŗf™Ŗ™™ŖĢ™Ŗ’™Õ™Õ3™Õf™Õ™™Õ̙Ւ™’™’3™’f™’™™’Ģ™’’ĢĢ3ĢfĢ™ĢĢĢ’Ģ+Ģ+3Ģ+fĢ+™Ģ+ĢĢ+’ĢUĢU3ĢUfĢU™ĢUĢĢU’̀̀3Ģ€fĢ€™Ģ€ĢĢ€’ĢŖĢŖ3ĢŖfĢŖ™ĢŖĢĢŖ’ĢÕĢÕ3ĢÕfĢՙĢÕĢĢÕ’Ģ’Ģ’3Ģ’fĢ’™Ģ’ĢĢ’’’’3’f’™’Ģ’’’+’+3’+f’+™’+Ģ’+’’U’U3’Uf’U™’UĢ’U’’€’€3’€f’€™’€Ģ’€’’Ŗ’Ŗ3’Ŗf’Ŗ™’ŖĢ’Ŗ’’Õ’Õ3’Õf’ՙ’ÕĢ’Õ’’’’’3’’f’’™’’Ģ’’’!łü,Äb¹÷ H° Įƒ*\Ȱ”Ƈ#JœH±¢Å‹3jÜȱ£Ē CŠI²¤É“(SŖ\ɲ„Ė—0cʜI³¦Ķ›8sźÜɳ§ĻŸ@ƒ J“ØŃ£H“*]Ź“©Ó§P£JJµŖÕ«X³jŻŹµ«×Æ`ÊK¶¬Ł³hÓŖ]˶­Ū·p欝K·®Ż»xóźŻĖ·Æßæ€ Lø°įƈ+^Ģøqį"KžL¹²eÉ7kŽĢ¹³g >†žLžŗ“éÓØ7Žīø:µė×°cn­Z¶ķŪøsū„­‘·īߥƒ ’źcńįȓ+_NōøEēĢ£KŸN=%tŠ×«kßν»Ćģ‹+óN¾¼yķą#ņĪ`Ņł÷šćėN±u¦‘ŃČßĻæ’lŃŻ7™{žhą ÅpŁ‚ 6蹃F(!ƒ¢Mhį…fØ”evč”UcŌEßC”)3eĀ%ʇ×,¶ŲԈdĮŲŠj̘Ÿ\2ŗØćŽ1喏 ŃM¤ų<&©dIHzå\޾2^\M.i啽‰Ø$ŲķU%–`†YŸ– eŅ„^_NĄ†—pКlĘ)§†nŠi§Pij•ē@{:ŁRŸūųčPƒŽi(€tZ؞"ZŠ¢ *éNJ„ؗz$ØX•NźéDBu)š™²vPØ<”śéŖ ©ś¢£x¹JŠØrŹź­/ɺԜ•aŹ­³ŚŠė°*銫±ĀŹēC“˜yP„įPćI;²’ĮЭ¶„r“©CƒŠ )“1Š“m¶“®ė)²Ą.»ed™ŒV/1죌dūˆY¾Õ¹›Äܰo“ײ«šHī¶Ūmm9§I{Ÿ@a˜™‰{™X;†~ę”Y&ś5«īĀ(+›²¦g±B1L9‰“@#2ł¢įģ@’¤±ĻĘĆ„Éaˆ›šŹH—4HšŖœ,BŹüńĮ’I[ō>ŠJf¦Ī„af ā¦{ņŅd‡W¶©æ:}\Į"gBŒĄ7g¦ ¹­0݁M¾8×ŌšŁ<ž}čžVČ!Ԉ‹Fāū€­oāŹH‹n×%f¶Oé²Ķ¶ŗøą†N"āU}‹Š½aXNu€>ļ#IdD ¤`‘Ņfāó¾ĖčžĖĒ»¢—~gÖśćBæ÷ž^ņa?c™„Ÿ*lBĢ+_^õX:ßŖŚÓ#„½õŻ}o„öČs|‡ą'-ž’ä£ĻņĖēSŸ>Ņė+پüļÖīóÆ\’÷óžłöW¾ž”ģCŪóņ¬ų Š€ CąŽx*^M¦‚Ģ /S@²K‚:¢ l@čAᐰE"|Ķ Kų›~(…®q! q#ĆĮ055œ”lrx ¢†‡:Ta;č²ł ńV@,O“’Ä#š¦‰żYāČ-*ĀbF, œ6ČÅ.NnŁ"ÆĄ˜1zńŒhlÓBĢ('2noiŒć‚ÜĒ Ņ!l”£%sGż17HŹ#›śŲœ“@ÉiŅ» ’(<"ZŹlŒtdUĄ#ÅŅ )^IāĒÉŚe‘ $EÉP¾+”4åm.‰H£h2#‡ģd"?9J„©ē”S&݇ŹFbŁåGˆŖWڲ”Žņ%™š§J\z2—Čü„3'©LX‡•²ģ‘ŠiČā%s“äå79)ĪGŽ2›³¼J*Ē Ģē“R#‹ó7ŃĖf¦3Qµ f4ļ]¾óŠź¬ę1Ū=tŖ^dnČ<ĻROv–s. t(8™ ĶsŚó™VY§4W©OƒVÄ_;{IÄCgQM2F£Ž~¦µ›•Ō„”™ŅJz Y4ŸGĀiAÉIQ‹PK'žōhCņSkõH ĶāN b9Py¤^!ņ£HH:+3ķ«¦«Iƒå2‘»"=®Ŗ_՝7 Ņ·}b¢:ėDĻJBĀ$Øå'GB69±®u 4LŖAlj֊ąģF“’jHŽC€ł&\‰™V(}ˆTv =Z_2†Šrš¹—å®¶/ec[Į»Šöt“whÄčµŃ¦k72×½pW‰>” £u“fłÄځ ÄM8;Xi]¢QŌŚ›xTkEg$Į2t³RĘU BŒįMlQģtł$ݿѓ Ų½émĀUŁY53ŲĘ3 żŌ+°T1²’“Ģä%;¹ÉP~²”£Lå)[¹ŹX¾²’# Ė~'ĖUcU»ŁaˆzŽHL¾• ‘+ˆÉfŒ±ł‹ÄĶ̰!…ŲķfÖ"m뮦Æ|õ •VV”–Įläćģ‹x®kmŅ`­CGųǘq{G¬©O"Ē›®0—[÷g}INĀ䅰ŠöA4ųęjәŽ5eMėY§aæøęo®w­ė^óś×¾6°‡-ģbūŲƾo™Z§dēŚ¾7H([™ ŚŌ ¼a1u›jŽķ*Ų–¬xq^žŽ·µmPS›J «É”šēv§Aa+’®˜µ–Ū›”ż6Yy#5»ć!ędrGo¬9 1v\¹s„0ēšÕÜ©¤ŪŹÖ”Õ7€Æb};éZܰā†ų@ö¦\¹ŽlįWY÷Ac’÷2ŽKŻh€F2ƼnYø]EŽ×|ŗ\å>1Éö7°…Ģå;'–Ć'~ŁœČĖ -ˆ·ÓÖĢ®F [] Ŗ§nUļ–ēNMķ@žLĢń¤hÓ­×½³Q™÷2p8ÕGy˜v>maGל=ԃ¬.PJƆ# ¦Ńǧߵ¦ča÷3fßK?Ä ž2\Æ÷Ęūˆ>Ēŗē²8| 2EŹ×Šq‡x$*Ä­ÓĪl!õ²Ä¾ćųŽ;ÅrƳ§&ż×_5nžÅ<­N1ęĖŌܦ{Ä\ö®~ŒĘ’3Ž£?ņóVŚžYśū_)µÕ’'//—-ā‘wڧõā/&”~žV~ogrpĮ²WL€ĘuZÆ÷A’ätņ7×ĒwH%÷"HJ&ų€}gN؁ńn’GO˜‚„‡O07ƒ<—~āz×O ē‚Aį€ē—€(„ S‚9؂>Hƒ8h„5˜xB„ŻÄƒnGf8‚„:ȄTˆ…™ōƒQ{4†z*ōd˜†g$kČjØGįц3ņ†dŲprhEx˜‡zø‡|Ų‡~ų‡€ˆ‚8ˆ„Xˆ†xˆˆ˜ˆŠøˆŒŲˆŽųˆ‰’8‰”X‰–x‰˜˜‰šø‰i;orafce-VERSION_4_14_4/doc/orafce_documentation/gif/DUMP.gif000066400000000000000000000042671501757153000233650ustar00rootroot00000000000000GIF89aNYp!łL,NY‡3f™Ģ’++3+f+™+Ģ+’UU3UfU™UĢU’€€3€f€™€Ģ€’ŖŖ3ŖfŖ™ŖĢŖ’ÕÕ3ÕfՙÕĢÕ’’’3’f’™’Ģ’’3333f3™3Ģ3’3+3+33+f3+™3+Ģ3+’3U3U33Uf3U™3UĢ3U’3€3€33€f3€™3€Ģ3€’3Ŗ3Ŗ33Ŗf3Ŗ™3ŖĢ3Ŗ’3Õ3Õ33Õf3ՙ3ÕĢ3Õ’3’3’33’f3’™3’Ģ3’’ff3fff™fĢf’f+f+3f+ff+™f+Ģf+’fUfU3fUffU™fUĢfU’f€f€3f€ff€™f€Ģf€’fŖfŖ3fŖffŖ™fŖĢfŖ’fÕfÕ3fÕffՙfÕĢfÕ’f’f’3f’ff’™f’Ģf’’™™3™f™™™Ģ™’™+™+3™+f™+™™+Ģ™+’™U™U3™Uf™U™™UĢ™U’™€™€3™€f™€™™€Ģ™€’™Ŗ™Ŗ3™Ŗf™Ŗ™™ŖĢ™Ŗ’™Õ™Õ3™Õf™Õ™™Õ̙Ւ™’™’3™’f™’™™’Ģ™’’ĢĢ3ĢfĢ™ĢĢĢ’Ģ+Ģ+3Ģ+fĢ+™Ģ+ĢĢ+’ĢUĢU3ĢUfĢU™ĢUĢĢU’̀̀3Ģ€fĢ€™Ģ€ĢĢ€’ĢŖĢŖ3ĢŖfĢŖ™ĢŖĢĢŖ’ĢÕĢÕ3ĢÕfĢՙĢÕĢĢÕ’Ģ’Ģ’3Ģ’fĢ’™Ģ’ĢĢ’’’’3’f’™’Ģ’’’+’+3’+f’+™’+Ģ’+’’U’U3’Uf’U™’UĢ’U’’€’€3’€f’€™’€Ģ’€’’Ŗ’Ŗ3’Ŗf’Ŗ™’ŖĢ’Ŗ’’Õ’Õ3’Õf’ՙ’ÕĢ’Õ’’’’’3’’f’’™’’Ģ’’’ó÷ H° Įƒ*\Ȱ”Ƈ#JœH±¢Å‹3jÜȱ£Ē CŠI²¤É“(SŖ\ɲ„Ė—0cʜI³¦Ķ›8sźÜɳ§ĻŸ@ƒ J“ØŃ£H“*]Ź“©Ó§P£JJµŖÕ«X³jŻŹµ«×Æ`ÊK¶¬Ł³hÓŖ]˶­Ū·p欝K·®Ż»xóŒ Æßæ€ ƒ"ßĮˆ+^Ģø±cĒ…õJž\ĄHĖ1«ÕL¹³g•œ?†~8ŚléĻØSw<½‘õB×ba«žM¢ģ‹·ęöŗ»¶ļß{g¦(|kqąČS·MœķņäŠ'?wø|ŗUė’ѳ×ÅžŗyB4n,/•»öóoĶ'¬®pCeīĖ£Ÿ?[=Bö•łU#S_b7ōµ~įÉG߁žŁ§›we2ɀ1 ±™L(Ę>h3•‚vų‡įwŠqį>bHøĻ$ޠ̆ʈˆ‰hŗ(/ī£c|Ź(䇏łuY‘!ğ@šięž2䕗˜†CVUq4Ē`APxā’ūS€T±–„•hŗ„„BŲŁHŠ$‚Łå„źٕ넩ēRk&t¢EnžeꞄÕ'Bā¶%ZƒźØP‡‚Øiy>j©O‘Š¶Ø •^źiN™z4iY~jje:¹ĻØd•zź«0…ŗŚ¦”Žė­/ÉŹ«c¹ŠėÆ'a‰$’Ä kģ±Č&›¤­Ą6k’ŖiB묳ŅZYŃ퓿^;¤¶ŲĀŹ­Œßvkjø’+ī„ę"˜ī¹Ž®KŸ»ģī /zóʋf½Śįkļ¶ū¤oæ1ž Ą«[°–'ĢģĮ+|^ĆĄALÖaŹVl1cQ|q`olģŠ&\œ f@­Wõ¦ŖŹ±j$±oŗīŠņủÄr®.+sk3WusH?·dŽĖµķœ3©Y­)i-gD4mF;m1O?Ķ3Ó6׬ęŃ §J“üń…iŅZKZ6KCėģõe#‰@…U“5ŠgƔ¶Čkg ’Ū2’9ö}%ŖAõX ‚Ēä_* ]wAśxJwwkõD)¹GžżéwO§ •œ¾OįŠ-ŗ@+ōˆöä<Ü܎K÷å ±ˆ‘‚śéāß ”ł€”PĻį<ž^=«tC¢ÆÓ~#ō“vŠh_'ꨟ2ʈ`düŻ »õ›[ūēåc6•žß~/rV8“™TXæįœąŗŻē·y~&ńy^˜Äó6 éCšÄ©Ćµ‚-C!Èۨ÷>ž„.47ŠŠ÷qøųuEƒ+\ąp&=Āi®z ÓMĄ$†ō-+, śĘ@Ū™Æ„óÜģ,žĘ‘o"+ٲ’ ²:Ö)Ćt5:e$t!Ė(ćd3!–’ŚT¤„Pķ/'ŹÄžD¦ä‘Fˆ` £ĒHĘ2I!™šaf*VC ZL1`_= cŗŠĮtó‹"ģ†Į†°ę‰į‹Ą„¢I@c|ŻqXō¹ōM¤{`ßqrš<ŅoGQŗ„ęGµųq_Jū]āšÖ/~õ«fü3@Ü)’ óf‘'Mī#ČįF8š`O ¦3]§GD–£L䓪¾µ.EgĢ„IłJXNŅ•éÜ5mbµR3!‡L&.+’ĮŻU4hTć5ŅĆą¹+”Ģ”#•¹ĪŠt3[ ™£ 7mI Ę žēŪē7·vN”@‹FėCŲ;SPsÓ …(ŪBāŸČü“”õ&=ŃÆyt$žQčäÖF³eōYEéDIā¶\–©”āÜf°RZ’ƒžd:1£Nc2öt§ƒ”é׏(Ō¢õØHMŖR—%ŹŌ¦:õ©PŖT§JÕŖZõŖXĶŖV·ŹÕ®zõ«` «Xǚ”€;orafce-VERSION_4_14_4/doc/orafce_documentation/gif/INSTR.gif000066400000000000000000000065701501757153000235160ustar00rootroot00000000000000GIF89ašrp!ł:,šr‡3f™Ģ’++3+f+™+Ģ+’UU3UfU™UĢU’€€3€f€™€Ģ€’ŖŖ3ŖfŖ™ŖĢŖ’ÕÕ3ÕfՙÕĢÕ’’’3’f’™’Ģ’’3333f3™3Ģ3’3+3+33+f3+™3+Ģ3+’3U3U33Uf3U™3UĢ3U’3€3€33€f3€™3€Ģ3€’3Ŗ3Ŗ33Ŗf3Ŗ™3ŖĢ3Ŗ’3Õ3Õ33Õf3ՙ3ÕĢ3Õ’3’3’33’f3’™3’Ģ3’’ff3fff™fĢf’f+f+3f+ff+™f+Ģf+’fUfU3fUffU™fUĢfU’f€f€3f€ff€™f€Ģf€’fŖfŖ3fŖffŖ™fŖĢfŖ’fÕfÕ3fÕffՙfÕĢfÕ’f’f’3f’ff’™f’Ģf’’™™3™f™™™Ģ™’™+™+3™+f™+™™+Ģ™+’™U™U3™Uf™U™™UĢ™U’™€™€3™€f™€™™€Ģ™€’™Ŗ™Ŗ3™Ŗf™Ŗ™™ŖĢ™Ŗ’™Õ™Õ3™Õf™Õ™™Õ̙Ւ™’™’3™’f™’™™’Ģ™’’ĢĢ3ĢfĢ™ĢĢĢ’Ģ+Ģ+3Ģ+fĢ+™Ģ+ĢĢ+’ĢUĢU3ĢUfĢU™ĢUĢĢU’̀̀3Ģ€fĢ€™Ģ€ĢĢ€’ĢŖĢŖ3ĢŖfĢŖ™ĢŖĢĢŖ’ĢÕĢÕ3ĢÕfĢՙĢÕĢĢÕ’Ģ’Ģ’3Ģ’fĢ’™Ģ’ĢĢ’’’’3’f’™’Ģ’’’+’+3’+f’+™’+Ģ’+’’U’U3’Uf’U™’UĢ’U’’€’€3’€f’€™’€Ģ’€’’Ŗ’Ŗ3’Ŗf’Ŗ™’ŖĢ’Ŗ’’Õ’Õ3’Õf’ՙ’ÕĢ’Õ’’’’’3’’f’’™’’Ģ’’’Ü÷ H° Įƒ*\Ȱ”Ƈ#JœH±¢Å‹3jÜȱ£Ē CŠI²¤É“(SŖ\ɲ„Ė—0cʜI³¦Ķ›8sźÜɳ§ĻŸ@ƒ J“ØŃ£H“*]Ź“©Ó§P£JJµŖÕ«X³jŻŹµ«×Æ`ÊK¶¬Ł³hÓŖ]˶­Ū·p欝ė5€»xóźŻĖ—o ˆvū Lø°įƈ’„Ėø±ćǐ#+0’ņCĖk1KŽĢ¹³ēĻX5½ōYÓ S«^Ķŗ5LŌa”=–¶ėŪøsėŽŠöE߁’Ī»øńćČåŸH|9WēÉ£KŸNŻ*tˆĶŪ^ÆĪ½»÷ļ;·;ĢĪV<ųóčÓ«iž!łĢėć˟OæcūŅŲfĀ;Ķ]4ł€ū`F™21Ü17ˆAŁ~Ü0*ąA(”@xeŅ}õ…(āˆÓ˜Š{e²Ų$Š!‡ūL²eõlXć>ūY˜#Ž+ƒ‡ÄDˆć‹.rXŠ>zČā>õ˜h“$F)唩Ałd~'Zø2”‰&Z&/nIä$‰AfZ*ó"˜Jčeš/Ią‡TÖiēÅYYгؖ ž‰£ ū įį>īsƒ–‹n©—„bh)1\™Äe^ś§åhxvźé§éIŸ–ž)Źl(‚õ(ž¹˜Ÿœ2jZźź@™lČ&{ +ģ°_fXe‰Į ɤe č#ŖĘš×Æ ŽźØ2õ,vc„ūÄ ¬ŪrYOŒsz”la›ėī»š¾¦{'fD*AAŽÅė]gBxf`Hžś«£śŗźbž®Ź_™wj_l‡ńF,ńĕ—Š`tÆY&ŠJńĒ l‡ž†%|yņŹ,S9rŗiqĖ4×ņĖ"m\VĒ6÷ģ3¼8Ósy3’lōŃx ģŠ(Ū‹ōÓPG©4§L«ÅsŌXg½ŽŌźžluŃZ‡-6u#Æ».vf§­öŚlėöŲpǽ›ŹRĖm÷Ż®ŃM¢Žux÷ķ·V|‹ų߄žŌąõ!nųāŒ„ų|7.łä9EŸå”g®¹K˜«×łę ‡³ĶŸ‹nśéN÷\:ź¬Ge@Ū…=ō:ģ“×n;¶J“:x»·īūRt ×{åĢł<üļČ|ÕhAwL›”¤E„G“ŠMӛ­³ęy¹Ms¢óQdē.Iك"ō”£r'/ĆɊNŌ”…č93 fHŽrt£%^H Ņ‘VҤ-)Jk¹R€Ŗ“„Ɓ)>_*Ó–Š“¦b»)NS¢Ób­§>- PƒŠ“”UhG„Q“ŗO¦žq©N}],JU³”m“©ŖVo—Õ‹Jt«`m[@£:œU’T)Pͧü8²œ“.TŸß„+ĒĘJÖ®ĄFoFu+öWŗ’„­h9åZ׭ܕ$yõŠĪR–ÕĮś•±Ąt¬< kW…¾ÕqŠŻk_#[еJ•’µ,e +ŚĶZd?6ͬg!»Z±v”“m(aG{•Ć6"ū1ężTūŲ_öö…miwö[ŚŽpøŸ…Č~ø(­ŻÖ‹Kuldf¬†5sa1Y¬!Ē\‡ą’ ŲDkw—6ۃ|·™Qįšq=Z„8,›Ź]A 6…9Ų€«`ŽāP )Żęfč½+Ń.€[{%‡ą± Jļx/+X‹¦I:šQŌ»^ė 7įÕ,C–Żžņ4€Į\b$Œ¬Ēü®J‚ęœ†Ė„Aųņ58"lR„¤[~)xŬ}1Œ s±AøĀŻ•s{$®ģŚąŒ7ʍPśHä…‹i:LϚW(’»¬Vą¶Õ×væ<~Ÿ˜ŃĄ)t&4±'D³ŽąüåŹ!”˜kM~Y—YBŹ`F 6FŒ@™Ö B7”@"Ųąxʬ@R}ųY€ PĻAʘŠe"ĘD­e€Š\Œę)C˜d“ēŒ„‰įć@“Üįˆy†Ę†éGiŁ(•iķ _ūŲĄMņXPo©5'Žmß1hŁ‘b¬ēÜA"g‚ ŽÕę@1dĀEI$&$"b”ÉŸÜ5É|“ą÷d—ĘåcĘ÷č‰ m×ߘ;VgЃū47Pƒi 9¤¦Ż0Ž}ūŌ󟍗†ŌēAŖę’˜_¤µwhAKĘ0^yŠ‘”HFųh ‹&ijś·–AöźŁœµīƒVyΚōjŒ.6l‹ń5²–iMx——j­]N2«œY.ŌŪ“‡½u܊ÖH&G"Łh’©ź@w&hm¼Ō H‘\ v¾Özd¾¼ÅµP¢łŃ%ź±.qķ$żePņŚé³@v—I¾Bėj˜čFŖ1ÆŪ)CĢ|ŪķČŃ6ū+ŗü­‹į-óyÜZ1˜{ęZ¢ņ«ž@®°”‚ڲŒPĄQŅźå{W¦EåČš õؘ*Ō0 ˆsŲȚu­AŠdėnŠ-Ū„±”:d)Ś—ä5ҰIŒ>cœ© ‘Ŗg œ¦Ś~o$÷ā}­£D6āz,ł¹ŒC į7=~pEÅ^žyę˜ĖĘłą‘SWQ͐“µö‹§×ä¹į]Ģ’čI½¾`ģ4ĶøQø#„ūμĻä{Õ¹¬üņĢKüXó脿ōOF}õŒeÆżöÜwļż÷ą‡/žųä—ožłč§Æžśģ·ļžūšĒ/’üō{;orafce-VERSION_4_14_4/doc/orafce_documentation/gif/LENGTH.gif000066400000000000000000000034241501757153000235730ustar00rootroot00000000000000GIF89aŁ4p!ł:,Ł4‡3f™Ģ’++3+f+™+Ģ+’UU3UfU™UĢU’€€3€f€™€Ģ€’ŖŖ3ŖfŖ™ŖĢŖ’ÕÕ3ÕfՙÕĢÕ’’’3’f’™’Ģ’’3333f3™3Ģ3’3+3+33+f3+™3+Ģ3+’3U3U33Uf3U™3UĢ3U’3€3€33€f3€™3€Ģ3€’3Ŗ3Ŗ33Ŗf3Ŗ™3ŖĢ3Ŗ’3Õ3Õ33Õf3ՙ3ÕĢ3Õ’3’3’33’f3’™3’Ģ3’’ff3fff™fĢf’f+f+3f+ff+™f+Ģf+’fUfU3fUffU™fUĢfU’f€f€3f€ff€™f€Ģf€’fŖfŖ3fŖffŖ™fŖĢfŖ’fÕfÕ3fÕffՙfÕĢfÕ’f’f’3f’ff’™f’Ģf’’™™3™f™™™Ģ™’™+™+3™+f™+™™+Ģ™+’™U™U3™Uf™U™™UĢ™U’™€™€3™€f™€™™€Ģ™€’™Ŗ™Ŗ3™Ŗf™Ŗ™™ŖĢ™Ŗ’™Õ™Õ3™Õf™Õ™™Õ̙Ւ™’™’3™’f™’™™’Ģ™’’ĢĢ3ĢfĢ™ĢĢĢ’Ģ+Ģ+3Ģ+fĢ+™Ģ+ĢĢ+’ĢUĢU3ĢUfĢU™ĢUĢĢU’̀̀3Ģ€fĢ€™Ģ€ĢĢ€’ĢŖĢŖ3ĢŖfĢŖ™ĢŖĢĢŖ’ĢÕĢÕ3ĢÕfĢՙĢÕĢĢÕ’Ģ’Ģ’3Ģ’fĢ’™Ģ’ĢĢ’’’’3’f’™’Ģ’’’+’+3’+f’+™’+Ģ’+’’U’U3’Uf’U™’UĢ’U’’€’€3’€f’€™’€Ģ’€’’Ŗ’Ŗ3’Ŗf’Ŗ™’ŖĢ’Ŗ’’Õ’Õ3’Õf’ՙ’ÕĢ’Õ’’’’’3’’f’’™’’Ģ’’’’÷ H° Įƒ*\Ȱ”Ƈ#JœH±¢Å‹3jÜȱ£Ē CŠI²¤É“(SŖ\ɲ„Ė—0cʜI³¦Ķ›8sźÜɳ§ĻŸ@ƒ J“ØŃ£H“*]Ź“©Ó§P£JJµŖÕ«X³jŻŹµ«×Æ`ÊK¶¬Ł³hÓŖ]˶­ŪÆ1ȝK·®Ż»xóźŻĖ·Æßŗ1&ĘżK8o`Į…+^Ģøńį‹ƒ'~Œ€[Ė1ŸŌ‘ó[ž)†&9šji³§¦žø:a듯Ęę8›imÆ·A§Ģ­ū3Aށ[n”xå‰Ę3‹öż;crå3=9Ż4ņŻĖ™÷¾Xżaué7ŗƒė•7ł…ĄĻ[}®^uĘIb(Ū×~c}Ū×Q¦×¾}øJćbpCs;ę™2vĶ@&\īŁ\ōt_~)”‰ķ÷‡c±§eöUˆ ęT‚Įōą@,īCŒf7LŅ`Œį8“y Õ!mŁ5DŒd‰˜P&hx”›2¢h!O¶œ2avƒQʙgB—!Bh` $†Ķ•I=sC€_™Š JB¤&Iŗ%BŠPA: „ę>aīógŸ|j–ēžZēįAhŲH4“0(Ż|m:·P c2”IxbŚ’Y BZ×>y XŖLŗ—ć]61ꢓ%’YЌuJ8Ÿ’fŠŃj“äŖQk™ÄEŒC]r‡'ŠbHwoØõś©™ÄżÉæ1pČ#÷»ā“ķ[c°“°ģr¤,ӋP±m(”ŖbÕKŒ¹åöĢ3ø„l‡=+S.øMzwg£„ŚōĘr½zmĘØ2›(gAæ$kpŁÖźeA1V¬¦Œ$vå&˜ ’ź½bäł+ŖNčŅšuŁČ™ÅÆRŲ ĒŚzk+A•Ęł÷@ XmÅisuöApv|m» ÷eƒ'Z¶Ś•·µxAH xĒ–¹4[[4t§_j·9Œ—c.Ń$ÄzŠ8%‹Té¤ÉÜźŌY”‰ĢŽ·Š”]Ņ£»kŠŻEC.ŲńM¶…{®¼~)|£Æ5½HČūĘ;ų1½īj}RųŸæ¾Gn×^|ź&±’–ūćmåšžü÷Æržó‹hHĄśĻ9Ü ČĄ:šŒ 'HĮ Zš‚Ģ 7ČĮzšƒ ”GHĀšš„(L” WČĀŗš… 0Œ” gHƆ0 ;orafce-VERSION_4_14_4/doc/orafce_documentation/gif/LENGTHB.gif000066400000000000000000000034231501757153000236740ustar00rootroot00000000000000GIF89aė>p!ł9,ė>‡3f™Ģ’++3+f+™+Ģ+’UU3UfU™UĢU’€€3€f€™€Ģ€’ŖŖ3ŖfŖ™ŖĢŖ’ÕÕ3ÕfՙÕĢÕ’’’3’f’™’Ģ’’3333f3™3Ģ3’3+3+33+f3+™3+Ģ3+’3U3U33Uf3U™3UĢ3U’3€3€33€f3€™3€Ģ3€’3Ŗ3Ŗ33Ŗf3Ŗ™3ŖĢ3Ŗ’3Õ3Õ33Õf3ՙ3ÕĢ3Õ’3’3’33’f3’™3’Ģ3’’ff3fff™fĢf’f+f+3f+ff+™f+Ģf+’fUfU3fUffU™fUĢfU’f€f€3f€ff€™f€Ģf€’fŖfŖ3fŖffŖ™fŖĢfŖ’fÕfÕ3fÕffՙfÕĢfÕ’f’f’3f’ff’™f’Ģf’’™™3™f™™™Ģ™’™+™+3™+f™+™™+Ģ™+’™U™U3™Uf™U™™UĢ™U’™€™€3™€f™€™™€Ģ™€’™Ŗ™Ŗ3™Ŗf™Ŗ™™ŖĢ™Ŗ’™Õ™Õ3™Õf™Õ™™Õ̙Ւ™’™’3™’f™’™™’Ģ™’’ĢĢ3ĢfĢ™ĢĢĢ’Ģ+Ģ+3Ģ+fĢ+™Ģ+ĢĢ+’ĢUĢU3ĢUfĢU™ĢUĢĢU’̀̀3Ģ€fĢ€™Ģ€ĢĢ€’ĢŖĢŖ3ĢŖfĢŖ™ĢŖĢĢŖ’ĢÕĢÕ3ĢÕfĢՙĢÕĢĢÕ’Ģ’Ģ’3Ģ’fĢ’™Ģ’ĢĢ’’’’3’f’™’Ģ’’’+’+3’+f’+™’+Ģ’+’’U’U3’Uf’U™’UĢ’U’’€’€3’€f’€™’€Ģ’€’’Ŗ’Ŗ3’Ŗf’Ŗ™’ŖĢ’Ŗ’’Õ’Õ3’Õf’ՙ’ÕĢ’Õ’’’’’3’’f’’™’’Ģ’’’’÷ H° Įƒ*\Ȱ”Ƈ#JœH±¢Å‹3jÜȱ£Ē CŠI²¤É“(SŖ\ɲ„Ė—0cʜI³¦Ķ›8sźÜɳ§ĻŸ@ƒ J“ØŃ£H“*]Ź“©Ó§P£JJµŖÕ«X³jŻŹµ«×Æ`ÊK¶¬Ł³hÓŖ]˶­Ū·p欝K·®Ż»xóźŻĖ·Æßæ€ Lø°įƈ+^̘` #KžL¹²å˘3kŽĢ¹³‹;‹¾üybčŃØS«^­ŗ4hÖŖc|€—¶EŪ'qGŌ—7Eß$c—øCć‘'Tž–9Cē”C•Ž–ŗAė±ļÓ–;Aļæ;’Ÿ’“āXä Žeņßu ”bAG" Ł@IŽ7P “0‰[’(ŅFe=hFžøQŽ ćåy— €@J¤L ctar!\‡?ŚvƒŒy©oŌó¢@bhY—”įaš*Y&Š@v17ˆńfO=䦗”@”MŠØ’ ‚І‰GRi•¦–:åŽ[xŠ pN’Dœ&b¹”ū)hW•$Ę”˜>$$šqśDœo”=˜§²ū“yāƒ”A³‹3ŗZP=7Hū©z „x# ¢Įéle.dć¶ŻĘ°Ā®y*o¦V)Š™¶&™"dZ¢Źē>¦ŅZķmeā,F`"¤)‰¶ÅĄ.W½4Éø1')ž wl-ēē³ĻҚ0Å»'A¶ž¹æ[bœŠĄŁ­°ƒ“ ”ŒŠ`+ʑ™ūķ—œqū“pńĘĖļ”Ko–ņ&-Æ© ’[ѱ±&j¤mā®É/Ė–«ŹĮ*M 7,ÜīĻĖI&e&źę¤@XęüŻĘ&oēgŒ8Z×]¦Č³–"­;“KšB°¢‹ŠxÄ*ź.‚ÖōµG÷¦uĄG ‡ĄŽm¬}טųäzėŗAX?QŠaK)ē¦k(+ćƒW‘sĢ“§TŁ]ßė¢ĒīśDRĢģęwé>Räō^’wˆĖ¹xļ­ē–ß\ ‘¦;ćž7ōӛ„ü[ÕG˜Q=l"ü<õļ.5ś¾KÆŃ°ŚGŒóüōןńmöoö[žü÷s™žĆLG$՘(b; <ČĄ:šŒ 'HĮ Zš‚Ģ 7ČĮzšƒ ”GHĀšš„(L” WČĀŗš…0Œ” gHC«;orafce-VERSION_4_14_4/doc/orafce_documentation/gif/LISTAGG.gif000066400000000000000000000050571501757153000237100ustar00rootroot00000000000000GIF89aÜgp!łD,Üg‡3f™Ģ’++3+f+™+Ģ+’UU3UfU™UĢU’€€3€f€™€Ģ€’ŖŖ3ŖfŖ™ŖĢŖ’ÕÕ3ÕfՙÕĢÕ’’’3’f’™’Ģ’’3333f3™3Ģ3’3+3+33+f3+™3+Ģ3+’3U3U33Uf3U™3UĢ3U’3€3€33€f3€™3€Ģ3€’3Ŗ3Ŗ33Ŗf3Ŗ™3ŖĢ3Ŗ’3Õ3Õ33Õf3ՙ3ÕĢ3Õ’3’3’33’f3’™3’Ģ3’’ff3fff™fĢf’f+f+3f+ff+™f+Ģf+’fUfU3fUffU™fUĢfU’f€f€3f€ff€™f€Ģf€’fŖfŖ3fŖffŖ™fŖĢfŖ’fÕfÕ3fÕffՙfÕĢfÕ’f’f’3f’ff’™f’Ģf’’™™3™f™™™Ģ™’™+™+3™+f™+™™+Ģ™+’™U™U3™Uf™U™™UĢ™U’™€™€3™€f™€™™€Ģ™€’™Ŗ™Ŗ3™Ŗf™Ŗ™™ŖĢ™Ŗ’™Õ™Õ3™Õf™Õ™™Õ̙Ւ™’™’3™’f™’™™’Ģ™’’ĢĢ3ĢfĢ™ĢĢĢ’Ģ+Ģ+3Ģ+fĢ+™Ģ+ĢĢ+’ĢUĢU3ĢUfĢU™ĢUĢĢU’̀̀3Ģ€fĢ€™Ģ€ĢĢ€’ĢŖĢŖ3ĢŖfĢŖ™ĢŖĢĢŖ’ĢÕĢÕ3ĢÕfĢՙĢÕĢĢÕ’Ģ’Ģ’3Ģ’fĢ’™Ģ’ĢĢ’’’’3’f’™’Ģ’’’+’+3’+f’+™’+Ģ’+’’U’U3’Uf’U™’UĢ’U’’€’€3’€f’€™’€Ģ’€’’Ŗ’Ŗ3’Ŗf’Ŗ™’ŖĢ’Ŗ’’Õ’Õ3’Õf’ՙ’ÕĢ’Õ’’’’’3’’f’’™’’Ģ’’’¬÷ H° Įƒ*\Ȱ”Ƈ#JœH±¢Å‹3jÜȱ£Ē CŠI²¤É“(SŖ\ɲ„Ė—0cʜI³¦Ķ›8sźÜɳ§ĻŸ@ƒ J“ØŃ£H“*]Ź“©Ó§P£JJµŖÕ«X³jŻŹµ«×Æ`ÊK¶¬Ł³hÓŖ]˶­Ū·p欝K·®Ż»xóźŻĖ·Æßæ€ Lø°įƈ+^Ģø±ćǐ#KžL¹²å˘ć3kŽĢ¹³ēĻ C‹Mŗ“éÓØS«^Ķŗµė×°cŸŒ ¶ķŪøsėŽĆ"ķŻĄƒ N¼øńćÄ{Ė^Ī\!’Ļ+FĒ;½¹uėÕAføn÷ėą]ē8¾ayøēĆ«7cū„ļŁĘ_Oßó|Š÷ ęG»æ¾ĖżAą>’Uą:v C.–ƒ Fx„šY™ $†2ūlȐ‡b0E”„$6āA >‡)£DÄ b‰4fv¢A)*„Fm™¬ P&µŻ ‹ū(#d=1¹āoCĘMūLe‘1ÜąćO7’ÖØ„]Y”#B™(@o“(—ä>™LRdˆŸÄ &f‚F‘sŠA šfĘŁeH{né§TUzƒ „jh”öIą”Œ"Śhy+°ˆ†°H$†Ž)†ŖŁi‡zøā!Š1gPc6ŖŖ£ŠžéjM£Œ¬“Ījk­øŽj«¢±źšėÆ»&D¤@h4¢ n!ĘĄį zø³Čį Šƒ[oε"°ÜŽŚź«ąĀD!Æ&ć@7d¢Ģ•)ā>WNĒ®Œ ŌŪ°½Øm¹įö ÕøŠń‹ŠØbŒZi‘+iä>Š(·p‘>I §£+«¾X ģļĘJ<°F_$%›†i›@“ĢIŒŹœ›2ß{2š§¢Ŗ1Ē8åńAļŗws]!ē,“Ķ—aFAżóŠLļ“3ŸKĻ•tÓTßō“vQĖ5uÕ\ĖtõG[ku×d³ōµGaĒ•vŁlŸtvGkæwŪtC]tĄŅé5wŻ|“Gr€×faą„nųį€Ż÷āw3.Š·—ŽÓ ¹„“G^vå bn9ך’׳ęM^Ÿč  Mśz§—Īqźį±®zæ®_ūėÆĪޜķ“ū‰ūr»ē^cļ±ļ;‰ĀæVüš™[~<[æ!īüóЇ1CĶGmDÕ[ÆżöČMŸņ¾q›÷f-OÓ}ä (7Čąē=’ł.Įļ5wx«ø>Ņķ’~[ņĒ„~żé_K$ĄÓģMq’b)`üč·?õ¹…€ł›HśF$£(p€ É’ȾČŠ}!1Ņ .xA³eŠnöć ž<ˆ@Ÿ…dGj"”ŲØĮ®‚,! ;¤žÉ!Ē*ȓrÜązc‘ÉjÓ3„11'“§Zč%ˆpŠ G¼Ķў‚CĒm­W¼Č‰©*źĢ9©Gtbõ#vՋ +«Yų®9>«‰ē³aAȧDžÄg]qćTŗČø°½Ģ…)Ų‰hĮ„ØGõā@†°=ŗk gB—½¶ų,œDŃ bą¤Ķć 7˜X œ4=Kī:¢ĆµÆzql‚Ō_Fzų±3"D’‘’¤č…£=‚Ŗ’-ZŽ' BL1ö‘Xžzī$M¬E½@†vÄ!4ĢIJJō !—¶P"Ņ".RV…|9°zä‘K•Éņ²K‚ń ÷ģÉ2‚¤¦š ÖŖˆqkH’‚Yš®8ęwęŗćūq2Ö K¢ß łČHN²’—Ģä&;łÉP޲”§Lå*[łŹXβ–·Ģå.{łĖ`³˜ĒLę2›łĢhN³š×Ģę6»łĶp޳œēLē€;orafce-VERSION_4_14_4/doc/orafce_documentation/gif/LNNVL.gif000066400000000000000000000033211501757153000234770ustar00rootroot00000000000000GIF89aX2p!ł<,X2‡3f™Ģ’++3+f+™+Ģ+’UU3UfU™UĢU’€€3€f€™€Ģ€’ŖŖ3ŖfŖ™ŖĢŖ’ÕÕ3ÕfՙÕĢÕ’’’3’f’™’Ģ’’3333f3™3Ģ3’3+3+33+f3+™3+Ģ3+’3U3U33Uf3U™3UĢ3U’3€3€33€f3€™3€Ģ3€’3Ŗ3Ŗ33Ŗf3Ŗ™3ŖĢ3Ŗ’3Õ3Õ33Õf3ՙ3ÕĢ3Õ’3’3’33’f3’™3’Ģ3’’ff3fff™fĢf’f+f+3f+ff+™f+Ģf+’fUfU3fUffU™fUĢfU’f€f€3f€ff€™f€Ģf€’fŖfŖ3fŖffŖ™fŖĢfŖ’fÕfÕ3fÕffՙfÕĢfÕ’f’f’3f’ff’™f’Ģf’’™™3™f™™™Ģ™’™+™+3™+f™+™™+Ģ™+’™U™U3™Uf™U™™UĢ™U’™€™€3™€f™€™™€Ģ™€’™Ŗ™Ŗ3™Ŗf™Ŗ™™ŖĢ™Ŗ’™Õ™Õ3™Õf™Õ™™Õ̙Ւ™’™’3™’f™’™™’Ģ™’’ĢĢ3ĢfĢ™ĢĢĢ’Ģ+Ģ+3Ģ+fĢ+™Ģ+ĢĢ+’ĢUĢU3ĢUfĢU™ĢUĢĢU’̀̀3Ģ€fĢ€™Ģ€ĢĢ€’ĢŖĢŖ3ĢŖfĢŖ™ĢŖĢĢŖ’ĢÕĢÕ3ĢÕfĢՙĢÕĢĢÕ’Ģ’Ģ’3Ģ’fĢ’™Ģ’ĢĢ’’’’3’f’™’Ģ’’’+’+3’+f’+™’+Ģ’+’’U’U3’Uf’U™’UĢ’U’’€’€3’€f’€™’€Ģ’€’’Ŗ’Ŗ3’Ŗf’Ŗ™’ŖĢ’Ŗ’’Õ’Õ3’Õf’ՙ’ÕĢ’Õ’’’’’3’’f’’™’’Ģ’’’’÷ H° Įƒ*\Ȱ”Ƈ#JœH±¢Å‹3jÜȱ£Ē CŠI²¤É“(SŖ\ɲ„Ė—0cʜI³¦Ķ›8sźÜɳ§ĻŸ@ƒ J“ØŃ£H“*]Ź“©Ó§P£JJµŖÕ«X³jŻŹµe `ÊK¶¬Ł³hŃʈų5­Ū²k»Nmū¶.ŲøÕ ‘oGæEéŚLø°]Š€7&føxgc…/Fž99i儗'f&øyfgŸó" -”4č”M»LzōTÕŖ²:ūÆk©°[÷Ż16䋙š²ōŻ3·ĒŚ>‘+®ØģĘחÄyG˜ ęŽ#Ńd⨼ šŻÅ’Ų]ņkÄ •‰A>$€zܱ'Ģ“^"i4& ,oqņāńœ¶Ż~ūÄ0ą>õÜ  MgŹ'šBų`Ż>™„5РĀ„Œ@fh[{pŻCĮ}Ē {-XŠ‚~¹ć@.f¢Ÿ@ōķ³"c,“BEŻ$Ę ż8I\“X×!‘9fņ£Žßa¤ÄŲē21ÄšaA;Z‰™Aƒ×{ū„9¦@x)Ø#Jz¤„%fĄ–5ÖG ‘l9 ‘ń‘xPu^.$^„®–^b.BøŒz)źbb¹h—æhPpośI2O $ę@wī#ʖJ b}ĖiZŠ$7ŖJ~­Ę’ dšŹ'_|݊£u€źXkIyfBŒ2Ā;l±ČŪaBQę•$ĻF‹“Ó&YsAćדk‚¦L=~)Ź] Ī•Kī¹ę:WYÆ}”ėīWZŹĘ–aiś"_I2*P¾|Õ³V š=jī¦[0ŗ‘Åfa’$é0“b°Jķµ|ŀø.› @źM Øyž„Œ²#—L2ɕ‰Ū—É,“ā–Qź*h*j‡š…‹³@ ņŁķĄ=¤]Š<Ī֍0ņe*¶‚5äqpŌéĢ40j̳"Äé½Uė%šŒūF̱ĢX[j©6ČÕģRMŠ$Źj(fbŻ.A"žÜtĶ:ĀDų „†4®Ą!Y“Ģ•ą>ÄĢų y™L’£Väķć|Jn7!^,Ŗ(å”T¶8 C˜}'PˆM2#šMBž|‰¹v4āH#Y`–™ä>Źpµ’ąŻe•xę©'EQä¢Aoƒ#Œ]eRį@7Ę9FÖG§@ŻZęœŹ2IWŸ{vźitœōgA ~·ß Ź(£#¤†īwĆv«bŖUŖ®*S`śķC=ŗņ÷éÆĄ¢7¢ˆÄĘPl±”Ҧfģ²Ē2kldOī3É^¹*Ia›KŽ Ž’\J*i›ŃŽ`$‡­¦ÉŸ³Ķ¦ ĄøĮ¶ėne“*1ņŅ«Œ½öbĘ˜õö{Ææ"ä„x6rµą}\‰1ׇ Ć9#—p&' sX(œ¼Ŗę]üĪ 0ĄqjśīČ$ūŠeB3ęęžA¢„FŹšJ”lÉ4×¼“j˜±kŃØ­:Ņ“ ‚vŪĢ6mtL8_y°CķōÓJ%=ŪŹž6 õÕXF kTwjuÖ`‡m“Ō\o]µĢb§­öKdƒÄ³ž_yÆ-÷ÜJ7×[įŻ­÷Ž|÷ķ÷ßhÓ-ųąMų·'®xD†/ĪøćG^Pć’3Dy嘟yK—oī9•žšč¤§:駗®:z©Žśź°;÷śę³Ēnūoµcžūķ¼+×»Ūæģī’/üń–¹ņČ7™ó1’żō&SϧõŲ’'½āŪgļżTݾ]fżmžłi‘ČPłč{„žBģ·/’üj½?żA;?žü§’ų÷]kˆųg櫌$oėHC¢µ-* `-W·ŻÉlĄĆ d"8µ“éå\3h—VP!†[ a8X6‚o„!DaąZXvЃ7t!eXHB ~p‚1ōÓ {˜‘LųŒ'6¤”søÄĀš9¬Īƒ(Ä)n#!ŚŹO’HÄöœ0!\t E§Œ‘ŠUbf4‚ ūp1ŒP,ćåøB+®‡R9#E5D2^dAģzc3±®ĄLWš)¤œr¢B鬅6jDČʰ¢Ē9źŠ ZBJ%÷ø!+Bģ4™Ö$;¹0¦q؈ 6& ᤑŒä)¢ØMŁqEtŒeP6¹Ēø$£„äDšC¦Émq©„@^µLˆ)S+ƌdwTFGąČéVĖÄ `d^FOŽŚDXĘĘó 6Żģ–hō%©Ø ‘,Śg3’Ē“’1SóN²L“”IåŲ"¹ÆHz‰Cgr’9«āMv6ń—F2¢V¶'"sŸ²¤¢: rϊА2ōIdž‰1ÆĢ ˜p" Go 2¤©ń“ˆ£cœ`¦%44‚’č4Ø_“sŹLę:gDƒ8с ”Ń!åYJ¢ŽP^h|Ž ™“Ń¢]xbTRŽĖPÄĄŖVÆz/Ök«YåjĄ$™ŖÆ >e$0Ńą%¶Žh­mõ’\oäVyÉ®t½k]÷Ŗ×¾ęõÆx ,_;XĮśÕ°„=la{# kDĖz¬d#KYĒV²–Ķ,f7;YĶv–³—ż¬hC{ٌ”ė“ČR’Hwę,Ńr…W½ČžŠ‡L‚pN\@T&nEŻ. A©Eń&°$y©䑔E¬ę2÷¹ā‹so0]bm4?ļŪĻ@éÖ¹z—­Ż /0Ē+Žņ’÷¼ęM/z׫Žö²÷½ī/|ßۈId_÷Źo½ōĖßżś·æžÆ€LąøĄ>°,ą± ģ‘2KpŖšc¦šR£ęć/)U!h“’RM„ćSÆ'ĒZzéPÄxS7c ŌKV*IOČzµä•“Bˆ…éb ˜FÕ©Ał#ƌrŗX4é˜Vć“\InĘ~ S ޖDZ-ÓøŹŁ—Õ®VČ8N‰fĘFÜdžLč”J½q e©Ė'ĻŌ‰jŖ“³lĘ0ēų ™s™² ‡ ’c²ügJŻü˜MBĖo† UrŻoVA;žs wŚbšÅƒ¦sSąx<^¤B1`Ŗ¤×\MGśy”†ź©7½h11"ŗÆFmĖRĖ4ŃÄ“Ŗ-]ēVŸÄÓ™ÖĮ0 h[WZÓuLõœq-E_›Ųį&±'mģL#»0=vF_čģ’@‹[쟸÷–7ž•{Üčnćśē—t»ū+Żö6»8ćMļzŪūŽųĪ·¾÷Ķļ~ūūßøĄNš‚üąOøĀĪš†;üįøÄ'NńŠ[üā7I@;orafce-VERSION_4_14_4/doc/orafce_documentation/gif/LTRIM.gif000066400000000000000000000046061501757153000235040ustar00rootroot00000000000000GIF89ag\p!łH,g\‡3f™Ģ’++3+f+™+Ģ+’UU3UfU™UĢU’€€3€f€™€Ģ€’ŖŖ3ŖfŖ™ŖĢŖ’ÕÕ3ÕfՙÕĢÕ’’’3’f’™’Ģ’’3333f3™3Ģ3’3+3+33+f3+™3+Ģ3+’3U3U33Uf3U™3UĢ3U’3€3€33€f3€™3€Ģ3€’3Ŗ3Ŗ33Ŗf3Ŗ™3ŖĢ3Ŗ’3Õ3Õ33Õf3ՙ3ÕĢ3Õ’3’3’33’f3’™3’Ģ3’’ff3fff™fĢf’f+f+3f+ff+™f+Ģf+’fUfU3fUffU™fUĢfU’f€f€3f€ff€™f€Ģf€’fŖfŖ3fŖffŖ™fŖĢfŖ’fÕfÕ3fÕffՙfÕĢfÕ’f’f’3f’ff’™f’Ģf’’™™3™f™™™Ģ™’™+™+3™+f™+™™+Ģ™+’™U™U3™Uf™U™™UĢ™U’™€™€3™€f™€™™€Ģ™€’™Ŗ™Ŗ3™Ŗf™Ŗ™™ŖĢ™Ŗ’™Õ™Õ3™Õf™Õ™™Õ̙Ւ™’™’3™’f™’™™’Ģ™’’ĢĢ3ĢfĢ™ĢĢĢ’Ģ+Ģ+3Ģ+fĢ+™Ģ+ĢĢ+’ĢUĢU3ĢUfĢU™ĢUĢĢU’̀̀3Ģ€fĢ€™Ģ€ĢĢ€’ĢŖĢŖ3ĢŖfĢŖ™ĢŖĢĢŖ’ĢÕĢÕ3ĢÕfĢՙĢÕĢĢÕ’Ģ’Ģ’3Ģ’fĢ’™Ģ’ĢĢ’’’’3’f’™’Ģ’’’+’+3’+f’+™’+Ģ’+’’U’U3’Uf’U™’UĢ’U’’€’€3’€f’€™’€Ģ’€’’Ŗ’Ŗ3’Ŗf’Ŗ™’ŖĢ’Ŗ’’Õ’Õ3’Õf’ՙ’ÕĢ’Õ’’’’’3’’f’’™’’Ģ’’’Ō÷ H° Įƒ*\Ȱ”Ƈ#JœH±¢Å‹3jÜȱ£Ē CŠI²¤É“(SŖ\ɲ„Ė—0cʜI³¦Ķ›8sźÜɳ§ĻŸ@ƒ J“ØŃ£H“*]Ź“©Ó§P£JJµŖÕ«X³jŻŹµ«×Æ`ÊK¶¬Ł³hÓŖ]˶­Ū·p欝K·®Ż»xóźŻĖ·Æßæ€ Lø°įƈ+^Ģø±ćˆ1HžL¹²åĖ“c4ŒŒ¹³ēĻ C‹Mś³ęĒØS;š‘5C×va«žM{ ģ·ę–»’»¶ļƽ/'8ÜmńßČ Ÿø|łZēÉ£ū…±9^źŅ³_oŻūYļŚĆóęžz»ųóĮ—_Ÿš†A1ŹVKv/~Gś-գߏVæBė sšD“Ąƒłw€/)Č߃a9x€ŗƒ21Üpa ŠģC&’sƒd¶4õÜP lhHvš2jÖ¢…͈ ‹ū€}jøĻd™x$!„Dn5¤‰Ż)„19Ÿ2 ˆF“Af‚`&S$eŽWž†‚ 4 }_ī#}ŠQåi10 b=ū 1e=G–XäoÕiēBĆ]hę$bYfœ€źa ŠF”M2å’ 9ścAöµ)Œff© Y ‰ē§lé™`’ vC|ĘēgŖły“Śj|3J¤}qR– †°1•¹‡k}Nz ź±YŐį²6»¬Ø?2+­³ĆłZĻ€®Į¶Ā@Ūʉ`£Sø2ŻzČä‹å¶Éė@׎;ą@§eo§ø9kļ“Ҿ‹ģ¾=9IŒ2’ šĄŠś °Ąo {"^Š ”—ŅךøÅęØYŠ—jFŒÆf²–‰Äō‰ĮšĀ¢éOś+±kb0ŠŪĄĆ,sĄŠņk³±|&¤…mz–—N¹īŗV“)Žć~KL–3¶˜#£" ²@: MćŃ®I*;äITóĶ`gÄsAōF4ö\ź}öŚŻhEnĒ•6ŪtĒ·p¤ĘÖvŻ|ē—7Gwē¹w߄£8ÜÓ5ŠwįŒ“tųą9ßµxć”wżŸå:›ēuåœwō8s‰£ yē¤[Ō\i£u‡śź¬·īz룗.»Ł³Wūķ©]¤īøßĢ;„æ÷¾ošü/<ØĘ£—üńw./žóĢß;ōŃ?}õÕSŸödqöś÷ąw¦oB„_Łų•ožśģ{†~u×CÖ>^qļųj˜g^?Žø{WšWö‰sžŗ¬((€Čń_ž 8•.pBäßķˆ3® 0$¬ąåögŗųĮOƒZ¹ H2č9üqqżŪ5²’±~5Š„%, VčĮÜ=Š"ŠŒ „BBĄĮŠ‚¬cø‘I„ś;É2"Ź\Č2—ŁŽjd¼$.³” ņ-¦Š0…“CČÉT˜‘u ‰ŗŁ Ad#yźG]‘į~h÷±'r YāR¾8A2¤h~¬ˆ¼ō…FŠq7KŌ£Ā)µ'‰ĮŽ7DČ$NČVt’ŚĒ”•> ±’¤%'’CTŁŽ'Ćé  āĘĮ©MU–)ļ·ÅŃ1RYb ‚$K„xrvCœ$(bÄ4¢2!z4l°†4FB >U¼eÄPxĒ‚lŖSöiŁƒĢa‹Ž\ˆČŹ&I‹’xo~“Qc9'E1Sf+Nfb§IH#Ęry-uJ*–kdåKtśóŸ Ø@ŗ@VvxŌIp’Ee6Ź5ŒĢŌ$*+ ?į<„AĘ$&4`l]¾¼9KGI-&dYÜ¢B ”¬Y®q‡ŗÓe*O3ę›bR4·hĻ0VÓ”ūpÆĘŲI앤8»ĢØBdĒB¾ōNlØT£h2)RģŖ'±č@Ō»Q$j ŪJ½hTZ&¤§Ņ„ˆ ¹§ā&­­źŖ1»āÖĀ hJmˆČ²X×=AE«ąJ«Ņ×¾-T”^­HKżš“Ār3±ģU[7jÄgolė +W¶±C¬$E ä“cņ®äģfA;BŃVdj¦ŠdSūS²¶µ+¼,L’ŠZj&ŌH·Å--8Šā^F>óC®q—šą¶=Ī®t§KŻźZ÷ŗŲĶ®v·ĖŻīz÷»ą ÆxĒKŽņš÷¼čMÆz×ĖŽöŗ÷½šÆ|ēKßśŚ÷¾ųĶ/I;orafce-VERSION_4_14_4/doc/orafce_documentation/gif/MEDIAN.gif000066400000000000000000000035701501757153000235510ustar00rootroot00000000000000GIF89aŻ4p!łN,Ż4‡3f™Ģ’++3+f+™+Ģ+’UU3UfU™UĢU’€€3€f€™€Ģ€’ŖŖ3ŖfŖ™ŖĢŖ’ÕÕ3ÕfՙÕĢÕ’’’3’f’™’Ģ’’3333f3™3Ģ3’3+3+33+f3+™3+Ģ3+’3U3U33Uf3U™3UĢ3U’3€3€33€f3€™3€Ģ3€’3Ŗ3Ŗ33Ŗf3Ŗ™3ŖĢ3Ŗ’3Õ3Õ33Õf3ՙ3ÕĢ3Õ’3’3’33’f3’™3’Ģ3’’ff3fff™fĢf’f+f+3f+ff+™f+Ģf+’fUfU3fUffU™fUĢfU’f€f€3f€ff€™f€Ģf€’fŖfŖ3fŖffŖ™fŖĢfŖ’fÕfÕ3fÕffՙfÕĢfÕ’f’f’3f’ff’™f’Ģf’’™™3™f™™™Ģ™’™+™+3™+f™+™™+Ģ™+’™U™U3™Uf™U™™UĢ™U’™€™€3™€f™€™™€Ģ™€’™Ŗ™Ŗ3™Ŗf™Ŗ™™ŖĢ™Ŗ’™Õ™Õ3™Õf™Õ™™Õ̙Ւ™’™’3™’f™’™™’Ģ™’’ĢĢ3ĢfĢ™ĢĢĢ’Ģ+Ģ+3Ģ+fĢ+™Ģ+ĢĢ+’ĢUĢU3ĢUfĢU™ĢUĢĢU’̀̀3Ģ€fĢ€™Ģ€ĢĢ€’ĢŖĢŖ3ĢŖfĢŖ™ĢŖĢĢŖ’ĢÕĢÕ3ĢÕfĢՙĢÕĢĢÕ’Ģ’Ģ’3Ģ’fĢ’™Ģ’ĢĢ’’’’3’f’™’Ģ’’’+’+3’+f’+™’+Ģ’+’’U’U3’Uf’U™’UĢ’U’’€’€3’€f’€™’€Ģ’€’’Ŗ’Ŗ3’Ŗf’Ŗ™’ŖĢ’Ŗ’’Õ’Õ3’Õf’ՙ’ÕĢ’Õ’’’’’3’’f’’™’’Ģ’’’’÷ H° Įƒ*\Ȱ”Ƈ#JœH±¢Å‹3jÜȱ£Ē CŠI²¤É“(SŖ\ɲ„Ė—0cʜI³¦Ķ›8sźÜɳ§ĻŸ@ƒ J“ØŃ£H“*]Ź“©Ó§P£JJµŖÕ«X³jŻŹµ«×Æ`ÊK¶¬Ł³hÓŖ]˶­Ū·p欝+4€»xóźŻĖ·Æßæ€ L8oŒ‰v +ī{XbāŐ#KVÜććɅ+‹@!g‰ŸQ††8ŗk銧G¦öŗšnk…ÆAĘöv¶CŪq_ÕŻ–÷@߁ļAć‘'$¦¼es²ĀŸGŒ^[£ō‡×*‹a—hv°ŌS†ū’*ż;ĆģÜ3 ÷Žłąų“ļM[ÆQ õĶ›\­ Ąhp֟^Ź ˆ~ėż¦Ģo&hT|e"†GnU^BšmŌÜ$LH~%µ¶‚‡ūÜšYj£Ż·O)#ÕsW‹ Š6QkõüGį#™˜Wƒ3]ˆŠ$0v„\&ž¹ĒŽAŠtø ‹œÉØ$A…vƒ‹5¹ŻoHU(@ĪŚH+ō$$mFRŌ_ N)Ōjõ@Œz™c@=MÄā‡ŹČĶ>õ&†zR‚¹bšńˆęŽc&ts“š€7p1>j§#Ab<©‹&6†©}ū‰9d˜M +“¹’hP­E:”ĢŖW~ušē>™Ąøe‚‡Iy”—X~äå”’IøbcXĆ$¼ŖØģÆa:œzö-ˆŒHŗJŅ™)›[Dö”Z¢"ńĒ™ŠLx¢žŌó!1Ā^vØ@™LŅäŸ*j³²łkŠ$*›Æ@ÄĄ(†Ž/ $“öåU¤1y%Ā6Rd©Į)tšøHāBĘ]†Yd q†Ę$ś ˆ"AŹ€«2›®ģą£č†ˆņA4ĖKįĪ”Ńę ūŗѝ:<ō‚I”I™·xŲÅšŒ—BDIŲČē-i”żõƃ횟z,N‚ą–c:ć°“æi6źf¤ū@½’›NŠ+¼xS»mŽōuœŃ2„¹ÆµZž,B¾W&2ęE —\ß7’]ĘĶ)ćĖ섿šø¬vĢF-•™ōzļ>īc­†#¤wā ѼčzŻ—v””©¤!D3Ā:śHšŠ:Ļ+ŒZ“y»ąŪā&Z»Óć|“ģūļdcē1×Ū›ļŅ£0 óšé7„$śēŽ’ū±!įbLīK‘Č)³_{ōg,ĻYˆxū«ˆ‰P•³€‘xÓQ «Ņ?Õ\$P*źŻPøZ0xņ‰ß/>WqQ,ßm$čĮ¬T0]A’ŽNX·N°†ÅżĒūČ;MV ¢‡™q0F<¢—˜ė0Ń/!U §HEµx«ŠXĢ¢·ČÅ.zń‹` £ĒHĘ2šńŒhL£×ČĘ6ŗńpŒ£ēHĒ:ŚńŽ xĢ£÷ČĒ>Ź% ;orafce-VERSION_4_14_4/doc/orafce_documentation/gif/MONTHS_BETWEEN.gif000066400000000000000000000043671501757153000250020ustar00rootroot00000000000000GIF89a,4p!łG,,4‡3f™Ģ’++3+f+™+Ģ+’UU3UfU™UĢU’€€3€f€™€Ģ€’ŖŖ3ŖfŖ™ŖĢŖ’ÕÕ3ÕfՙÕĢÕ’’’3’f’™’Ģ’’3333f3™3Ģ3’3+3+33+f3+™3+Ģ3+’3U3U33Uf3U™3UĢ3U’3€3€33€f3€™3€Ģ3€’3Ŗ3Ŗ33Ŗf3Ŗ™3ŖĢ3Ŗ’3Õ3Õ33Õf3ՙ3ÕĢ3Õ’3’3’33’f3’™3’Ģ3’’ff3fff™fĢf’f+f+3f+ff+™f+Ģf+’fUfU3fUffU™fUĢfU’f€f€3f€ff€™f€Ģf€’fŖfŖ3fŖffŖ™fŖĢfŖ’fÕfÕ3fÕffՙfÕĢfÕ’f’f’3f’ff’™f’Ģf’’™™3™f™™™Ģ™’™+™+3™+f™+™™+Ģ™+’™U™U3™Uf™U™™UĢ™U’™€™€3™€f™€™™€Ģ™€’™Ŗ™Ŗ3™Ŗf™Ŗ™™ŖĢ™Ŗ’™Õ™Õ3™Õf™Õ™™Õ̙Ւ™’™’3™’f™’™™’Ģ™’’ĢĢ3ĢfĢ™ĢĢĢ’Ģ+Ģ+3Ģ+fĢ+™Ģ+ĢĢ+’ĢUĢU3ĢUfĢU™ĢUĢĢU’̀̀3Ģ€fĢ€™Ģ€ĢĢ€’ĢŖĢŖ3ĢŖfĢŖ™ĢŖĢĢŖ’ĢÕĢÕ3ĢÕfĢՙĢÕĢĢÕ’Ģ’Ģ’3Ģ’fĢ’™Ģ’ĢĢ’’’’3’f’™’Ģ’’’+’+3’+f’+™’+Ģ’+’’U’U3’Uf’U™’UĢ’U’’€’€3’€f’€™’€Ģ’€’’Ŗ’Ŗ3’Ŗf’Ŗ™’ŖĢ’Ŗ’’Õ’Õ3’Õf’ՙ’ÕĢ’Õ’’’’’3’’f’’™’’Ģ’’’’÷ H° Įƒ*\Ȱ”Ƈ#JœH±¢Å‹3jÜȱ£Ē CŠI²¤É“(SŖ\ɲ„Ė—0cʜI³¦Ķ›8sźÜɳ§ĻŸ@ƒ J“ØŃ£H“*]Ź“©Ó§P£JJµŖÕ«X³jŻŹµ«×Æ`ÊK¶¬Ł³hÓŖ]˶­Ū·p欝K·®Ż»xóźŻĖ·Æßæ€żĘ@ø°įƈ+^Ģø±ćǐ#Kžü8ĘD”+/Ĝ¹³gĀ–ržœ8“hŅØ%›N8:uįÕR.)[bķŽ·ęŽ¹[aæ9|`ńŠĒ—&Ÿq¹AēC‡ }śĆéÖ]&ĻŽūPļĢÆO:ļ{!ł”Õ?b’¹]½ÕóįĶw_Žgzėķ3„’BbP_HÜłWt쉇D’ŌŽ‚!)sĆ`’H_tź– C Ēą†õį’d²O‡ó wĆ@hܖIa& T"A²Ż€Ų‰W˜o†Åˆ˜„‡Å FŒŹĢø2–żxāaʜ£Œč„ˆP&hH©”Ch×%a/ ŌbšŠ€¶Ļ‹¬JŲ$ør˜a®½Ūī>ļŹ/–ŃZ&fĀ÷ péV$į Ó*«]Bõjb&™¬0/l1萝2*²Č1 J¤”VLknīcÆf:²¦ Ėģ`Ći,Ŗ|ŗźL°ž\NRå¹óźÜ±@7­åĪśBŲōAĖhŁ$AhŌūp[Š­_ņŪ/ŗfDāŅŠN,œ„ūX+Ś‘Y—Ämbńs‡ķ3°aļĆÅ£w© Æ7.É÷œ””Č3†ÕsC°8—Żß“T$¾ŽJ čŖ¼vż4GÆ>GłŖic~ķ“lĻĢźā’ Ż«EpŹ ®ŁgŹV坲Ó¹@1d¢²žhüņšG¶YkķÕś\¦c|$“ąkóōµ]jóHNi²×³Ėjō÷čņ¼‡uj¾ŻķĖ:Aā‚šŒ9Ū‡ā”ų2NšÜ74˜k;bŲåŠ`Ø=kH¹IąµšIĶY ĆūnŠcUjZæÉąüžuĻ$¤~Ķŗµk¬«*«»PŒĄŹöŁFøū šŃä6ūµńćȍW˜)ÓBe*Ū<=”1Ć÷-Ļø=¹÷ļąg¦0>ė|p€ÅL2{c łzf±Ē˜ żaōmgb/PŁL»)³Ū}ūų·~eu÷Wx’ 6č x M‚zūŌs4ŃVŸ@+8'!…h8§Ģ$ūLāœ…”ā>ūe(b]€ Xa{Ƅū9 E >čć@F4Śt “ć>ÄLH m,ŚFä@óéęn%’ˆä„Ųi72\°Hb Ή”ćnIź¶›z”a%E=éę›p®†Äģ³¢:–gēšbągž@YžwēŠ}ŃwV{Yś§[nb¦ępYīCeEmĀi鄜%8×Y MBc&$ž§]n1Ō‰ž2™Š¶£†6Rx*ŠKÄ$p“1é'^“é®k1‰éÆĄjÕD”Ug§ŠŠvC­4^W `hWW²ŅH›±ĄĶvź³u2™ N*[«@Ō>«ėIëM4ZŸŌjÖ$¶ó_|Įėd}eƤf‹$ūše$Ļ–wüõŅhƑk²yR„ģVl±M=Rœ•ĘÄ^ģńĒBe\Ē‘ ņÉ(ƒ$2a&7ŌrŹ0ĒL©»#O,óĶ8Ū,ŃĖSń¬Ļ9-ōʈé,ōŃHóH3ĖF'ķōÓ|-]4qPWmõ‚;óŖõÖ\w WÓW‡ķ4Šą‘’-öŁnšķŚh·ķ ŪČĮķöÜkĆ,7Żxæv·Žy÷żńŽ®ī÷ąœ Īšį„'īā¦1Ž™¦^G.łämłZ2åsYīęœw޵ę.{žč§Ü&ä¢Ó%Ó;«D“fRƒ­“é„£äøN·õ:Õ­G;ļÜŁ]»ģaåžÓī%!—ņ#µl|gmζ±ŗ³.¤ėæÆŽ»ķ=_ųšĄ{4[Y![ßqJĢŪ•~HĪ Ÿ=I@[Ų”–AyĻÓś*æÆšž"µO;’ģóHŸōdæ’™Ļ€č Xš÷’”,zŲŪȜŅUĄĶ!d:z¢ŽØś€ öL[ŗ|ˆ‚?Pu„`Aį »ē¾ ķDQ1Ł~Ņå’Ŗź!Ä`īŁ’ФÄōńF²Mx=…nvEDČĀ’¹Š GāĒʗ‚ 1j™Ž¶Ģu=k‹ÕŁā¢4hĆ$¤Q+|"ń%©ÜhQ@ £Ķl–„J±‰Ÿ¬bh’Ģ/!W\Hhśb¢ÖEM*$żÅŖ”¬hėó—‹ZÕA;ł)Z,ņS—ČG̓ЌgŌ“')2§ˆŻ°|YL]ŒE/$ķ«FĘŚŃ·øˆJPJawT#A 0Š!VŠŌĆŠ“;ā#l ™CĆsId=<d-±¶#Ą,ŒSō«fŠeŖdJS—d"8†–ݤ J[ŖK¤69Ī’Ž2 ā17·’”.uŲ|įaÄT(&…h„€jŃmbEĖśm-!(ŠįA/(śøaź)W1j;ĢŁk ł¹&ʟMӊ1K=š“Nhųš0ā!źįHB€QŅ¢vˆ±£XöåaL1ę;‘łÉó%äNó|±Xʂh°EéźPbÖ³%MŹ,GÄјK[J›°Ņ|vˆĶ(²ÓŖ­*Oցˆ*Ø™a±VT%¶sQÕ£ĖČŅѧ¤Æ™ĮŪ)Ȗ‰Y¦Ń"ėĮ+żŚ »·j­DH\æźS(ęOÆ“kĖɆ š Ž<åŌŹźNĪ.°²bu&<ß*N”„h£™Åģ-˜@Ҧ“ˆ…-¦ųJ¼>Ö';©e«ļ\ū×ĘźE§y īÉh¾Øu°Ē[ķ\[ėŁāÉVø¢®dū’>1µ~ŹMlqYėÖęvŗ‘}īX«›[nÖ·ÉļĘŌ‹ÄńJ—½3ÉZ®{‚ĻśŚw-īŗÆZņ«ßžzŽæžuą{³ąņ*īĄ” /‚ $ ĘĮ ްT Ü] [ų;.ģ…7·žrųƧɚoALāĆ)¶Ą(N1Tį[ā˜·“®‹gübļRFĘ4ĪńXp\3ėųĒ;fńƒ… ä"[…ĒŁż¦‘—\cō~ÉLŽr»|Œœ*¤Y¹ĮeA“lÅ|r™&P–²˜‹)d’*Dg%č ĻŗeSSĶ7 ’ó˜ē¬’§†é9­Ģ’ ųÜ6&ŻŠ}čS—żl؆Ś1ō ģէǙΐĘn;ĘŃčŠt²Ó„Ŗ³"5*”žÖQ­L5§*¢”Nū™/LäéVÓ€O bĀ5YĘZ7u*d–ޤ ,åʦ‚į³*ŁFݘR&¬vµ²qĀĄ>åęNbȵž (?E®¹I©UØ“¤ ƒ*¶T©¼ģræzœžH™DÅKIéiØRźŃHŚ\Ū<¤*›‘«ŗŠ›Ł6·ĄWƒe¼ą?ųĮ‹•gĘ@Cgj±Ō£(=l‹ CŚ-Ó¹'’rL’=š’ÆäÄPFŹeW®ņ–³<壙Ӕƙnbš“`‘¹Äć%£é“‡ęūZe>ĶsgŸ{Ģ5¹Ņ{Ö/żéŌ51Ō§ī\©Sżź\qŗO“Žõ®O÷{^{Uø~?±›}ĀM?»ŚBö“}ķpēī(ßøŪżīxĻ»Ž÷Ī÷¾ūżļ€¼ąOųĀžšˆO¼āĻųĘ;Žė;orafce-VERSION_4_14_4/doc/orafce_documentation/gif/NEXT_DAY.gif000066400000000000000000000044061501757153000240660ustar00rootroot00000000000000GIF89a<p!łI,<‡3f™Ģ’++3+f+™+Ģ+’UU3UfU™UĢU’€€3€f€™€Ģ€’ŖŖ3ŖfŖ™ŖĢŖ’ÕÕ3ÕfՙÕĢÕ’’’3’f’™’Ģ’’3333f3™3Ģ3’3+3+33+f3+™3+Ģ3+’3U3U33Uf3U™3UĢ3U’3€3€33€f3€™3€Ģ3€’3Ŗ3Ŗ33Ŗf3Ŗ™3ŖĢ3Ŗ’3Õ3Õ33Õf3ՙ3ÕĢ3Õ’3’3’33’f3’™3’Ģ3’’ff3fff™fĢf’f+f+3f+ff+™f+Ģf+’fUfU3fUffU™fUĢfU’f€f€3f€ff€™f€Ģf€’fŖfŖ3fŖffŖ™fŖĢfŖ’fÕfÕ3fÕffՙfÕĢfÕ’f’f’3f’ff’™f’Ģf’’™™3™f™™™Ģ™’™+™+3™+f™+™™+Ģ™+’™U™U3™Uf™U™™UĢ™U’™€™€3™€f™€™™€Ģ™€’™Ŗ™Ŗ3™Ŗf™Ŗ™™ŖĢ™Ŗ’™Õ™Õ3™Õf™Õ™™Õ̙Ւ™’™’3™’f™’™™’Ģ™’’ĢĢ3ĢfĢ™ĢĢĢ’Ģ+Ģ+3Ģ+fĢ+™Ģ+ĢĢ+’ĢUĢU3ĢUfĢU™ĢUĢĢU’̀̀3Ģ€fĢ€™Ģ€ĢĢ€’ĢŖĢŖ3ĢŖfĢŖ™ĢŖĢĢŖ’ĢÕĢÕ3ĢÕfĢՙĢÕĢĢÕ’Ģ’Ģ’3Ģ’fĢ’™Ģ’ĢĢ’’’’3’f’™’Ģ’’’+’+3’+f’+™’+Ģ’+’’U’U3’Uf’U™’UĢ’U’’€’€3’€f’€™’€Ģ’€’’Ŗ’Ŗ3’Ŗf’Ŗ™’ŖĢ’Ŗ’’Õ’Õ3’Õf’ՙ’ÕĢ’Õ’’’’’3’’f’’™’’Ģ’’’©÷ H° Įƒ*\Ȱ”Ƈ#JœH±¢Å‹3jÜȱ£Ē CŠI²¤É“(SŖ\ɲ„Ė—0cʜI³¦Ķ›8sźÜɳ§ĻŸ@ƒ J“ØŃ£H“*]Ź“©Ó§P£JJµŖÕ«X³jŻŹµ«×Æ`ÊK¶¬Ł³hÓŖ]˶­Ū·p欝K·®Ż»xóźŻĖ·Æßæ€ Lø°įƈ+^Ģø±ćǐ#KžL¹²’å˘3kŽĢ¹³ēĻ CÌ “éÓØS«^:†^ҬcĖ–ķZtaŲ³sė0÷īߥƒĖ60‘wJćx‘ŸTīWøóēŠ£KĻ‘9Iė ±'Õ¾{Hļ§‹ś"ųēķ¦’»^a{ļĘ’9_}óļóŌ/?E’kH€BT_6ØR|Öä_ƒAø1ĀǁǕ‚ø!~„L 7T˜‘‰laˆ‡N±ø\~Z„bB3ŽƒÄŲ‡Si©ų¢D<²ä¢I ĘXQ!Ł‘d"ߎV¢‡O YR‘U‚xPm)©ˆ‘$”‹łxP&“tdeBh’8yŠ j8evFž—P&h ÷S&a†GęAʐ㓁¢¦L&+ „¾Ą%A…šęę@+(#p „†˜E™iP¢jŹŁP„€‚JӚ#aŁP›ńYڤ`ö)Š yΊę¤Gjy©yY11Ä`©Ÿ7yWŚ@öw«ū< žrM"+F­ZZÆ]J‰øZäB±ņyii® §«™ŗ„ŖHŖ2Ą° 1*еn&šI¦ŹˆĮéˆöĮ›«Œ 1ŪėNõÜ`@·cėæŹ&kP=® Kгqyƒ2énŗĻ¢GyJqŁ~{'ؤķsļ„y¢‘#¢—"ßgėNœ­pŅ“U’^¼¹s°Ģ)śŽ–śóėŲ©Z8]”eæKŻž½¼ł¤ävO8™¢²öQӟŸOß§|ĪÉf#0“_ųbų…†@hü'27ōēW‚LŻW߃ĪäąBė”É€ž $ʀbš·Ļ ūLĀą†!N²1›ÅIƒ¶čbQ*T”AbóŪ@ļ)&¢±bgļ±ųāDī#jł!tƒ2A DL ÄFP­x1:ę”RGée‹‘-¦Łcłä@h ”Ģ–ū(¢@+0ÉߙP…IŲ—x¾(_—ĶH‚ū@x: “Ł ßµW`›ķ ڦ£K‘Ēgž”źµg™ś9Š$&Qžųצ~u –xą§MIZéŖó]ŠŠ€iŖF“²jk\®ZŲ‘¬n©zėÆĶåJÆmł ģ±¹ kZ’žŃŠģ³Æ)+±Ę9 ķµ¢Iµ¶Y†‹ķ·•i ·j ī¹x‰+³r™‹ī»Ķfdē¼~%Gļ½ųę«/ŖÕ ļæu<¬Ą[š¶'œĀłĖšĆ=9üÆÄW|ÅļblńĘ1i|®Ē‡¼Čߒ,ņÉ%™|­Ź(·¼®Ė± óĢŽŅL”Ķ8%3²;ēģ3C=ōĻD4ō­G’­tҬ2­ōĻNWõÓ8O§ÕTόõ—[gŻr×E‚ż•ū–möٌI9ڊ©m4ŪpĒÆŪ2zmhDdĖ Ż_‰­uĒę·MäVĶfĖYZQąHŚUøĶĒ1>Öą8Ž8B”Óō8Ķ‘_žQ†@eNųāž}×ęZnŅ‘ļõ„³āŅ•NŪéģRŻłźM€‰~‹^“åøcN;~vߞ2Gŗ3xcč°Æ-;A¾w\ūÓĘœQėąĮö:¦6žśhŸüž¾~­ųh`%ö|擮P&Ö<;DlV7żŅŖhoh>ōŪĆÜg6s˜tT“:X}twū›ūTŲĆ?į=¤P‰#ž×ŖgżT°"ž©Ÿö˜‡©& ƒ8zSś˜¤Ā}Ä<„É ÷Q Y xĆ’ä@•Ɔ¤Ź¢¢'Æūƒar(‚¢Ō£q’?™Mf|ĮӔŖ WđÅĄ;‚d‚}7œ`ŸbŃLū "в×7# ‰XÜaæ(āæ›‘P)śŽ qō6fÉQÄPž†~öķqt±+“ y8B„ų'~āI“XP38zQ„‰¤_5õéķNó Ÿˆ6ĀFN¹ĮNeŹåå_ qS¬ƐĮPC݃Ī'wÉĖ^śņ—e[1`E+;©'€A”eXš@D‡M¤+õŲŻż)Œ™Lę"—8FGzčŒõHP4”c·i-ăE„4bšBNF¬n°! Ńž§ßüĻQ\A§>#0’²rb4ŻzhABܧżŹ9®…P1Ń&ēÅX~ƚ\”śOæ°Eåó;uČöe“Frœ£_„Q‰Āor mØBZČM‰(~ݬčnšÄR”.DĢŲūˆÉHś „ŌiŗxZ3jDpƋé®b©Äš21ۜę;wzRs®ØRmŲó(¢»śõ®y‘\NĮV2O#7H`RķƒÖüYo­ńjėSĒz¬ŽņŽQM+_µŚ.½śŌ«ŃŻ¢ė8¦Źƅ5,DŽó²¼\œ/QƒŁĪ²M²ņŚlHZ ŚŅšö“ØM*­jWĖŚÖŗöµ°­lgKŪŚŚö¶øĶ­nwĖŪŽśö·Ą ®p‡KÜāj% ;orafce-VERSION_4_14_4/doc/orafce_documentation/gif/NVARCHAR2.gif000066400000000000000000000036331501757153000241020ustar00rootroot00000000000000GIF89ajPp!ł9,jP‡3f™Ģ’++3+f+™+Ģ+’UU3UfU™UĢU’€€3€f€™€Ģ€’ŖŖ3ŖfŖ™ŖĢŖ’ÕÕ3ÕfՙÕĢÕ’’’3’f’™’Ģ’’3333f3™3Ģ3’3+3+33+f3+™3+Ģ3+’3U3U33Uf3U™3UĢ3U’3€3€33€f3€™3€Ģ3€’3Ŗ3Ŗ33Ŗf3Ŗ™3ŖĢ3Ŗ’3Õ3Õ33Õf3ՙ3ÕĢ3Õ’3’3’33’f3’™3’Ģ3’’ff3fff™fĢf’f+f+3f+ff+™f+Ģf+’fUfU3fUffU™fUĢfU’f€f€3f€ff€™f€Ģf€’fŖfŖ3fŖffŖ™fŖĢfŖ’fÕfÕ3fÕffՙfÕĢfÕ’f’f’3f’ff’™f’Ģf’’™™3™f™™™Ģ™’™+™+3™+f™+™™+Ģ™+’™U™U3™Uf™U™™UĢ™U’™€™€3™€f™€™™€Ģ™€’™Ŗ™Ŗ3™Ŗf™Ŗ™™ŖĢ™Ŗ’™Õ™Õ3™Õf™Õ™™Õ̙Ւ™’™’3™’f™’™™’Ģ™’’ĢĢ3ĢfĢ™ĢĢĢ’Ģ+Ģ+3Ģ+fĢ+™Ģ+ĢĢ+’ĢUĢU3ĢUfĢU™ĢUĢĢU’̀̀3Ģ€fĢ€™Ģ€ĢĢ€’ĢŖĢŖ3ĢŖfĢŖ™ĢŖĢĢŖ’ĢÕĢÕ3ĢÕfĢՙĢÕĢĢÕ’Ģ’Ģ’3Ģ’fĢ’™Ģ’ĢĢ’’’’3’f’™’Ģ’’’+’+3’+f’+™’+Ģ’+’’U’U3’Uf’U™’UĢ’U’’€’€3’€f’€™’€Ģ’€’’Ŗ’Ŗ3’Ŗf’Ŗ™’ŖĢ’Ŗ’’Õ’Õ3’Õf’ՙ’ÕĢ’Õ’’’’’3’’f’’™’’Ģ’’’’÷ H° Įƒ*\Ȱ”Ƈ#JœH±¢Å‹3jÜȱ£Ē CŠI²¤É“(SŖ\ɲ„Ė—0cʜI³¦Ķ›8sźÜɳ§ĻŸ@ƒ J“ØŃ£H“*]Ź“©Ó§P£JJµŖÕ«X³jŻŹµ«×Æ`ÊK¶¬Ł³hÓ¦Œ ­Ū·pćŹu#”¹xóźÅ[įŻ½€įöUKŲ!€‡&n¹Ų`捏 K>9ce—OfĪl‘ódɞ)n~9ŚcčĻjOK,Ķ8”ꈯQ›ż5KېeėƌŲ5iߦwė¦mxkŽ…£öœiŅjćÅ(‰{ ²‰+÷źy0Äź½ƒÕ/pŃŪ?s“i"ł}™ÄĢŌ»ĄÄŚNĻŻą ō遦vū¼—Éyō C{Ź€]|õWķ=`a™] e ‰ALÖq±Ļ$ņĮWā†Ž)”…¦–2’¹'į@7(Óą[Ų”±{"—Ё2¶ØU`n½hßjy!¤L]Ĉ·OŒī'Z’ Mā’D¶%$RÆqF yF¹Oƒ P=G¢XgYŪ–Gu©,¦x•Ż˜Ų’óØ&AœA Ū p%§BN6ōžIžēfq’…uč~BŹ”K`&j馑5)G‹–źŸ Ųéoœj4*u3bD›©§§hr—ŹjgGÆĘŌ§¹łh뚓¦Ŗ«N¼ŖŚŖfĒöųę°>kY²¢BKź€Ģ6[[–Yŗ†ķ¶€iĖķ^„V»¬āśZ.Näž ¬ŗč²k¬»6„ ƼšāZļEō¢ō×·üö믿f.{ļ“ÄŖ÷ŻĄüķj°Ą‡ūS¾TÅń¹G;™Ä ?jķÅgģšEÄĢ*Ē {<+FhŽe±€%›\*F7Š^ŵRV!o †7RĘEž‹=ÖĻ;Ćh[7÷*¬ĖęJ4 Ž‚HR†ZęyXs™'1’h\Ł A™ōõtÖf~mŻb\{ŻXؘMWŃ vĢ4CŅ'4€®LY“;+8t÷ńÉ[Žb”³Š4 .õĪõ(sā$I?ŪņÜ5;tŻ Rö=õ‹‡µiv ӅÉ'f—Ēd¢„¹§ˆ¤76I xš¹äKSNųCbČÜōxŌīÓõĄ‡`‰X‡ WĄa:ę³šcžž–Č4^÷ä¶ßĪŠÓQW[q>ß$f+#"č ¾„ŗÕū)žsco—_dųpļ,=Ø’Öo’żųēÆ?^Šļģ­ģYŒt샦tmq j[xf¶&hP mZLU9„Uļ$KŠĮ‡¤E;ƒ”īF‰£2q_³ė“ĻpÄ`]R÷5Č „78”‚äC¦Šģ‚ ±]Õ»­ m?āYĮ1S"=‰ qizŅ 9øT_8d‰o%’>ŊQdHī"‡Eͱ,‹+A“½XҁQŠ(BQ÷Å3²{k\†Ü“Üé0q¤ćBfĒ;’éq*ū ¤ ±õĒBņˆL¤"ÉČF:ņ‘Œ¤$'IÉJZ2‘;orafce-VERSION_4_14_4/doc/orafce_documentation/gif/NVL.gif000066400000000000000000000040571501757153000232540ustar00rootroot00000000000000GIF89aū<p!łA,ū<‡3f™Ģ’++3+f+™+Ģ+’UU3UfU™UĢU’€€3€f€™€Ģ€’ŖŖ3ŖfŖ™ŖĢŖ’ÕÕ3ÕfՙÕĢÕ’’’3’f’™’Ģ’’3333f3™3Ģ3’3+3+33+f3+™3+Ģ3+’3U3U33Uf3U™3UĢ3U’3€3€33€f3€™3€Ģ3€’3Ŗ3Ŗ33Ŗf3Ŗ™3ŖĢ3Ŗ’3Õ3Õ33Õf3ՙ3ÕĢ3Õ’3’3’33’f3’™3’Ģ3’’ff3fff™fĢf’f+f+3f+ff+™f+Ģf+’fUfU3fUffU™fUĢfU’f€f€3f€ff€™f€Ģf€’fŖfŖ3fŖffŖ™fŖĢfŖ’fÕfÕ3fÕffՙfÕĢfÕ’f’f’3f’ff’™f’Ģf’’™™3™f™™™Ģ™’™+™+3™+f™+™™+Ģ™+’™U™U3™Uf™U™™UĢ™U’™€™€3™€f™€™™€Ģ™€’™Ŗ™Ŗ3™Ŗf™Ŗ™™ŖĢ™Ŗ’™Õ™Õ3™Õf™Õ™™Õ̙Ւ™’™’3™’f™’™™’Ģ™’’ĢĢ3ĢfĢ™ĢĢĢ’Ģ+Ģ+3Ģ+fĢ+™Ģ+ĢĢ+’ĢUĢU3ĢUfĢU™ĢUĢĢU’̀̀3Ģ€fĢ€™Ģ€ĢĢ€’ĢŖĢŖ3ĢŖfĢŖ™ĢŖĢĢŖ’ĢÕĢÕ3ĢÕfĢՙĢÕĢĢÕ’Ģ’Ģ’3Ģ’fĢ’™Ģ’ĢĢ’’’’3’f’™’Ģ’’’+’+3’+f’+™’+Ģ’+’’U’U3’Uf’U™’UĢ’U’’€’€3’€f’€™’€Ģ’€’’Ŗ’Ŗ3’Ŗf’Ŗ™’ŖĢ’Ŗ’’Õ’Õ3’Õf’ՙ’ÕĢ’Õ’’’’’3’’f’’™’’Ģ’’’’÷ H° Įƒ*\Ȱ”Ƈ#JœH±¢Å‹3jÜȱ£Ē CŠI²¤É“(SŖ\ɲ„Ė—0cʜI³¦Ķ›8sźÜɳ§ĻŸ@ƒ J“ØŃ£H“*]Ź“©Ó§P£JJµŖÕ«X³jŻŹµ«×Æ`ÊK¶¬Ł³hÓŖ]˶­Ū·p欝K·®Ż»xóźŻĖ·Æßæ€ |7€Ćˆ+^Ģq ‡†KžL¹²eɏF¾Ģ93Ā͜C‹}Ų3į‹ I«^MŚ“Ba7”}”vBŪqŌ”·ĮŌ¬»^ė{ińݱ’¹|_ó‰ĒŸė|.=bõ°×‡JĻ®¼;ŅęÜgæ#®-Žcų®ē™{ļø=)ųä·É3L?ž-żžķĶÆ7ś^|žå±’×}<å'`€.DąAŃɧ |/c~SxP&h@·_HŠŌ߁-˜2ˆ…D„,)sƒaJeaAŹ ·į"Å ĘHrŌ H$*³O&2ftāA*V$"Eb‰s-†øä@°Żš¤@ āƒ”A E/”Éa7PécŹ4rĆa©˜¤@‡uhā|(tܗ„¹O c L™gʦā +db'“q†˜P&7jøŅ$øi囑H‰ūL2É@“ QĻ£¹Ķ8Š Fz*Š$™Å°e‘Jī³f„2źć>7dŗ„‡pśg(B¤Ryj˜©®ši„Ōće ł—*})4q’Zh³Äx,4žŻ  4Ī )j=70«h­šj‘ŖĘp)¬ć>ö+AĖā®Žõ…;®b˜+µi>††›ifK(–‰1%Dž č«Ķ6i„h,I©Ŗc>¶)N] dØDŒb‰ęzļ@Ą‰ļ@1’”c§4“qbW ņb \.­ļ„č·$%9pĀ֗™l7cȦ·5UL%Ę5“nģ#~ßų0£ū„\Š$;Ē’†F¦›ļĖy¦Ī6ś¹ē›/޸Ӑß<9l–SÉvl1¬({쓯8ē¹ÖŃCķ»ó¾ūģæėīūī lÜ܎°n\6ŁĪ_4“×{Ćģ²'0—Ųó>{q’Ź÷e¢Qālģįębdź~ū„#ß¶ūģÓžłć棈łhVīhb™Óˆž GĄ¾ŠpĒŁžD wĄšŒ 1 AĄÉLN ƒm6E›Iˆ”C³‰ŃžF,€™0"R’ÉÉ ņ:Q±©")|IŚ0ˆ3‘(‹p7aŽœĘ&„)¦„)įeb%+$C#žd†Z GĀ("ņl'z“”‘•Ŗ1¢$±XņėMó…““č 9=sѧx+5ń":ŌĪĮØ1JtŠĖF”|Ž}TĻɒ%*‹tŒŹ¹8H üŃ"qōć ŁF™/MY$äžFņEbÖ^²*,Vh D„)O(Ą@śD”‰|É)vŹŁ,Æ1ʹ„.ƒ3Ÿ]*ę5¾ &g& É ó˜¼<2oƒĢe:󙩌¦4§IĶjZóš=Ų̦6·ÉĶnzó›ą §8ĒIĪršóœčL§:×ÉĪvŗóšŒ§<ēIĻzŚóžų̧>÷ÉĻ~śóŸ h7;orafce-VERSION_4_14_4/doc/orafce_documentation/gif/NVL2.gif000066400000000000000000000051331501757153000233320ustar00rootroot00000000000000GIF89a Bp!łC, B‡3f™Ģ’++3+f+™+Ģ+’UU3UfU™UĢU’€€3€f€™€Ģ€’ŖŖ3ŖfŖ™ŖĢŖ’ÕÕ3ÕfՙÕĢÕ’’’3’f’™’Ģ’’3333f3™3Ģ3’3+3+33+f3+™3+Ģ3+’3U3U33Uf3U™3UĢ3U’3€3€33€f3€™3€Ģ3€’3Ŗ3Ŗ33Ŗf3Ŗ™3ŖĢ3Ŗ’3Õ3Õ33Õf3ՙ3ÕĢ3Õ’3’3’33’f3’™3’Ģ3’’ff3fff™fĢf’f+f+3f+ff+™f+Ģf+’fUfU3fUffU™fUĢfU’f€f€3f€ff€™f€Ģf€’fŖfŖ3fŖffŖ™fŖĢfŖ’fÕfÕ3fÕffՙfÕĢfÕ’f’f’3f’ff’™f’Ģf’’™™3™f™™™Ģ™’™+™+3™+f™+™™+Ģ™+’™U™U3™Uf™U™™UĢ™U’™€™€3™€f™€™™€Ģ™€’™Ŗ™Ŗ3™Ŗf™Ŗ™™ŖĢ™Ŗ’™Õ™Õ3™Õf™Õ™™Õ̙Ւ™’™’3™’f™’™™’Ģ™’’ĢĢ3ĢfĢ™ĢĢĢ’Ģ+Ģ+3Ģ+fĢ+™Ģ+ĢĢ+’ĢUĢU3ĢUfĢU™ĢUĢĢU’̀̀3Ģ€fĢ€™Ģ€ĢĢ€’ĢŖĢŖ3ĢŖfĢŖ™ĢŖĢĢŖ’ĢÕĢÕ3ĢÕfĢՙĢÕĢĢÕ’Ģ’Ģ’3Ģ’fĢ’™Ģ’ĢĢ’’’’3’f’™’Ģ’’’+’+3’+f’+™’+Ģ’+’’U’U3’Uf’U™’UĢ’U’’€’€3’€f’€™’€Ģ’€’’Ŗ’Ŗ3’Ŗf’Ŗ™’ŖĢ’Ŗ’’Õ’Õ3’Õf’ՙ’ÕĢ’Õ’’’’’3’’f’’™’’Ģ’’’¬÷ H° Įƒ*\Ȱ”Ƈ#JœH±¢Å‹3jÜȱ£Ē CŠI²¤É“(SŖ\ɲ„Ė—0cʜI³¦Ķ›8sźÜɳ§ĻŸ@ƒ J“ØŃ£H“*]Ź“©Ó§P£JJµŖÕ«X³jŻŹµ«×Æ`ÊK¶¬Ł³hÓŖ]˶­Ū·p欝K·®Ż»xóźŻĖ·Æßæ€ Lø°įƈ+^Ģø±ćǐ#KžL¹²å˘’3kŽĢ¹³ēĻ C‹Mŗ“éÓØS«^Ķŗµė×°cĖžM»¶ķŪøWĒĄ»·ļߥƒ N¼øqć18ī>μ¹ļä—;ŸN½9tŠŅ«k’}=śöļąwO˜=|õń Ė›_æ½Dõģ™»' @kż÷[柸h’ˆ’„ €R X&!ˆ‚B1Ȑƒ"AŲ•„KQųąKHT†qȑ‡ŲˆeHāM'ī“āE+:”É|:µč߇Z$£€6ÖČ¢ˆŗdbS)ŽČ_IŹÜ°[ƒöŃčcŽC‘(¤DAņøŠ“VY!FTB”%Ab‰ŠHfuć–9¹!“śa)„BdŽ%Hj.Ņ$ 1P›įiӘ:R¤gžh²eTž™ŠL šęG™ †2!ečL|Źéē™Mz¢OŚēCš’ÄéJO¹4’…ē‚_Ž¹Ļ ­īMr’)Ó[¬1UŠP&“Œdf“’ŗjEE2tƒ@¾šŠ± Łéf‹j‰Q± 1›,³ak­¼:lAõh ’]āéŒq;­ūdŅČ@“ ĮnA1@Ŗ¢½¹*‰ŒųūÓÆŃfŠŃ$ęnŪ2+¤›°B1ˆė-“‚¾yĮ )sšĀŪb\­6ŗą·ÅėėFhŌÉf˜ s]}į$1`D ¶b0Č.ŪÜĄ5 €µrLŒ7ŻĢ]Ž,°„KŹ[«łŻ'Fßł4·ÉÕĖŪ±QcŻ.oŻńÖė³S~Zę”O 5²TÆ|5ŲūhżsĢ÷’Āķ3t™`«ń¹MaFŠQOŁ’žŒĘ—õÜWļ>Ō"øøLŗ¦ZĻe²p _Z¬ā—%CІāå*Zc×§9ćĢĪ7ē©ļs8ćbČsÜi>»åŻpū ńź,9ÄĀZyźj3]ćĢb.{ģ³+S;·/ŸÜī ū^¹~ū{śķć^dńć„£{мÉAs_& ×nėąŁÖN©¾ą: hߢŗOĖÆĘąl²ūKN#œ„“K1Ķ€!†£Ā+£W*ƒ—l%æ}pR5‹¤DĘ8;]p°×ź*²EĢxQ`ø¶š:"£ą@>˜ĮÅqP„T’s×>Ģ{ÉDļG‘r•Š;ńiĪÉŚ%øūŌ#9ĘF©$¦KOį¹ās»ޭėX7ŻčĄƒ!ó0¤sūČ ģ¾”‰X!O hä^!Ł„fÜćVo*8Ā1§ŒŌ9#0تݹ‘ŠqDįŲŖ—qæ© ųµž…°/Bß!ąŁ wŜ@Z™žÖå„=я ü+ąApńROtb99 žÄt d–ČVFĒX ņE\œ%tź3+`,„±l„ĮŽX¾JkWŗ“/_w'e³]ĀL^1÷qLe$Ó=Fj&ĀĮšEÄbRՎ~Ø..ŠĮY‰ŪĄG’“ČiHT¶$$uHŒKĪ‹N¬K-ŗĪóŻu« gÜźč>©M¢XEŖ‡ę¶ƒä4.hśä¢š†'ĪŅIĢ p|(tZQ86”m½Dӝ’^tŸq£āńgźżM"³Š=MčĶ‹‹łį˜@Ō÷ŸŻj~żBˆo:NyvKEĪZōJöT!“©¤¬eAŅ„Ŗ½JlīƒÜąø5HĘ vR`֞v,K O»'O­>S©c-ŚĆz·Põ­FCk «¶œ¼ °OU‘oÄčŖ­nJ•qė]’•¤¤ī Ÿ4}ˆöœ¹ŹćŁ5³W"A49ŗ*— $­GND'Փҵ§•-‘BŹiN¬2³x¶ˆLKėX8‰^ŸŻdhmIK¦ZĈå‰:Ų[V¹ ng;5WēN6)ؽ„F,&Õ%šļ*öōčswB:ėŽ)žbīo’Ż«fÄVöK'±^óšö»÷ot’Ž›U—½8Cɓč4ÄĘā·*õš~qR^7wøŽå¬pO`ķ~¤dęZīy©kY £²†ģtŅ_Æ·(ķ•īFʇ/ ū)‰0Žń˜dģŃųʉ厏ƒ„ū˜8#ś1$d!÷øČĮ‰d閛&;łÉi­‹”Lå*ƒ&iVβ–·¼..{łĖ`³˜ĒLę2›łĢhN³š×Ģę6»łĶp޳œēLē:ŪłĪxγž÷Ģē>ūłĻ€“ MčBśŠˆN“¢ĶčF;śŃŽ“¤'Żę€;orafce-VERSION_4_14_4/doc/orafce_documentation/gif/ROUND.gif000066400000000000000000000042631501757153000235030ustar00rootroot00000000000000GIF89aTp!ł;,T‡3f™Ģ’++3+f+™+Ģ+’UU3UfU™UĢU’€€3€f€™€Ģ€’ŖŖ3ŖfŖ™ŖĢŖ’ÕÕ3ÕfՙÕĢÕ’’’3’f’™’Ģ’’3333f3™3Ģ3’3+3+33+f3+™3+Ģ3+’3U3U33Uf3U™3UĢ3U’3€3€33€f3€™3€Ģ3€’3Ŗ3Ŗ33Ŗf3Ŗ™3ŖĢ3Ŗ’3Õ3Õ33Õf3ՙ3ÕĢ3Õ’3’3’33’f3’™3’Ģ3’’ff3fff™fĢf’f+f+3f+ff+™f+Ģf+’fUfU3fUffU™fUĢfU’f€f€3f€ff€™f€Ģf€’fŖfŖ3fŖffŖ™fŖĢfŖ’fÕfÕ3fÕffՙfÕĢfÕ’f’f’3f’ff’™f’Ģf’’™™3™f™™™Ģ™’™+™+3™+f™+™™+Ģ™+’™U™U3™Uf™U™™UĢ™U’™€™€3™€f™€™™€Ģ™€’™Ŗ™Ŗ3™Ŗf™Ŗ™™ŖĢ™Ŗ’™Õ™Õ3™Õf™Õ™™Õ̙Ւ™’™’3™’f™’™™’Ģ™’’ĢĢ3ĢfĢ™ĢĢĢ’Ģ+Ģ+3Ģ+fĢ+™Ģ+ĢĢ+’ĢUĢU3ĢUfĢU™ĢUĢĢU’̀̀3Ģ€fĢ€™Ģ€ĢĢ€’ĢŖĢŖ3ĢŖfĢŖ™ĢŖĢĢŖ’ĢÕĢÕ3ĢÕfĢՙĢÕĢĢÕ’Ģ’Ģ’3Ģ’fĢ’™Ģ’ĢĢ’’’’3’f’™’Ģ’’’+’+3’+f’+™’+Ģ’+’’U’U3’Uf’U™’UĢ’U’’€’€3’€f’€™’€Ģ’€’’Ŗ’Ŗ3’Ŗf’Ŗ™’ŖĢ’Ŗ’’Õ’Õ3’Õf’ՙ’ÕĢ’Õ’’’’’3’’f’’™’’Ģ’’’’÷ H° Įƒ*\Ȱ”Ƈ#JœH±¢Å‹3jÜȱ£Ē CŠI²¤É“(SŖ\ɲ„Ė—0cʜI³¦Ķ›8sźÜɳ§ĻŸ@ƒ J“ØŃ£H“*]Ź“©Ó§P£JJµŖÕ«X³jŻŹµ«×Æ`ÊK¶¬Ł³hÓŖ]˶­Ū·p欝K3€»xóźŻĖoŒ‡vū Lø°įƈłž„ĖøńH!;”,–²ć˘1ZŽøYagƟ3‹½0ōEÓQkUMŗ5iÖa ”m•¶ėیm?¤­{joÜĄŻžfČ›ģšąČŃ÷¼{!7ŠQŗ<¹õŹ‘›+\Į˜ź×ĆӭްxB¼ÄnLŗ«,š>ew£#%’/¾>Vś©µ#Ģ4é} 4ūd@&ö'1ąŁ§ąZųdBb(ĘtūˆŃ_…Š”L‚ vhVƒ=xŠ ’(‰ū˜4zčbm„E–˜B‹q'ūŲøXR‡!ųāF”ā@"DĢ_ŹČ—¤@ķķsäR¬Éä”B y^EE” €Mś'Š$\B×byT– ”•b©_X¬ iꛣ]¹Ÿš“Gœxā„fGY‚vgž€Ī“'G}vÕf ˆĀ4(gk‚uh¢®“ØF…rõh¤˜š4iF•nui¦ †“©f~õiØØźYb3NĘź«°Ę*ė^¦j+„·™ė®¹Ł”ƼB ¬‚Ćh±õ!k,žŹ†×ģ²f>k“ŠNI-r×’Vūb¶Ąq«ķƼzŪ•³–k.b‘{.­ ©»ī»}}W箺¹ ƼU‰«é¼|ņĖS§˜źę«¾)L’lū»Ą‘ g¾¾)ŒkC—*g®{Tń¾R!üpi?1,lD ×1Å3ē“ȉfÜÆÉKĢ©ĢzZŖĖŖ†Ÿ 'ך³Ļ Ū *Ό~”ä ļ#¤^ZāEą>õXõlOæ'™^U’ rBüÅF³AhdM” )ŃÕC6ɉ1 Ņ<#4õ@ ” Ž÷@Š@Ÿe~ī£Ö*#„#Ū(7“†)søH,#Šö@`R4äszļ“i};8›ēš±(ŠŌQ’wŁw=š “cŃ@”å_ļó܀’¹ ’ń˜{Ź…ß:¹®^k$ Øæyļ“ ¹zŠnøģNŻyˆŒ³¾õAųJäń~:B– …bˆ‚w ōŗĘfŒ8BćQ{1To¼¢ żķ—@éįĪń/Ł_›Ū@Pd½ŽdyŁŽAĄ84PˆrŚŠŠ˜„Ą™ÅN} TČ÷ÜW·‰m~/A|ׄČ2;ćß÷¦Ęæ,īe­Ć_öÖw½‚8n hČP^Nč$½<pLÕļģ–¹ VsAl‰iZX·Ļ„ķjƒS›+$  x^‚a H§fq\ČD € åĶģ!?“Õ÷Q9ķQ¤o[`EÆŽŻ`1MTŚ…&!„L§…ƒą>Øt‘Ér†l+ÄĄ'É2łSچF(#xYņ’˜Ģ¤&Ė„öiOV1øĮ /F?¹]‘ +Š›ż²6;\(uŖGßvČ»Cä|nLÜA1ČĒvn³Ztģ'ŖoŠsœ|Ö¢øEE`§Ėsb»,¢/²mN±”ĻŒŻséś$-O”©G/"óx1«ę1miĶk’ }IRü@č’sÖRŽų,§Mü §’q„bJ]{¶El64'}“A;ŅͤEˆōœ'@{rŃ2MŌ#Į”IGšÄ{ “&#µÖ?óéLØ@S£łY™=MŠQ—nņ¦‰,M&]…ÓwĶō4;ż©P‡JŌ¢õØHMŖR—ŹŌ¦:õ©PŖT§JÕŖZõŖXĶŖV·ŹÕ®zõ«`MK@;orafce-VERSION_4_14_4/doc/orafce_documentation/gif/RPAD.gif000066400000000000000000000051551501757153000233430ustar00rootroot00000000000000GIF89aN_p!łA,N_‡3f™Ģ’++3+f+™+Ģ+’UU3UfU™UĢU’€€3€f€™€Ģ€’ŖŖ3ŖfŖ™ŖĢŖ’ÕÕ3ÕfՙÕĢÕ’’’3’f’™’Ģ’’3333f3™3Ģ3’3+3+33+f3+™3+Ģ3+’3U3U33Uf3U™3UĢ3U’3€3€33€f3€™3€Ģ3€’3Ŗ3Ŗ33Ŗf3Ŗ™3ŖĢ3Ŗ’3Õ3Õ33Õf3ՙ3ÕĢ3Õ’3’3’33’f3’™3’Ģ3’’ff3fff™fĢf’f+f+3f+ff+™f+Ģf+’fUfU3fUffU™fUĢfU’f€f€3f€ff€™f€Ģf€’fŖfŖ3fŖffŖ™fŖĢfŖ’fÕfÕ3fÕffՙfÕĢfÕ’f’f’3f’ff’™f’Ģf’’™™3™f™™™Ģ™’™+™+3™+f™+™™+Ģ™+’™U™U3™Uf™U™™UĢ™U’™€™€3™€f™€™™€Ģ™€’™Ŗ™Ŗ3™Ŗf™Ŗ™™ŖĢ™Ŗ’™Õ™Õ3™Õf™Õ™™Õ̙Ւ™’™’3™’f™’™™’Ģ™’’ĢĢ3ĢfĢ™ĢĢĢ’Ģ+Ģ+3Ģ+fĢ+™Ģ+ĢĢ+’ĢUĢU3ĢUfĢU™ĢUĢĢU’̀̀3Ģ€fĢ€™Ģ€ĢĢ€’ĢŖĢŖ3ĢŖfĢŖ™ĢŖĢĢŖ’ĢÕĢÕ3ĢÕfĢՙĢÕĢĢÕ’Ģ’Ģ’3Ģ’fĢ’™Ģ’ĢĢ’’’’3’f’™’Ģ’’’+’+3’+f’+™’+Ģ’+’’U’U3’Uf’U™’UĢ’U’’€’€3’€f’€™’€Ģ’€’’Ŗ’Ŗ3’Ŗf’Ŗ™’ŖĢ’Ŗ’’Õ’Õ3’Õf’ՙ’ÕĢ’Õ’’’’’3’’f’’™’’Ģ’’’­÷ H° Įƒ*\Ȱ”Ƈ#JœH±¢Å‹3jÜȱ£Ē CŠI²¤É“(SŖ\ɲ„Ė—0cʜI³¦Ķ›8sźÜɳ§ĻŸ@ƒ J“ØŃ£H“*]Ź“©Ó§P£JJµŖÕ«X³jŻŹµ«×Æ`ÊK¶¬Ł³hÓŖ]˶­Ū·p欝K·®Ż»xóźŻĖ·Æßæ€ Lø°įƈ+^Ģø±ćǐ#KžL¹²å˘3’kŽĢ™m  C‹Mŗté?›^Ķŗµė×°cĖžMŪ4źĪøsė.`do‡æ-ßM¼ųåį‘+T.™¹ńēŠ;ß8Ż`uĒ×£kߎ7ūEļĮKēN¾ü_ńÅ£G¼Ž¼ū÷eŪGTY>üūųµŚH’xž’’µpüq„F&øĻ Ź@$Ś@7`5`€VXŌ„ õ§Ń @‡Ż@Œ@™ō¦Ģ ZØāŠRaø†)#Ę Ü¶ Łˆ#% “c&(*s›ˆ uøć>æ C‰0Ć 6Bå"‹TV Ӕ Į˜ą‡ū !Ę>™|y#`ŽöY™Å`Ą>2²Ł$˜f_f2ämhp9‚“ŲŁ¢•|ö –iIP #ędŚé%’F~)‚“ˆ&£>Ŗ hŽŲ “T؟ †ś¢l¾‘А„ī1'"ŚŖ@h)ʦFf"ä@™dź!‚æĶźim£ū*ź°Ä†W H‚ t+¬³Śh«6rak“¼ž2Ė.ØL=ƅYO„ŁN5”°Å– j²”{©@yŗ «‰\āˆ-—unį>·µIi» Źć­įīiѧę ŗHf„®u‚v'h8’ń½LЁZ›Äܛ±²Ū(‚—.Ł©§ßl²•“›Ž±=ŠR¬–|ņĢ*"¬ėĄ,óV“ØüՄÓ,tfkT4v2­ō}GcŌ4c@/-õ{OćL VO­õvUWŌubQo-öĮ9'Wöda­ön_OŌöaiÆ-7gźkjCvē­÷Ž|÷żZŅs^Ÿą+n8eAKŒųįŒĒµøŅ7.łZ‘ ]łä˜Ē—ł‹›w>Ųå3ƒīłčY‰n²é¤§.®ź²īz]Øūė“5{¹·×®{P¹ŪūīĄļō»ØĆo|Mş{üņa%ļ§óią÷ōŌ³‘ōՏv}öÜw’÷CŲ{ļPųŽ—ļŚšŅ.ŸłŠ_Łz‘ĆĻ–üČ^-šŁ¤Æļ’[Ģ\Ń’’i ŁšF•õ“enŪßXxzāf`ŗģŖ/õ[ąūŅ—A ¢E‚ŌńąS,ų:żu0$=ź MB£qP--T˜BBיš"Ņ™TøAüMЇü›į3TĄł\P"ń ŽŖÅC„\J{n ™Ā!Ž} y/DH&¦X8!&Äg«¢ Ø_„†¬»”A¢äµ,q +“Īr"'k ¤ŠlbwE“²‰YdČŗJČzqŠų£PŠØ:5$#˚FJD®8ź,KįÖ>4 ”L1č^ T I—I’ˆĖĮ·š”±ˆQŒ2$#B6¶’<½ÉGLŃM™:G^ņ”¹ƒäŲ㠒D؁FpøÕ z ĘeǼÖLZˆ”Šad½QP‰ty?Y‚<Ձ$šš… b¼Iœ9įež0xŖ›±3˜jŃA,Ł:„¬ņAQ M¦¶Č¦Ū nj1i”"(ĘKqŃW×¼J vH—Ł©M™ Ų@e²wöņį'0%ņFLÓ Źäˆ˜£ŠŌC™õ ȳ¦IJd2–7āŅo†i•…nŽ_T†9Eƒ4ȳ%ó…ŃGF²‹©=Ŗ‘’f§`ś ' ¢Æ.ebŖlBŃ4g£‰ņ‡«Z¼ĶŁO õ±QȚ¢yǁ€›ČcŸ\ēJ×ŗŚõ®”QČ$–ź6½RØĮź“©œ\ äVĆį`½IĢ25F½š„2"dØĮō¦-HeńÕ Kaė^dÕ =W9¶!2€<”*¼„„ŌC_R¹VĄ3LaQŒ¦m£wDŁ&i“¦-µ£nQyIåSYł%NF;·źhõ“!†ÅķZŃöš”.cĻbĶ—·‚CbFłZŌ‰P2³é¼īv Ęæž2€Į“w9ĘšĘ2F^½¬C”:OŸ0÷›ń½ļz5§_ķVw„ö#7 .(¶ž<łļŻ‹ŁG0ĄóµpS$¬¶$vD‡«ż/‡;bSč6¾FŖ†™2b±yŲ#”lˆÕūŻ 8ˆ7V0}»™`2$yŖ“i¼c§ø®pėŪc“˜$®Œ0‘W¬ćs7É&Ž#“›\^ń†®ĖÅ«˜”ó9hĢh¾ŽĢ¼ę4³™Ėéy3œēLē:ŪłĪxγž÷Ģē>ūłĻ€0“ MčBśŠˆN“¢ĶčF;śŃŽ“¤'MéJ[śŅ˜Ī“¦7ĶéN{śÓ ī\@;orafce-VERSION_4_14_4/doc/orafce_documentation/gif/RTRIM.gif000066400000000000000000000046071501757153000235130ustar00rootroot00000000000000GIF89ah\p!łH,h\‡3f™Ģ’++3+f+™+Ģ+’UU3UfU™UĢU’€€3€f€™€Ģ€’ŖŖ3ŖfŖ™ŖĢŖ’ÕÕ3ÕfՙÕĢÕ’’’3’f’™’Ģ’’3333f3™3Ģ3’3+3+33+f3+™3+Ģ3+’3U3U33Uf3U™3UĢ3U’3€3€33€f3€™3€Ģ3€’3Ŗ3Ŗ33Ŗf3Ŗ™3ŖĢ3Ŗ’3Õ3Õ33Õf3ՙ3ÕĢ3Õ’3’3’33’f3’™3’Ģ3’’ff3fff™fĢf’f+f+3f+ff+™f+Ģf+’fUfU3fUffU™fUĢfU’f€f€3f€ff€™f€Ģf€’fŖfŖ3fŖffŖ™fŖĢfŖ’fÕfÕ3fÕffՙfÕĢfÕ’f’f’3f’ff’™f’Ģf’’™™3™f™™™Ģ™’™+™+3™+f™+™™+Ģ™+’™U™U3™Uf™U™™UĢ™U’™€™€3™€f™€™™€Ģ™€’™Ŗ™Ŗ3™Ŗf™Ŗ™™ŖĢ™Ŗ’™Õ™Õ3™Õf™Õ™™Õ̙Ւ™’™’3™’f™’™™’Ģ™’’ĢĢ3ĢfĢ™ĢĢĢ’Ģ+Ģ+3Ģ+fĢ+™Ģ+ĢĢ+’ĢUĢU3ĢUfĢU™ĢUĢĢU’̀̀3Ģ€fĢ€™Ģ€ĢĢ€’ĢŖĢŖ3ĢŖfĢŖ™ĢŖĢĢŖ’ĢÕĢÕ3ĢÕfĢՙĢÕĢĢÕ’Ģ’Ģ’3Ģ’fĢ’™Ģ’ĢĢ’’’’3’f’™’Ģ’’’+’+3’+f’+™’+Ģ’+’’U’U3’Uf’U™’UĢ’U’’€’€3’€f’€™’€Ģ’€’’Ŗ’Ŗ3’Ŗf’Ŗ™’ŖĢ’Ŗ’’Õ’Õ3’Õf’ՙ’ÕĢ’Õ’’’’’3’’f’’™’’Ģ’’’¬÷ H° Įƒ*\Ȱ”Ƈ#JœH±¢Å‹3jÜȱ£Ē CŠI²¤É“(SŖ\ɲ„Ė—0cʜI³¦Ķ›8sźÜɳ§ĻŸ@ƒ J“ØŃ£H“*]Ź“©Ó§P£JJµŖÕ«X³jŻŹµ«×Æ`ÊK¶¬Ł³hÓŖ]˶­Ū·p欝K·®Ż»xóźŻĖ·Æßæ€ Lø°įƈ+^Ģø±ćǐ#KžL¹²å˘’3k>€ēĻ C‹ż9FĆΤS«^Ķŗµė×°W›ŽL1€·ę¶»»¶oĮ½7G8\nńßČõæøœ`s·Ļ“K7Ž»at¶×§kĒ^]7ŽģŪßń:y“ēÅ«›Žŗ{…7 ŠQęšs|ó;ŽoŁ~½­ż-džBÄĢ&Ń$»Å †@"TąK ž'įT÷qÄ L 7Ä@Ģ ōՉgz6Pp@SĻ g³mxĆ ū¼˜į@6.ć>#pŸŒ¦}–‰GNhdSE4`Bh 9"}Ź ±ORŽč䂙Hi•ŹÄ'†–tjI$ž v„ē‰4›Ÿū€Ų愨śy1©ŗj  ™ß>bŌŗaAL𦗠@°Ā…jģR1pØl‡Ģ*;*ƒĖFŪls¦­Hź>»±¹›‘īó(¶™¦Œ¶nĘh ‡»Tø†+Иļz*\³ōJm»ĒęėҰÄ(Óļæžü,¶0Ąt&”I| ¤Ģ‚;|_Ƙūnµ?šFLÆøŽ¶°@v\±@1 ‘)ƒPņ;qnbŹ,sĢėkóCK`OĪŃyC& b ±¹ļ]ńŽBƒ¬eŽ»œ+¹¾ėٜ7Ņi¢·žŚøßĖÕ|ó× ń\¼‰=W^ƒ­vAfä²DmĒ…öŚt‹7s„Ņ5¾wŻ|wt·EC×u߄kųą|ņ†xįŒ/vw~ēxć”×—·į—S7QŚ•{ųę™Ė=yē¤ėl]lƝŽśź¬·ī:룗.;ƒ¤s>»‘¶o—ūķ’ķ>ļ¼«|rĆÆ{ķĘß^üoĖ'O<ņĪ—Ž|mÓGO=ō‘”öśöܧ†oBtŚ÷…/žłč«F~yŲ?¤żłėcU}IŁ \’WĪÆYzö³G”åŸ ŻUņ×>śĶR¹_Ēvސ’Õ’86o„[/˜@ ‹‚Uq`å øĄŽlĢ'ś‰BŖˆr$d!G6ŌNÄ!€08B –0#¹R h5Аl|EüŒĆnć3ķn…ÉÄŪpęĮ…m)/l\ {¶5öiäEž¢÷$52‚k š:#Ōrƒ'V‘ ń‹\ ’0$ń†>DŠ@‡‘Ż N×āÉrźHBrd £S~G® PM±3]B„TĻØ©C“a3X¶…dR’”!±hדęō&¤L%f§6ĆIİI Č¶ŠŠRR“k’ÆFY”,2n‹d'+D •2!I¼’w“Ģ1qXe:¤ŻŽˆ©.zqŒKōT~Z†Å;j1zœāƒ ²Õ#ļKŸ'¹ÄQö&7t Vnn#%™6—-S§Ń'7²JŠ:JŠ‚ō %ĶBöX6ÖqģqĒĢēnDCNžĻĕ”¤’[JĢ–ŌœÄ}e­t)%Bę,œ¢®‰Iˆ› YŖŒ)Hˆā§]­T„XI;:ĮŹŌ8mZ:>jW'ė¦õ6øØ•R‘"±¼•’4yCvj‰Ė¬h9™Qނģųq*K‰Z§1ĢG.eŠūö”>µ"JéZÉź°’,’SõŹ\ė֜,ńń"Å4£NöT*C9¶4„0=§—śĆŠ~”YĮL ٧Ųu“‰ !c›=5ńŒ5ķą8‡™Yn¶°9ÜH\)›×Ø\¤£… kĮÖæD-¢®„¦7Ł©×Ó:µ3S¤Ŗlu‹YĆrŠ·e*€ŹÜŃŌg Ļm®t]ƒ\ĆA·ŗŲĶ®v·ĖŻīz÷»ą ÆxĒKŽņš÷¼čMÆz×ĖŽöŗ÷½šÆ|ēKßśŚ÷¾ųĶÆ~/;orafce-VERSION_4_14_4/doc/orafce_documentation/gif/SESSIONTIMEZONE.gif000066400000000000000000000033461501757153000251130ustar00rootroot00000000000000GIF89ac3p!łA,c3‡3f™Ģ’++3+f+™+Ģ+’UU3UfU™UĢU’€€3€f€™€Ģ€’ŖŖ3ŖfŖ™ŖĢŖ’ÕÕ3ÕfՙÕĢÕ’’’3’f’™’Ģ’’3333f3™3Ģ3’3+3+33+f3+™3+Ģ3+’3U3U33Uf3U™3UĢ3U’3€3€33€f3€™3€Ģ3€’3Ŗ3Ŗ33Ŗf3Ŗ™3ŖĢ3Ŗ’3Õ3Õ33Õf3ՙ3ÕĢ3Õ’3’3’33’f3’™3’Ģ3’’ff3fff™fĢf’f+f+3f+ff+™f+Ģf+’fUfU3fUffU™fUĢfU’f€f€3f€ff€™f€Ģf€’fŖfŖ3fŖffŖ™fŖĢfŖ’fÕfÕ3fÕffՙfÕĢfÕ’f’f’3f’ff’™f’Ģf’’™™3™f™™™Ģ™’™+™+3™+f™+™™+Ģ™+’™U™U3™Uf™U™™UĢ™U’™€™€3™€f™€™™€Ģ™€’™Ŗ™Ŗ3™Ŗf™Ŗ™™ŖĢ™Ŗ’™Õ™Õ3™Õf™Õ™™Õ̙Ւ™’™’3™’f™’™™’Ģ™’’ĢĢ3ĢfĢ™ĢĢĢ’Ģ+Ģ+3Ģ+fĢ+™Ģ+ĢĢ+’ĢUĢU3ĢUfĢU™ĢUĢĢU’̀̀3Ģ€fĢ€™Ģ€ĢĢ€’ĢŖĢŖ3ĢŖfĢŖ™ĢŖĢĢŖ’ĢÕĢÕ3ĢÕfĢՙĢÕĢĢÕ’Ģ’Ģ’3Ģ’fĢ’™Ģ’ĢĢ’’’’3’f’™’Ģ’’’+’+3’+f’+™’+Ģ’+’’U’U3’Uf’U™’UĢ’U’’€’€3’€f’€™’€Ģ’€’’Ŗ’Ŗ3’Ŗf’Ŗ™’ŖĢ’Ŗ’’Õ’Õ3’Õf’ՙ’ÕĢ’Õ’’’’’3’’f’’™’’Ģ’’’’÷ H° Įƒ*\Ȱ”Ƈ#JœH±¢Å‹3jÜȱ£Ē CŠI²¤É“(SŖ\ɲ„Ė—0cʜI³¦Ķ›8sźÜɳ§ĻŸ@ƒ J“ØŃ£H“*]Ź“©Ó§P£JJµŖÕ«X³jŻŹµ«×Æ`ÊK¶¬Ł³hÓŖ]Ėöc p欝K·n\ߌŻĖ7nŒ©ś Lø°įƈ+Ž‹w"€Cž¹mĶŹ1oŌüsFĻLA[v)za銧¦–,uõh”® ʆ8›`m‡·ƒę~r÷nÓ+¾XcœÄysō=™uĒߏn¼Õ™\¹Fę±?§(@¦}Õ{›’Ž;®2rm“G?0SÜļč᳿Aü¾zn Dټ²¹hä\ņygzs—’ve`fĮ)ō—sMĄƒöåTÄų×qč!zī“ɇ‘M2!x“ģó_e £‹ż'Ę@ÓĶxŠõģ£by-¾8ˆ:²Ä AʬH[„ er£D³¹'4j8A+|ēf"rŁaEf1+Š#{åķM bœWh"tC‹¦¹Ļ˜eöžEG„F‰R¢  E·‚‚U"§t)£A:äc'Fš ~ū ń݌œÖČįw™d²MNHŒ~Åpécš’źØJ}b’É$” żI+CŻÉ&u ½€‚õÉ¢¾{Ŗ‰‘IŒri›žŃķÓęÆąĶ5éJJ› 4‘5‹`z°ĪjP=7Pyė¹M‚ag Yø®léµaż§ ¦ ŁŪ诘:YP ÄĘÉ$^ b‹7zАiĄ‘ LäžØ-Vjp+40”‚1Dqv…*©,·H*9ɲJ¶ f••)ė¬¬¢1åŹ5‚lœ÷õw¦Ė8)®AٲKhAꢋdwˆj„j€Ępļ–€R+"zŹ\AĀ׵’J æ T©ŲWg=iŲ¤ż¼ėŠ Öj  }ż¤ŅŠ7ģ·ļįØ\Ę )K  ›YŽ™®,8]§Ī5”ÆōµžséjR¬ÉJŽ›ŚjtBĪ™čM[‡yŪłŽ,ōę9Č6B¹®]·čiÆ. ē—Æžä腮p(ą ĆžåĻēDr÷|™ļ±£Ž‘šØUänčĖ!ßóø²EŻń*żJŌĖ~åõ%mōŪ{\}󮟏łåĻń¼{a æ]”Ķo’żų篰ķ÷ļ’’  HĄš€L ČĄ:šŒ 'x–€;orafce-VERSION_4_14_4/doc/orafce_documentation/gif/SINH.gif000066400000000000000000000034561501757153000233600ustar00rootroot00000000000000GIF89aČ:p!łA,Č:‡3f™Ģ’++3+f+™+Ģ+’UU3UfU™UĢU’€€3€f€™€Ģ€’ŖŖ3ŖfŖ™ŖĢŖ’ÕÕ3ÕfՙÕĢÕ’’’3’f’™’Ģ’’3333f3™3Ģ3’3+3+33+f3+™3+Ģ3+’3U3U33Uf3U™3UĢ3U’3€3€33€f3€™3€Ģ3€’3Ŗ3Ŗ33Ŗf3Ŗ™3ŖĢ3Ŗ’3Õ3Õ33Õf3ՙ3ÕĢ3Õ’3’3’33’f3’™3’Ģ3’’ff3fff™fĢf’f+f+3f+ff+™f+Ģf+’fUfU3fUffU™fUĢfU’f€f€3f€ff€™f€Ģf€’fŖfŖ3fŖffŖ™fŖĢfŖ’fÕfÕ3fÕffՙfÕĢfÕ’f’f’3f’ff’™f’Ģf’’™™3™f™™™Ģ™’™+™+3™+f™+™™+Ģ™+’™U™U3™Uf™U™™UĢ™U’™€™€3™€f™€™™€Ģ™€’™Ŗ™Ŗ3™Ŗf™Ŗ™™ŖĢ™Ŗ’™Õ™Õ3™Õf™Õ™™Õ̙Ւ™’™’3™’f™’™™’Ģ™’’ĢĢ3ĢfĢ™ĢĢĢ’Ģ+Ģ+3Ģ+fĢ+™Ģ+ĢĢ+’ĢUĢU3ĢUfĢU™ĢUĢĢU’̀̀3Ģ€fĢ€™Ģ€ĢĢ€’ĢŖĢŖ3ĢŖfĢŖ™ĢŖĢĢŖ’ĢÕĢÕ3ĢÕfĢՙĢÕĢĢÕ’Ģ’Ģ’3Ģ’fĢ’™Ģ’ĢĢ’’’’3’f’™’Ģ’’’+’+3’+f’+™’+Ģ’+’’U’U3’Uf’U™’UĢ’U’’€’€3’€f’€™’€Ģ’€’’Ŗ’Ŗ3’Ŗf’Ŗ™’ŖĢ’Ŗ’’Õ’Õ3’Õf’ՙ’ÕĢ’Õ’’’’’3’’f’’™’’Ģ’’’’÷ H° Įƒ*\Ȱ”Ƈ#JœH±¢Å‹3jÜȱ£Ē CŠI²¤É“(SŖ\ɲ„Ė—0cʜI³¦Ķ›8sźÜɳ§ĻŸ@ƒ J“ØŃ£H“*]Ź“©Ó§P£JJµŖÕ«X³jŻŹµ«×Æ`ÊK¶¬Ł³hÓŖ]˶­Ū·p欝K·®Ż»xóźŻĖ·Æßæ€Ę@ø°įƈ+^Ģø±ćǐ Ē 88²åœ'V¾Ģ¹³ēĻ™/nžĢ9ōVmQOT}’uD×]aS”M’öUŪeq/Ōż‘wBßU3Ī‘ųSć±g§D>łńŒĪ/FWHĢ€ĻéX£c_­ģvß%†:XńµSwo½ŽkxōŃ£0i|‘÷”j_Ž>9ĘüĆe” b4wzÜ”“ŸwŠ©“21Ä  A’ö¦a*@&i^Aņ— B™ŌW\\½—PyV$ʆ…Ųn#P&1@Sj„Qø‡ŹČވ­ąŃ‚_©˜Š$hIŃ|M$äF4Rh#Ö–ö˜’‰ĮįŒ(t1„MŲå‡ūÄ0`7ō”’æ91^x B7˜Ę&jhpø#› Š˜Yg§x ixĆ>™4©LM†g“r˜ „{J·6žų2qŖYgOŗi˜ęØ94­&Ķ”eVŚ"£Mņč>“ø©@Ä4)„DÉäœ *ō«Ø Ķgānīv%›æņčå”Ź“I¶ŪjĖķ·’Ž¢‰Pu½q‹“Lž‹†ŗģ2‰jŗ¼ūˆ¹Ļ jā+¾?CŸ’+pĄ<ŲB‘ĪXpĮ_E£‘B$&¬¬$f¬ĮZĻ”’,rČ$ß0n~jäļ bœŪ2ŗźNR,Ģø Ž„6ļc@–åœóuŹdKŒŠD3“ŃE ä’ĻŖ¬ōÓŁ*“Iœ”64„ŹæŁ¦2†²¦ź>†zuzD^KfŁe6©­mNVńjMe² Ń;wCņ -Ŗj¬ß@=TųQˆZ¬õŻøDĢ®oWö+©QiÓ|’·7³ Čé©<ÉmTāi/śZXt”šŁ“Ķ·xŒŃ¦Eś@Ēr‘č9„^P=)ÓQ„¦š½īDĶ’ńŁłnŅt™¬°«š:?ņ·žĪ ę"ŗ@”f¾õ¦ßŽŗņ%…÷bÕŅ£}ų¬[Ÿ$łdc„§¾é7®ū¶?|½§Ł ø}żī»_­Ž7ĄäaOA™o'±:šŽ™ '¶š Zš‚#葪ęƒ ”GHĀšš„(L” WČĀŗš…0Œ” gHĆŚš†8Ģ”wČĆśš‡@ ¢‡HÄ"ńˆl ;orafce-VERSION_4_14_4/doc/orafce_documentation/gif/STRPOSB.gif000066400000000000000000000037411501757153000237500ustar00rootroot00000000000000GIF89a%6p!ł5,%6‡3f™Ģ’++3+f+™+Ģ+’UU3UfU™UĢU’€€3€f€™€Ģ€’ŖŖ3ŖfŖ™ŖĢŖ’ÕÕ3ÕfՙÕĢÕ’’’3’f’™’Ģ’’3333f3™3Ģ3’3+3+33+f3+™3+Ģ3+’3U3U33Uf3U™3UĢ3U’3€3€33€f3€™3€Ģ3€’3Ŗ3Ŗ33Ŗf3Ŗ™3ŖĢ3Ŗ’3Õ3Õ33Õf3ՙ3ÕĢ3Õ’3’3’33’f3’™3’Ģ3’’ff3fff™fĢf’f+f+3f+ff+™f+Ģf+’fUfU3fUffU™fUĢfU’f€f€3f€ff€™f€Ģf€’fŖfŖ3fŖffŖ™fŖĢfŖ’fÕfÕ3fÕffՙfÕĢfÕ’f’f’3f’ff’™f’Ģf’’™™3™f™™™Ģ™’™+™+3™+f™+™™+Ģ™+’™U™U3™Uf™U™™UĢ™U’™€™€3™€f™€™™€Ģ™€’™Ŗ™Ŗ3™Ŗf™Ŗ™™ŖĢ™Ŗ’™Õ™Õ3™Õf™Õ™™Õ̙Ւ™’™’3™’f™’™™’Ģ™’’ĢĢ3ĢfĢ™ĢĢĢ’Ģ+Ģ+3Ģ+fĢ+™Ģ+ĢĢ+’ĢUĢU3ĢUfĢU™ĢUĢĢU’̀̀3Ģ€fĢ€™Ģ€ĢĢ€’ĢŖĢŖ3ĢŖfĢŖ™ĢŖĢĢŖ’ĢÕĢÕ3ĢÕfĢՙĢÕĢĢÕ’Ģ’Ģ’3Ģ’fĢ’™Ģ’ĢĢ’’’’3’f’™’Ģ’’’+’+3’+f’+™’+Ģ’+’’U’U3’Uf’U™’UĢ’U’’€’€3’€f’€™’€Ģ’€’’Ŗ’Ŗ3’Ŗf’Ŗ™’ŖĢ’Ŗ’’Õ’Õ3’Õf’ՙ’ÕĢ’Õ’’’’’3’’f’’™’’Ģ’’’’÷ H° Įƒ*\Ȱ”Ƈ#JœH±¢Å‹3jÜȱ£Ē CŠI²¤É“(SŖ\ɲ„Ė—0cʜI³¦Ķ›8sźÜɳ§ĻŸ@ƒ J“ØŃ£H“*]Ź“©Ó§P£JJµŖÕ«X³jŻŹµ«×Æ`ÊK¶¬Ł³hÓŖ]˶­Ū·p欝K·®Ż»xóźŻĖ·Æßæ€ L˜e ˆ+^Ģø±ćǐ#KžÜŲÄƔ3°ģ³ęĻ C‹vĢY”ēѕžFĶŗuėŅ W»ć)±·ęīø›ao°æĻ8œ`ń¬Ē…L^”łUēʗė&ėŗDęÖ§fß·}ŗÓīQ·ƒo˜}|xßŅšo*>={Ü׫÷”ü„Ųƶ÷x’ ’±ž˜Ō~¼Ń§züŁw  8P 8H‘„FČQyŌ!Xą|ĄÅēF“€w/Q؜‡ :db…^Ø`‡ j 2Ü0Њ(ā—˜@70ĘŻb7*6¢@™$–‰q; “Ų‘ YxP&CęŲbC6"å‰/nˆDUD#b,Ęų`Eż‰1ѹ”Ü™DÖ&Į9P&µÉ)Š Źģ3‰›ÜM¢$šūйõē‡S¤ ŸRfŁ1ŒC—XrØ%BŁAŖØ”F ”“e"ʄy„’%Zŗ€’xcAœövƑæÅJŠ “$Ę”)ŖØ­6ŖŖpˆe b1,Ś’£’ųyTuˆ“f±ĒÖHĢ 7ąŚ%Ž%šęuAC²Ź©©Š žŗ›zÖ¹®”‹tščn'„—&z+©¾&$ʑ…īl »Ż0 L†9¬ŒŽōļ>\$ÆmVJŽÆĮŠÉ™Ī–{ŁlI&ō%§Æ™Xi‹”ymAæ™Ų”>6łYBõÜĶD3‹,ā@7ä9ÉØŗ8Łr’éå®ūˆŃ±ĖꌩĮ8†YĆ*YGć”vŹy5ӊFCĘW³ūp“ Ļ™īÅżžŹé %~Žu\Šw‚ĒŽqŽgTcŸ3Å&~dˆLdfā£H0©Ø‘Œ$ģIJJņ’ˆdd# ĆÉNz>ņ“  „(GIŹRšņ”ØL„*WÉŹVŗņ•°Œ„,gIĖZŚņ–øĢ„.wÉĖ^śņ—Ą ¦0‡IĢbó˜ČĢH@;orafce-VERSION_4_14_4/doc/orafce_documentation/gif/SUBSTR.gif000066400000000000000000000036751501757153000236440ustar00rootroot00000000000000GIF89aē>p!ł9,ē>…’’’3+3’’Ģ™+3™’’’’™3+™Ģ’’’ŖfUĢĢ€3f+™ĢŖf3™Õ’ĢŖ33€Ģ’Ŗ3+™™UfŖ’’Õf3ŖĢĢUf3U™ĢU33U3’ՙff33ĢÕĢĢŖĢ3ff€ĢĢUf™ŖĢfUf™Ŗ™f3™+Ģ’™™+ff€f™€™™U3’€3Ģ’ĢfÕ’Ģ€3U™3€’’Õ’3Uf’@€pH,Č¤rÉl:ŸŠØtJ­ZÆŲ¬vĖķz‰xL.›Ļć@3Œn»ßšø|N«æų¼~Ļļū’€‚ƒ„…D_ˆLІYŒŽ‘’“”•–—˜™[œHžš˜ ”¤„¦§Ø©Ŗ«£W®‡¬”°²µ¶·ø¹ŗ„“T½­»„æĮÄÅĘĒČÉBĆQæĢŹUĻŠÓŌÕÖ×zŅNĪŲ]ŚŻąįāćŌߋM®äKęķšńņó—ļJÜHōEöż ų*ŗ$ Y F!€ pš@Ü?‚3jÄxń¾#"0Į X pĮ‹cʜI³£‘F0T”"€‹„hĮ!8›4“*]Ŗ i¬sGŌHPfčvtĀdʵ«WYpKv¬Y±N‡8˶ģØūhą7d€v<}mĖ·¬Ų_ œ Dƈ+6œvŁāljGYPh ēOŠŃG÷hČ ƒhLø“é„ĆŽŠčÜģą—BØ Į/‰ŲC·¶¦>Ķ»·oŪ’”Ą*ēĢo¤+_Ž.5’&¢¹NŠœ¹õ먃{1.³:öļą9j÷6½ę”äįÓ«Æå|{łćē×˟t<ī1½ÓßĻY{ņPQ_˜Ė÷½×Ż€6č *©Õ1:Vhį…^Čąƒvh zāˆ$ Sb6'¦Øb –ŲāŠ0vųāˆ3Ęhc5z˜ć<Ī·#‡?ö($xA:X’äH.w¤K&éäiMå“T6%WÖĀF†\v‰ĘJlé„`N!ę˜h¢Yęgz¹fm¦)§œoB‘%}ßÄÉe¤Üi;śRΤ!ˆ=~ʧ_‚Ŗ$ ą=n˜ 3…ŚwØŽŖ·h'«dŹ) īI7 „‘B¢UŚ)©ž‚jL/•Š ©”Ų Ŗ©ZŖė#śgė§‚ŽJh©I“ꮹžŗ+ɅĄ'ÆĒĄJ¬ŖĀ.[‚Ö ›¬©»=ŗc”g,³ŹBģ¬ĆÖźź­˜n[ī»×nq‚(ƒ,¤ mt°Śž"Ё d¤ō¾³™“B°@šü’»’®!­J­“Ą„ézĖ-olDĘģ`@FIõ“ėīĒ—ČŲRį‚/ØÅbł AIž×sĄBtšĮ9…ræ’"ŻŁĪ0w[l/[Ü2ŻčŌ¬ZkDÕMĮõ0ųt’Į•h»ņMR ĆKÅe‚'ČšŌ“BXt^$­tĻBHōC–!ÕßJKĢ2ĢpnŚ‹QĮĄ,ÉEÕ}bmīÄDäė8ä Q Źr-ÜgChĮēüh.Ł€˜}öÜGåA×O[BX  }Æ“³ĘwŻ«żĶŁ+PtŅæĄ“įµ<ūām'H=›NQ*“zÜ|NŌ‹P|€V8DƒH8PrJr ‘m  ŒĮKļˆėÆ/Ć8(EOżõzt³²¹žŻ:Ó3 < u±ĆõŽGž,k˜«Ū> ē4#P…m`«Hü°g9ęN}Ą`؊@ų‰D*Ź#mx‚•”„*"1‘¬ź»”b|ĀĢ\’p=uÉ B{įö·±!ˆĄÜæ°@fÅ \óE†˜€ŠŲ„źŠĖ)ꐈ )”ŠD» ž €^1‹EpaĘAĢépŒ£ēHG4,amÅŃP!x„ō•nyX ¦7å L¤ņF@•}°_¼ßƒā¼¬ƒ¼šÖfųČT2płÉ\'Ä ¾ģŠieV.ƒOŗ‘†‘ Ål ?(€+¹Ūžöź’ƒ’¹!^÷°ĀBō²oC;ž‰ ĢĖ}"Ļ“ä#UĀȬDĄC9$7IĮgĮ՜6ā>ŚųqœśpY2×7•p²m~°t-hĄ:’n&!ąĄ ¼I·Ķ ¬‰4Ū 7_žS/¢ ŽÉI’!A+ŅŌeLʒŸ°‡ŪŒįrČϜ4Ä¢ ”(¼¶QEįėć¾čBQ£Ą3ž†Ą—9 …€‡ŗė'.¤•HŅŌž²įpŗéŠśĄ“°ĄhģŖ0³žŁlwтWPjƘ#{E€NC;z©£Źš”Œ(n‡Ė§źō<ŻeUƒU`M²Z^D¬“€‚|īS\¾zėV×ŗ‹¶ņQÆŹW•ęŗ›Īģƒź^ŗS¾FT°{€ģ“Ė…y!öŖŠ%*cŃźŲZN®qmŻYmwYb¤•Qš5mg*"£†*V“źŚbgk†E¼S“Ķķu[ éö·nxķüz+Üā÷øČM®re;orafce-VERSION_4_14_4/doc/orafce_documentation/gif/SUBSTRB.gif000066400000000000000000000054561501757153000237450ustar00rootroot00000000000000GIF89algp!ł:,lg‡3f™Ģ’++3+f+™+Ģ+’UU3UfU™UĢU’€€3€f€™€Ģ€’ŖŖ3ŖfŖ™ŖĢŖ’ÕÕ3ÕfՙÕĢÕ’’’3’f’™’Ģ’’3333f3™3Ģ3’3+3+33+f3+™3+Ģ3+’3U3U33Uf3U™3UĢ3U’3€3€33€f3€™3€Ģ3€’3Ŗ3Ŗ33Ŗf3Ŗ™3ŖĢ3Ŗ’3Õ3Õ33Õf3ՙ3ÕĢ3Õ’3’3’33’f3’™3’Ģ3’’ff3fff™fĢf’f+f+3f+ff+™f+Ģf+’fUfU3fUffU™fUĢfU’f€f€3f€ff€™f€Ģf€’fŖfŖ3fŖffŖ™fŖĢfŖ’fÕfÕ3fÕffՙfÕĢfÕ’f’f’3f’ff’™f’Ģf’’™™3™f™™™Ģ™’™+™+3™+f™+™™+Ģ™+’™U™U3™Uf™U™™UĢ™U’™€™€3™€f™€™™€Ģ™€’™Ŗ™Ŗ3™Ŗf™Ŗ™™ŖĢ™Ŗ’™Õ™Õ3™Õf™Õ™™Õ̙Ւ™’™’3™’f™’™™’Ģ™’’ĢĢ3ĢfĢ™ĢĢĢ’Ģ+Ģ+3Ģ+fĢ+™Ģ+ĢĢ+’ĢUĢU3ĢUfĢU™ĢUĢĢU’̀̀3Ģ€fĢ€™Ģ€ĢĢ€’ĢŖĢŖ3ĢŖfĢŖ™ĢŖĢĢŖ’ĢÕĢÕ3ĢÕfĢՙĢÕĢĢÕ’Ģ’Ģ’3Ģ’fĢ’™Ģ’ĢĢ’’’’3’f’™’Ģ’’’+’+3’+f’+™’+Ģ’+’’U’U3’Uf’U™’UĢ’U’’€’€3’€f’€™’€Ģ’€’’Ŗ’Ŗ3’Ŗf’Ŗ™’ŖĢ’Ŗ’’Õ’Õ3’Õf’ՙ’ÕĢ’Õ’’’’’3’’f’’™’’Ģ’’’©÷ H° Įƒ*\Ȱ”Ƈ#JœH±¢Å‹3jÜȱ£Ē CŠI²¤É“(SŖ\ɲ„Ė—0cʜI³¦Ķ›8sźÜɳ§ĻŸ@ƒ J“ØŃ£H“*]Ź“©Ó§P£JJµŖÕ«X³jŻŹµ«×Æ`ÊK¶¬Ł³hÓŖ]˶­Ū·p欝K·®Ż»xóźŻĖ·Æßæ€ Lø°įƈ+^Ģø±ćǐ#KžL¹²|å˘3kŽĢ¹³ēĻ C‹Mŗ“éÓØS«^Ķŗµė×°cĖžM»¶ķŪøsėŽĶ»·ļߥƒ €ńćȓ+_Ī<ĘBĢ£KŸN½ŗõėŲ;ν{_$Į+ߖ¼÷óčåš¹Ž`ū“ļÓ˟_6>Gūń×§Ļæ’Xżéą’žh V^$ą[ 蹃C5XтnIį…ādįD"$†2f(āˆ>m(Q‡)sY&’čā‹#µŠ)³]&Ę­(Š ÄbU2Ā(äéeŅČ>“l1ū(ĄŠ™Lb•‘Df©eCX2„ä@hd²?ŖČ¤Ž™lGU—[¶éf~į-d_ ŹH‰ÜŠh@¹błęŸ€$†œqއP=+*³‚A‹ D畁F č”1ÜPé„–ŽĄęx˜vji|™ ŗ JY§Žf^ééŖ™²*é«ü@ 1ŹĢZ+­“ā×%™·öj+Øhd§x6 «ęšuŚŖ,®Ģśš+¬Ц÷%˜Z”‚ŃfŪŻ“YY¤µåa|«ķøĄq»‘¹ūY“)¹ģІnµ†^«n»ōęöī·ń†;o½üŅvÆø ­;•‘÷k0e’ī0ƒģ°j O.[?lqjf§±qrnģńĒ ‡¼\Ć—ZĮ¦”lņŹ‚©LšĖ,ĒĢĢīŹlsf4Ÿ|óĪ•å šĻ<M1w@ mōYEw–ōŃL‡µōfO7-õVQć<õՁU™ÖXw זķõŲJ‰0Łh×eödk§ķöOmG÷Ūtē4÷cwĆ'ņŽ|÷Ķ7‡~3Qą„žńŒ†'wdāŒ7~Ey7Ö¢ć³ų—‰4[yMꜱę;MN4䅆ų‡1®ļ‘„O —čĆĮ.č+ŃNę©Ļø:—­ē—ģĮĻ’^ŗ§Ÿ˜ūC¶ĒŌyļ Ļ%üoĻ{äs&ņ”¼PøĻ®śŠČ3Šõ6Eߛų÷¤bq%^ŽŗöŗsĻśń®3¼¾päŸ+’¦P^>Pه¤łī^ņŽAöG“śéʀšņą­1„o<Ē–y¤„äōiL܇¦h(G‚ȹ`čęw*‘,€‚ŚĒ>:D… ÕµÓā†|©:!FpCöDW}Jœ"óiLA4"““#žh„ĘKȱHĒB†PjUļrE…Ų{zā Dˆަ~“–+¢ØGD Qė4AštQƒł#ˆ»xG Ž‘G?$’aAų„ÆīĢ8™Ø‡qųt1Pa[laüˆˆHE`PŽĄvˆń)ćÄ Ē”p¤É‡ŒPŒ"żØ˜źI,#62€žÜó@µg=E("†)šr‰¢÷ØZf˜klŽAҧ0ķ£GOō“!%黂0ӁΠ/ƒ…#93‡ÄŃ6™¤Ęż™Ń6t&$+²@T"3•V©źXADž÷$ϰŒÓØ}–2Ŗ¬‘Ž’ł½„ਁŚŌx•åĮƚIbą@J4XÉ¢¼Ń$7¦2-ź ŲcešDZĀt"Žl 2!"†V¹”U0}©L/Õ Y sˆę£{’f €zü²‚O4O ܾ˜Ā4>r,R-ŗŠ„:µ© \ČA$QfPeŖVŸź¹§n5™Ø•~¦:&ŸĪ‘x"EB 5K d…­21×ŗ*ƒ®wµ+šJ׾ï€ż«`KŲĮ¶°ˆ5l4gFRƒƒ”EÜb :‘°.ĖY˜½¬f›e«;Ö(”bZĮ‹uGQfb {źɳQ Vt–:!Óf3ū¬ƒäP]LM£nsĖ[P‰*Å|+VČŪŻ7Ŗ1*nnY)ßv ÅģŃ@D« Q½µ=ĀC˜n¤Rėe껕ļ ĄŪŅļ–·‘ćEļxĻĖŽō¶w½ī/|ē«°Žś¶”rųĶ/å¢Mu,½$ź;c;ž > jāB9 BŖ}¬ĄĄA}§„†(Yt{Ląū+‹«æĆ=¦ō6\é*tœŒŅv¢śÖźī¾ō ”üŲa“ųUc0‰)¢(@®ōʇō˜Žć-ņō8£Õ'.'įOP!$A3Œ&ź’&¼Ŗˆ][ČIĀ5GŌ INōˆN6ÖDĮĢ?XéĒ•‘ČF!ūĻFcī„ńåI]؇VYĆ•—¤š“ :CŁ" “1ż‚gƒ€8Ī?F‹ŸKčH :Röī:1‚Ø½ÖłĀŒŻsGžē¾HśoĒņ“/b£'żŌzźuł¶Lp!ł5, >‡3f™Ģ’++3+f+™+Ģ+’UU3UfU™UĢU’€€3€f€™€Ģ€’ŖŖ3ŖfŖ™ŖĢŖ’ÕÕ3ÕfՙÕĢÕ’’’3’f’™’Ģ’’3333f3™3Ģ3’3+3+33+f3+™3+Ģ3+’3U3U33Uf3U™3UĢ3U’3€3€33€f3€™3€Ģ3€’3Ŗ3Ŗ33Ŗf3Ŗ™3ŖĢ3Ŗ’3Õ3Õ33Õf3ՙ3ÕĢ3Õ’3’3’33’f3’™3’Ģ3’’ff3fff™fĢf’f+f+3f+ff+™f+Ģf+’fUfU3fUffU™fUĢfU’f€f€3f€ff€™f€Ģf€’fŖfŖ3fŖffŖ™fŖĢfŖ’fÕfÕ3fÕffՙfÕĢfÕ’f’f’3f’ff’™f’Ģf’’™™3™f™™™Ģ™’™+™+3™+f™+™™+Ģ™+’™U™U3™Uf™U™™UĢ™U’™€™€3™€f™€™™€Ģ™€’™Ŗ™Ŗ3™Ŗf™Ŗ™™ŖĢ™Ŗ’™Õ™Õ3™Õf™Õ™™Õ̙Ւ™’™’3™’f™’™™’Ģ™’’ĢĢ3ĢfĢ™ĢĢĢ’Ģ+Ģ+3Ģ+fĢ+™Ģ+ĢĢ+’ĢUĢU3ĢUfĢU™ĢUĢĢU’̀̀3Ģ€fĢ€™Ģ€ĢĢ€’ĢŖĢŖ3ĢŖfĢŖ™ĢŖĢĢŖ’ĢÕĢÕ3ĢÕfĢՙĢÕĢĢÕ’Ģ’Ģ’3Ģ’fĢ’™Ģ’ĢĢ’’’’3’f’™’Ģ’’’+’+3’+f’+™’+Ģ’+’’U’U3’Uf’U™’UĢ’U’’€’€3’€f’€™’€Ģ’€’’Ŗ’Ŗ3’Ŗf’Ŗ™’ŖĢ’Ŗ’’Õ’Õ3’Õf’ՙ’ÕĢ’Õ’’’’’3’’f’’™’’Ģ’’’’÷ H° Įƒ*\Ȱ”Ƈ#JœH±¢Å‹3jÜȱ£Ē CŠI²¤É“(SŖ\ɲ„Ė—0cʜI³¦Ķ›8sźÜɳ§ĻŸ@ƒ J“ØŃ£H“*]Ź“©Ó§P£JJµŖÕ«X³jŻŹµ«×Æ`ÊK¶,ÓŅŖ]˶­Ū·p欝K®Šhėźpwb޽tc@@–šDĆGT¼‘ńRĒ^!7”|‘ņBĖ1Ռ•óAĻ‹)‚†8hé©§¦føzõåĮ…El=ū"±¾5]?„ķ‘wāŠŹn ½©Ū©oŽĒS Ó¾ā 1Æ(ęĘĄźŖÕdėœą eo“’}Ī<Éä3”‘ˆž ąĆ'XƚøBÄf¬ xe+ؖß>ūķÓAų ¤}Ų tšEˆ2ļ…&įA™ˆq!C™ 4Ś—bžķ3‰uhŠ§Ų Ī1V”DāJķ „Ę€²·n¤9ÜwAŲ›BĀÄ¢†ÅPįƒ2ž'˜Żˆ˜ƒ)Õ(P€>„™8jŁsQŹ(bBż„eĶTf‰ĻtxźķSuŪ!ȖIVĪ ¢ŽYgŽÉĒągżŲx õg•)Zc%:•ŒžtčtxŲ„i-4É$ģĶÅŚ˜Åx]”SŅI]&Š(㜧֤)k•²%“d}ō'®2w&”6Y–`’‹"öh”1(ó(‚ĪeepLFKk®õQūšBPņ©1ŽHźgjż @=vš™ZŻŻ:ģøŪqW’•ūd«- FZK|HŠllÖBs«CšīŹė—i†øļXš˜Æ—Öž pDsYmnüĪ«œ½µFŌ!’Bž†pĘȁ|ńD‚vņǧ ¬Ē1÷ķW ‹Ģ0ĖĄQ½™ĢŬ²PœöģóĻ{‰ō[BØYH'­ōŅL7ķōÓPG-õŌTWmõÕXg­õÖ\wķõ×`‡-öŲd—möŁh§­öŚl·ķöŪpĒ-wR;orafce-VERSION_4_14_4/doc/orafce_documentation/gif/TANH.gif000066400000000000000000000035621501757153000233470ustar00rootroot00000000000000GIF89aÕPp!łB,ÕP‡3f™Ģ’++3+f+™+Ģ+’UU3UfU™UĢU’€€3€f€™€Ģ€’ŖŖ3ŖfŖ™ŖĢŖ’ÕÕ3ÕfՙÕĢÕ’’’3’f’™’Ģ’’3333f3™3Ģ3’3+3+33+f3+™3+Ģ3+’3U3U33Uf3U™3UĢ3U’3€3€33€f3€™3€Ģ3€’3Ŗ3Ŗ33Ŗf3Ŗ™3ŖĢ3Ŗ’3Õ3Õ33Õf3ՙ3ÕĢ3Õ’3’3’33’f3’™3’Ģ3’’ff3fff™fĢf’f+f+3f+ff+™f+Ģf+’fUfU3fUffU™fUĢfU’f€f€3f€ff€™f€Ģf€’fŖfŖ3fŖffŖ™fŖĢfŖ’fÕfÕ3fÕffՙfÕĢfÕ’f’f’3f’ff’™f’Ģf’’™™3™f™™™Ģ™’™+™+3™+f™+™™+Ģ™+’™U™U3™Uf™U™™UĢ™U’™€™€3™€f™€™™€Ģ™€’™Ŗ™Ŗ3™Ŗf™Ŗ™™ŖĢ™Ŗ’™Õ™Õ3™Õf™Õ™™Õ̙Ւ™’™’3™’f™’™™’Ģ™’’ĢĢ3ĢfĢ™ĢĢĢ’Ģ+Ģ+3Ģ+fĢ+™Ģ+ĢĢ+’ĢUĢU3ĢUfĢU™ĢUĢĢU’̀̀3Ģ€fĢ€™Ģ€ĢĢ€’ĢŖĢŖ3ĢŖfĢŖ™ĢŖĢĢŖ’ĢÕĢÕ3ĢÕfĢՙĢÕĢĢÕ’Ģ’Ģ’3Ģ’fĢ’™Ģ’ĢĢ’’’’3’f’™’Ģ’’’+’+3’+f’+™’+Ģ’+’’U’U3’Uf’U™’UĢ’U’’€’€3’€f’€™’€Ģ’€’’Ŗ’Ŗ3’Ŗf’Ŗ™’ŖĢ’Ŗ’’Õ’Õ3’Õf’ՙ’ÕĢ’Õ’’’’’3’’f’’™’’Ģ’’’¬÷ H° Įƒ*\Ȱ”Ƈ#JœH±¢Å‹3jÜȱ£Ē CŠI²¤É“(SŖ\ɲ„Ė—0cʜI³¦Ķ›8sźÜɳ§ĻŸ@ƒ J“ØŃ£H“*]Ź“©Ó§P£JJµŖÕ«X³jŻŹµ«×Æ`ÊK¶¬Ł³hÓŖ]˶­Ū·p欝K·®Ż»xóźŻĖ·Æßæ€ Lø°įƈ+^Ģø±ćǐ#KžL¹²å˘’3kŽĢ¹³ēĻ COŽ “éÓØS«^Ķŗµė×°c§60‘“ģŪ­i×ĘĶ»·ļߦuc“ œwŒ³Ž&—øeóˆĻ½FÆ8du°×‘OĢ’»BļWĮ;ߑ|VóŲ·«DO}T÷į_”?•¾Vųö)ŹĻæ”æ@’ŠyDŒpDX~ėé'€>Ō 27¬ŠąJJ…`Jū-ØQ… 8 “ģĆ”sŹ©‡”‚a1˜ F™ Ę@#žtŻ ©ĮØ Œ™“÷_A1ŹhbB™ QŠée”Żqå§L 1ÜćQÜ)1h„ø”ĶIyåsZBłćAKz”aŠł¢˜ј#^~WŠ’ a d1HŠø£Žm˜Ä ł„A7Sš“Ķ-C‹@XšP*&DąFņ}h„A=–%—/Š‘£–šnéé@]u!B+$I¤A‚ްO&!*s&„«Ę d‹9T£‰ŃēeƒŖ UjŻBĻeņ"¬vī,õˆXcžeWĻ Šųɜ™łŗŖW6²gŠaå$gž„ėA¶ņźŠ“‡ ­A”īC\r]N‚F=ōr)ģ°×"¤­µzħ@vŗO§M §ĀNš[fB“L éCb€Ųо"y×Ü“uڜ¦ĖE‡qʙ£LÉ'›ŒņŹ& ŖP%Z²½U¢QóĶ4Ū›]śs+ÜXź>?)ŠĻ@pĆÆH­tŅL/}4wéĘģtÓæ–Vn‡Wg4oq±)j&kīCĢ ų‚ŗh¼ńxƒŅl’ŚöŚU»)¦ŪUŠkļŻuG\óuČĀēŃWėŖ@t2ŚņįŹƒøā‰/n2wĒÜrā”Onl¢¾Ké@0ļ³B‹ž,ŒĶŠśgA‘O|ŗ@q"K#ˆŖ¶ŽdŌ©Ń1;“dĀjžÖØAÓ¹ķ«ounA“«īP‹ÜŹ]ŌČHn֍Ydõ ’0DK¼¹énIoé©Ņmļ£DĀóžżó%öKbń÷™o}‚j½©įĆßł]?¾Eh°ž“Ų—?÷Ļ€å#Žū.R±°Ż`kæŲ?łż#t"Ūč Ō¾€Ѓ ÄŽ‰6¼–‡k(L” [³ŹF?.Œ” Y³”ŗĘ#Ó°śš‡@ ¢‡HÄ"ńˆHL¢—ČÄ&:ń‰PŒ¢§HÅ*ZńŠXĢ¢·ČÅ.zń‹` £ĒHĘ2šńŒhL£×ČĘ6ŗńpŒ£ēHĒ:ŚńŽxüK@;orafce-VERSION_4_14_4/doc/orafce_documentation/gif/TO_CHAR.gif000066400000000000000000000050301501757153000237240ustar00rootroot00000000000000GIF89a p!ł<, ‡3f™Ģ’++3+f+™+Ģ+’UU3UfU™UĢU’€€3€f€™€Ģ€’ŖŖ3ŖfŖ™ŖĢŖ’ÕÕ3ÕfՙÕĢÕ’’’3’f’™’Ģ’’3333f3™3Ģ3’3+3+33+f3+™3+Ģ3+’3U3U33Uf3U™3UĢ3U’3€3€33€f3€™3€Ģ3€’3Ŗ3Ŗ33Ŗf3Ŗ™3ŖĢ3Ŗ’3Õ3Õ33Õf3ՙ3ÕĢ3Õ’3’3’33’f3’™3’Ģ3’’ff3fff™fĢf’f+f+3f+ff+™f+Ģf+’fUfU3fUffU™fUĢfU’f€f€3f€ff€™f€Ģf€’fŖfŖ3fŖffŖ™fŖĢfŖ’fÕfÕ3fÕffՙfÕĢfÕ’f’f’3f’ff’™f’Ģf’’™™3™f™™™Ģ™’™+™+3™+f™+™™+Ģ™+’™U™U3™Uf™U™™UĢ™U’™€™€3™€f™€™™€Ģ™€’™Ŗ™Ŗ3™Ŗf™Ŗ™™ŖĢ™Ŗ’™Õ™Õ3™Õf™Õ™™Õ̙Ւ™’™’3™’f™’™™’Ģ™’’ĢĢ3ĢfĢ™ĢĢĢ’Ģ+Ģ+3Ģ+fĢ+™Ģ+ĢĢ+’ĢUĢU3ĢUfĢU™ĢUĢĢU’̀̀3Ģ€fĢ€™Ģ€ĢĢ€’ĢŖĢŖ3ĢŖfĢŖ™ĢŖĢĢŖ’ĢÕĢÕ3ĢÕfĢՙĢÕĢĢÕ’Ģ’Ģ’3Ģ’fĢ’™Ģ’ĢĢ’’’’3’f’™’Ģ’’’+’+3’+f’+™’+Ģ’+’’U’U3’Uf’U™’UĢ’U’’€’€3’€f’€™’€Ģ’€’’Ŗ’Ŗ3’Ŗf’Ŗ™’ŖĢ’Ŗ’’Õ’Õ3’Õf’ՙ’ÕĢ’Õ’’’’’3’’f’’™’’Ģ’’’«÷ H° Įƒ*\Ȱ”Ƈ#JœH±¢Å‹3jÜȱ£Ē CŠI²¤É“(SŖ\ɲ„Ė—0cʜI³¦Ķ›8sźÜɳ§ĻŸ@ƒ J“ØŃ£H“*]Ź“©Ó§P£JJµŖÕ«X³jŻŹµ«×Æ`ÊK¶¬Ł³hÓŖ]˶­Ū·p欝K·®Ż»xóźŻĖ·Æßæ€ Lø°įƈ+^Ģø±ćǐ#KžL¹²åĖä˜3kŽĢ¹³ēĻ C‹Mŗ“éÓØSی µė×°cĖžM»¶ķŪøkĒPĶ»÷EeūN¼”š±Ē‹+_.0yXēĢ£÷†ž•ŗō릭wՎ½;hī[Į{ÆY|VóäÓSF•½ś÷ŽĮ‹ÉŌZYóĄ•Ż @k÷4߀ˆqG 7ģ“É$ūŌ“`ƒ ƒ ‰‚h % Ę]&f²[&*Č ī#ƒ*²Ō†ĘčwbŲ§ā…ó 4Ʌ1Ųxƒ6¾(ćtåv›B» Ōć>IīÓ“­%QFVi%l)±©eN0¤4Iś·˜ūܰ˜é'ˆTŅ”å–pˆ‘vÄ<Ø&“­M²[i&Ib›3uē  zY†v”(”Œž6gpr6*©J‰.Ź”„a:é¦ U i œ†:’§ˆF*ꩊ>Z*ØØ¶š©ŖČ™źź¬‘+«“ęQ„WöźėÆĄ¶&«®Ä.¤éeĒĖh²•1«lœĪNķ³ZN™µŌʈķcŪfĖa·ė-|ā.V„īøé›˜ŗčzĒīaļ¶{]¼…Ń+/sözxļ³ł Öļ¾Ćż ˜ĄóFšŒ{p_ 'œ¾ēŚš^G,ZÅyalńgßÕ1d+ņČ$—ģėH!›l„°Ē«ŹWö±TÖĘk«Ė-Æ4sQ;CU³K74„ (VĻOżÜŅŠ¾1R²ś…|4dJ³ä“Į9Ķ0ˆ4H_7UµĪY7]öÓ˜’eŲ…R=*Šgcķ(Ü9h1^N}Š °IYak*¤Œk~;YPrOŽ[Tc”É›mĻ­ÜÕP¾}×.ā§wBɱŁ\ęŃ7,Néi®Øł@ž;Õ8AZnŪnQ¾ ģų A“sÄ]=ˆĪyūpq”sĒżø;ņ>ć^‡DyjÓæī~1ąPļqĶq“ßAį4x=Mƒ»åˆŗŽMŠķ|ŽóKÄżZÓē(żD˜»łö¹Ó@ōWnqū˜D†Ä¼×ÄO~"±Ž2 ÷‘é”fz·ŪDŌfœ’D}}*ˆńR®?čć›köń½4%.iõ’Sį48;ˆI!¢!C°=’•ä?03™ą’3Ć÷ÄċA&ŒŲB2ķzĄcŻż¶DŲ Ä€`¾“ؐĒE°J ó!XĄō­é8]Kˆč"†$%'Š™ˆŸ’c¦ęE0!+ ^㦚üõ0rĘŠłhøÓ¹ę9PkXv(ĶAnkÄO‰ ØĆ‚l„¼ !M˜Ŗ†˜Ib¬ŽŪŻaņ†Bćc+ŁEPsœˆl@©ė D¤¬įr®ęDV.D źąsFéĖ“Xš4ĒĢåCĄ“$… •ꊔI’YjžR"ōyå EÉ-i–Äš£' 'LD6’›ńń&I*Ävśī"ži&żĘHĢk’ šfĆ'Ś0BS’žŻT¦Öt9¹LŖ"åÜt¦WŖČІ:ōH_|hm ś°ßHŌ6‰§}ž¹1ģ,ŁähGķ™J“s¤lé§ŠBK”®Ŗ . •J_ÓIĶōV5µ© s*©›Ę’§ŠŚ)P åÓauYB=*œŠ P„u—NSŃÕj%µŖŚŗ*V;4Յ¢nÕŖPżźŗŗ±ŽU«f}Y¹²Ö“¦­n%O[µ2×ø¢%Q)»Ø^÷ŠFŹŅ®r'\ŗTWĄ®“"…Żē_ «VŠŚ…°Œm¬>łŁČ¦Ė±u©¬eĒ#Ų·hv³Żélķ ZĪ:zńēawUZw96QĘ ĶņŁÖFgz\³p€ €Ż AS­Wke[ģŲĪo1`™U”!4ą-~»$UY™[\éh"ÜIœ ‡Ė9i} ŗ.]I[ŻčØ0X q¢2Ä[ĄN‘®.[ÅÉņžõŠMŚļ„^ŅŌ¾ K¦Œņqm|r’}×Ņš˜_­te’x{RŻ!x…’}0­kL ‹ĆÓōp€õ%b‰É¬Ä&&1Š]āo®xV-^ē‹YĢ×ŪX63αŽwĢćūųĒ@²/‡Lä"łČHN²’—Ģä&;łÉP޲”§Lå*[łŹXβ–·Ģå.{łĖ`³˜ļ;orafce-VERSION_4_14_4/doc/orafce_documentation/gif/TO_DATE.gif000066400000000000000000000045401501757153000237310ustar00rootroot00000000000000GIF89aÜjp!łA,Üj‡3f™Ģ’++3+f+™+Ģ+’UU3UfU™UĢU’€€3€f€™€Ģ€’ŖŖ3ŖfŖ™ŖĢŖ’ÕÕ3ÕfՙÕĢÕ’’’3’f’™’Ģ’’3333f3™3Ģ3’3+3+33+f3+™3+Ģ3+’3U3U33Uf3U™3UĢ3U’3€3€33€f3€™3€Ģ3€’3Ŗ3Ŗ33Ŗf3Ŗ™3ŖĢ3Ŗ’3Õ3Õ33Õf3ՙ3ÕĢ3Õ’3’3’33’f3’™3’Ģ3’’ff3fff™fĢf’f+f+3f+ff+™f+Ģf+’fUfU3fUffU™fUĢfU’f€f€3f€ff€™f€Ģf€’fŖfŖ3fŖffŖ™fŖĢfŖ’fÕfÕ3fÕffՙfÕĢfÕ’f’f’3f’ff’™f’Ģf’’™™3™f™™™Ģ™’™+™+3™+f™+™™+Ģ™+’™U™U3™Uf™U™™UĢ™U’™€™€3™€f™€™™€Ģ™€’™Ŗ™Ŗ3™Ŗf™Ŗ™™ŖĢ™Ŗ’™Õ™Õ3™Õf™Õ™™Õ̙Ւ™’™’3™’f™’™™’Ģ™’’ĢĢ3ĢfĢ™ĢĢĢ’Ģ+Ģ+3Ģ+fĢ+™Ģ+ĢĢ+’ĢUĢU3ĢUfĢU™ĢUĢĢU’̀̀3Ģ€fĢ€™Ģ€ĢĢ€’ĢŖĢŖ3ĢŖfĢŖ™ĢŖĢĢŖ’ĢÕĢÕ3ĢÕfĢՙĢÕĢĢÕ’Ģ’Ģ’3Ģ’fĢ’™Ģ’ĢĢ’’’’3’f’™’Ģ’’’+’+3’+f’+™’+Ģ’+’’U’U3’Uf’U™’UĢ’U’’€’€3’€f’€™’€Ģ’€’’Ŗ’Ŗ3’Ŗf’Ŗ™’ŖĢ’Ŗ’’Õ’Õ3’Õf’ՙ’ÕĢ’Õ’’’’’3’’f’’™’’Ģ’’’¬÷ H° Įƒ*\Ȱ”Ƈ#JœH±¢Å‹3jÜȱ£Ē CŠI²¤É“(SŖ\ɲ„Ė—0cʜI³¦Ķ›8sźÜɳ§ĻŸ@ƒ J“ØŃ£H“*]Ź“©Ó§P£JJµŖÕ«X³jŻŹµ«×Æ`ÊK¶¬Ł³hÓŖ]˶­Ū·p欝K·®Ż»xóźŻĖ·Æßæ€ Lø°įƈ+^Ģø±ćǐ#KžL¹²å˘Ó3kŽĢ¹³ēĻ C‹Mŗ“éÓØS«^Ķŗt °cĖžM»¶m1¾¾Ķ»·ļߥƒ N\vīÖȓ7P’¹C犔+ŸN] ō×f7¼½ŗwÕŻ;†78^płļčEŸĻøŽ:ćöéćo†o>}¾÷å맜¢ż÷ūZż·&˜‚˜ܰ„q1Øą…ƒYųÜCå­Ą2Vˆįˆ•iø‡ )›21d17Ą¶ŠŠHā™Čƒe2Ɍ1 ±‹™ )Ę>h#—Ž’869“Ś”ų`‘h׈ūˆńć JŚčä—wÅĆ c–Ię™eB™nh¶ięk Å L–sīsCbĢy\…nöłf›j‚)(P(CŒ”ˆŖ(¢Th¢*zhxõP]ˆū0Ēā“‹vé§Ä4:čØ:ńˆ”mŗĻqŹPø©Ŗ^R$*©“ÖdjA:Ž:ūĆźq“©"…pY8k­Č¤ė@G²‡ź‚›ģ“+-+P‘Īnx`“Ōv›”µk·Ž–K”ø” ˜±ę¶”ŗĮė»īÖĖ“¼õ=‹½öö{¾¼æž,“Ąžé{Į7ܒ}ÅĒaÄWlńÅÓF®ĆWŪ±£‡|’“N’Œ,²Č&ć˜ņÉÆL¢Ė,7 3†3ĒģoĶ āls½: ŲóĪęž¼ŸŠ@wK“|GlŅé1­4­NõӃN]ÕT‰õt[g­²Ķ]{ż2Ų©ķ–ńŁh§ Ūž™­vll3äöŪt×ķ[Ü“]ŃÜoć}VŲ6ŻG2}€Ļ”«Ž²’TųK‹Ńą ›.ā ’ŌųĆK>®xäo3ƒ“ä¢Q—Ē$ųę «å9Ė £R«+”NģŒkn9ēn­~rė·‡į“»뉽k›ūäŸē[|G.6›)é™ć~jźi鎲ņ" M +Ō)ü¹ Åhܵ±a›źlę $§@āĆM£lŽ+k;B™`‰=ń9æ•õ!óސßźˆš#\Ao!ŅÉĞø¦Ł™ObŠßó‚µÓ%€óĆ_CTäž}Ģ=*ąż.Ņ<„o‚ ©‡t®žėģéNÄŚ‡ g— D éĖõ(›LØ0B0SV<Ų²’'^aQ”X”ņ@ŠˆÆ rƒ „ƒ’éöŃó=1Š3Ŗ` ˜-毰€ĢAC‘\F¬‘c ¼”Ē8‘Ī‘†M\Č ÆĆ,Żń:w2ҌˆµĒ0ŹS¦£ć%ØC3DEö[Ÿ–ö‡<Ö± õŪŲD&F‚,#|³›lv4)„ s|b=%µ«“N,Q8ā ĔńC ¤'äi¢ ¦0‡IĢbSb ™„ee1SÕGFƒ2Œ3āĀ@ŌHĮ\ÓVŠÜĒö*©AL'G:ŽørĀr•'“—„ˆÆbŠF0J»‚ģGž6`dtžXĆpīcõld9 ‚E-m —C[lJʃCMV„“žģf„yPõ0EčóeAÖ7Ķ÷•ĻqŅ+–©PR&d€5Æ()ё-ƒ;”ˆķ¹QÉ„” •*ćBUWS›&H܈YĶ”˜Ø6ĻdŠ ¬¤:r-ķōVx`O‹p’Ÿ“‰JVU2UΧEuŻō<²Óļ95z9%§K—VµšõubšÓ Ē:Qƒn䬝««]?"-A螁ż©GKWĮ®õ±! b{ÕÅ*¶zŽĶŽ`AUBó³j{œ0ŚŅ^,³Ų-jWĖŚÖŗöµ°­lgKŪŚŚö¶øĶ­nwĖŪŽśö·Ą ®p‡K&Üā÷øČM®r—ĖÜę:÷¹Š®t§KŻźZ÷ŗŲĶ®v·ĖŻīĀ6 ;orafce-VERSION_4_14_4/doc/orafce_documentation/gif/TO_MULTI_BYTE.gif000066400000000000000000000034701501757153000247320ustar00rootroot00000000000000GIF89a×5p!łB,×5‡3f™Ģ’++3+f+™+Ģ+’UU3UfU™UĢU’€€3€f€™€Ģ€’ŖŖ3ŖfŖ™ŖĢŖ’ÕÕ3ÕfՙÕĢÕ’’’3’f’™’Ģ’’3333f3™3Ģ3’3+3+33+f3+™3+Ģ3+’3U3U33Uf3U™3UĢ3U’3€3€33€f3€™3€Ģ3€’3Ŗ3Ŗ33Ŗf3Ŗ™3ŖĢ3Ŗ’3Õ3Õ33Õf3ՙ3ÕĢ3Õ’3’3’33’f3’™3’Ģ3’’ff3fff™fĢf’f+f+3f+ff+™f+Ģf+’fUfU3fUffU™fUĢfU’f€f€3f€ff€™f€Ģf€’fŖfŖ3fŖffŖ™fŖĢfŖ’fÕfÕ3fÕffՙfÕĢfÕ’f’f’3f’ff’™f’Ģf’’™™3™f™™™Ģ™’™+™+3™+f™+™™+Ģ™+’™U™U3™Uf™U™™UĢ™U’™€™€3™€f™€™™€Ģ™€’™Ŗ™Ŗ3™Ŗf™Ŗ™™ŖĢ™Ŗ’™Õ™Õ3™Õf™Õ™™Õ̙Ւ™’™’3™’f™’™™’Ģ™’’ĢĢ3ĢfĢ™ĢĢĢ’Ģ+Ģ+3Ģ+fĢ+™Ģ+ĢĢ+’ĢUĢU3ĢUfĢU™ĢUĢĢU’̀̀3Ģ€fĢ€™Ģ€ĢĢ€’ĢŖĢŖ3ĢŖfĢŖ™ĢŖĢĢŖ’ĢÕĢÕ3ĢÕfĢՙĢÕĢĢÕ’Ģ’Ģ’3Ģ’fĢ’™Ģ’ĢĢ’’’’3’f’™’Ģ’’’+’+3’+f’+™’+Ģ’+’’U’U3’Uf’U™’UĢ’U’’€’€3’€f’€™’€Ģ’€’’Ŗ’Ŗ3’Ŗf’Ŗ™’ŖĢ’Ŗ’’Õ’Õ3’Õf’ՙ’ÕĢ’Õ’’’’’3’’f’’™’’Ģ’’’’÷ H° Įƒ*\Ȱ”Ƈ#JœH±¢Å‹3jÜȱ£Ē CŠI²¤É“(SŖ\ɲ„Ė—0cʜI³¦Ķ›8sźÜɳ§ĻŸ@ƒ J“ØŃ£H“*]Ź“©Ó§P£JJµŖÕ«X³jŻŹµ«×Æ`ÊK¶¬Ł³hÓŖ]˶­Ū·p欝K·®Ż»xóźµ€ßæ€ Lø°įƈ+^Ģø±_ ū:f 9”äɘ3kÖ\įåĶ…c°$酧C¦>øŚl낯;Ęī:»ōÅŚqgÄ­ū+±·±÷šŠæÓ&W=šøl†Ē).?;żctŠ™®·Ōī\”qąŽÕV’÷Čża¦}}–ļĪ:ų„ė«Žž‘Ų™öÅGYūF`ŃūdēW~)Ą ”Aš1Č Až4³X~7ˆ‘` ž5”`ŹĢōHóUāFū¤L_ź§ž{“Ś hĄ§”@ž ŌŚi³„VOm«@Œ~!žHP9˜P&5"ŽC ÷¤g„Ų “Ø’ć‹ =(PgūPX C*ƒå>^¢¹`l^¦Łą †(††h4©ę@nҤ¤Š: ßCÄōiՉŽčgFXŚy$—S*'A\hI™ä—‰Œ[.źb{¹Į@õō™„ ›fzӞ”1¤E„ž•Ÿ_7ŲwęT„–*]F j•%éę„}”!©@š¹®–¬Š©åIģe§e›ŠŠ#B²:„AbäĒ Ŗ"Uµ‚{(E“ +§<)©L”EŠi5jČc=š€ļ®š²»O -¾¦o§8”JP=7|ŖķŸ`g !¢1É Ū4‰¢­—Ä×Bōh‹-”f¶wŖ’§3Xć¢)š³Ō6L¹nĘ\pbK’,Ża aā£ĖdzB™LŒÜfĆś«“qū†››Ńķ»)}Īi*lM쯫Śz5ÆÖul¼ēņkq”Ä ńī>_UėÅ S„p–Ø1*sƒ®&“¬— śÕ¤…>‹g…µXs³‚%Ķ’Įż– ŪŻ(Æ Ł“VœŖā„HŒ1tmv»ģiÄx‚PߏšA}#h`·„W~:¶·id ×J'‰ą€µģīéĪŌč Rž±åͽn“±o”Ż ¾ƒż^čÉOP&ė'½X'JżFé"K0čŠo?ļóµ?>‰ ay£ó臷ńä]qV­UŠ”(ū̹ļųē¦ÉżāūȬĄ§æ‰OtžóMųߣ®€[üąg¾ņqF™7ČĮj:ŒwBHĀm^&ō WČĀŗš…0Œ” gHĆŚš†8Ģ”wČĆśš‡@ ¢‡HÄ"ńˆHL¢—ČÄ&:q;orafce-VERSION_4_14_4/doc/orafce_documentation/gif/TO_NUMBER.gif000066400000000000000000000060621501757153000242050ustar00rootroot00000000000000GIF89aŁ’p!łK,Ł’‡3f™Ģ’++3+f+™+Ģ+’UU3UfU™UĢU’€€3€f€™€Ģ€’ŖŖ3ŖfŖ™ŖĢŖ’ÕÕ3ÕfՙÕĢÕ’’’3’f’™’Ģ’’3333f3™3Ģ3’3+3+33+f3+™3+Ģ3+’3U3U33Uf3U™3UĢ3U’3€3€33€f3€™3€Ģ3€’3Ŗ3Ŗ33Ŗf3Ŗ™3ŖĢ3Ŗ’3Õ3Õ33Õf3ՙ3ÕĢ3Õ’3’3’33’f3’™3’Ģ3’’ff3fff™fĢf’f+f+3f+ff+™f+Ģf+’fUfU3fUffU™fUĢfU’f€f€3f€ff€™f€Ģf€’fŖfŖ3fŖffŖ™fŖĢfŖ’fÕfÕ3fÕffՙfÕĢfÕ’f’f’3f’ff’™f’Ģf’’™™3™f™™™Ģ™’™+™+3™+f™+™™+Ģ™+’™U™U3™Uf™U™™UĢ™U’™€™€3™€f™€™™€Ģ™€’™Ŗ™Ŗ3™Ŗf™Ŗ™™ŖĢ™Ŗ’™Õ™Õ3™Õf™Õ™™Õ̙Ւ™’™’3™’f™’™™’Ģ™’’ĢĢ3ĢfĢ™ĢĢĢ’Ģ+Ģ+3Ģ+fĢ+™Ģ+ĢĢ+’ĢUĢU3ĢUfĢU™ĢUĢĢU’̀̀3Ģ€fĢ€™Ģ€ĢĢ€’ĢŖĢŖ3ĢŖfĢŖ™ĢŖĢĢŖ’ĢÕĢÕ3ĢÕfĢՙĢÕĢĢÕ’Ģ’Ģ’3Ģ’fĢ’™Ģ’ĢĢ’’’’3’f’™’Ģ’’’+’+3’+f’+™’+Ģ’+’’U’U3’Uf’U™’UĢ’U’’€’€3’€f’€™’€Ģ’€’’Ŗ’Ŗ3’Ŗf’Ŗ™’ŖĢ’Ŗ’’Õ’Õ3’Õf’ՙ’ÕĢ’Õ’’’’’3’’f’’™’’Ģ’’’¬÷ H° Įƒ*\Ȱ”Ƈ#JœH±¢Å‹3jÜȱ£Ē CŠI²¤É“(SŖ\ɲ„Ė—0cʜI³¦Ķ›8sźÜɳ§ĻŸ@ƒ J“ØŃ£H“*]Ź“©Ó§P£JJµŖÕ«X³jŻŹµ«×Æ`ÊK¶¬Ł³hÓŖ]˶­Ū·p欝K·®Ż»xóźŻĖ·Æßæ€ Lø°įƈ+^Ģø±ćǐ#KžL¹²å˘å3kŽĢ¹³ēĻ C‹Mŗ“éÓØkĘĄŗµė×°cĒŽńpµģŪøsėŽĶ»·ļß²i§NÜ#€‘Ē&'¼¼øóē›”®:`ėŠ³k7ˆ}cwo’\7(üa’\C 7€)f˜dй$wc¦Yf˜Że‰„–o $†–FØękŽ œ]öiÄ(CL ƒ Jh /"wØ”Œš(BĀuXē>ø£‘.Z覈z¦Ÿ Õät8” „( ¤LŒÄhHL‡2VōiØ“ 5*AŽ*Š©<Ŗ*\&W¾kZĪZė±=é*gFŹśU,²ŠfÕl‘5«¤EĘF«-MÖ2[ź`Ļn+.TŻž÷­`įŽ«īRåV{n`é®+ÆQķbūīuöĪ«/QõŹzļ_ńī+p² \Į'¬šĀ 7üZ¾G¼S¶ R,ńÅKl1ĘėĒńʇ|įĒy"—ÜČ¢lņŹ©ÜŸĖ,— ³}3ĒÜqĶķįlóÅ:×óĪ’¬Š@ėK4tG½nŅĪ1­“øNõÓŃNšÕTOe›Ć\wŻõ°a}šŲY“ėBd—–vŁM­}rCn‹7ŪIĶ­zvćG·ˆg“ˆqŽ{óŪ÷’ΟZx“l8sƒ‡­ųāč6Īäćć‹8ܔWīģB7³bĖé ”"kÄÜŠbݘ®¹å½č °¢ūŗĻ«Wž¤”¢¦Īóź¬4IŒ“@8ɕ.^„œÄśČŖó~mBhĄ‰h#'nN gö¢ š‰÷ąó}ŠŽ‹o~&ē§žśź·Ļžūź+#h ?æżõ£qæžłļļ’ğł7Ą’0€L  &1}©Œ 'ų% V‚¼ 3ČA >°Ax ”éœ'­ß(dR{ŚĒrb@§Š dR¢™f(Ć Žą†bø”sØĆšp‡=ōaˆĆ!ź°Głžž“ČÄ%:±‰P|¢£HÅ)Z±Šß#” ¶ØÅ.rń‹^ #Ē(Ę2n‘Œhģ"ąHŸ)D8ņs‘”¾Ō+9ŖjĮć„ōČF7žkv¬Šk~g)”nWÄC SÖG«Ąg‘"äĖY•GJnu’¤$įt¹Ff’([óš(GIŹŻ@$”£¬ŚüH,J²•¢ŪU>‰K†Ä<¶l„'’č’-®Šņ&¹$Õ*y–_’§_ŃéŠ1kLć0“ŗģ#2%²ĢgFŽ˜ī¦rJÉĶnŽĘ•Ų̘“ÄJaśM“z™¦ĒFā9`’3œžŅ&:ń¢Īrz¤70@Ō°c:×üŖ5Ō2ȋšéĒua‹^¤½Fu ·ģYŲÅóœó¼K³d¹Ī0hGū”'‡ŅS%&-'QŗcĖpgŗzØWÖ³NsF*“f„£Ų¬fFO2­’¶Ń#*Ā]HRęŌD‡ÜGQA‡+ĶIŽĒFsÜ$Ó<ĪĦyR61ŗSŗXKBKZÕ ųōR›|GŖŠ0ä°nЦjUŖ u©J_$¾ ’£RKmR:¾N§w£Ø Å9¹®Ņ‡—Z½hF> ³*$ƅ$Hb ņØøō ĶÉėž$†vF”5{}†> Ąö_qÜź& ;kYō§ńī¬źŲs¦Š \h« '1 ©^– pM„ÄײŠHU](Ya‚ÕŁ™Vw«em\¬„<ÅRŸ°žćjŪŗęĄÆIiē’c>­ tł{)_«٦ī*iĶ=Æj·+]¹øÖ§Ō¼c¹źXŽmr Ņr€_÷¶,99ŌėŽ–ź9eõ·é!FqĆ;ÕēņŌ„Z.5MY_ūśF!“NĆ {U…€7¢ŗH{U4F“&N‘ŻGpz`× — EMäKš;„ –¶†‹µ,Ģ_ˆą“…ņ,1ćxIäč6Čo™Öl“y‘ ™¹ē†æĀćŪ¶±Pv‹²nūå‰0ČĒ’C׏5‚Ė0Gž°ÅŠb ]OtÉŠ4§“ŻŒ–zĀŁ!*ұqļ¬ę?ē7É|ī³”;Ź1x°„¾fž‰čźxóҘē¤;2+h|IKi–4‰9mĶR’IÓ£ęH¶jx­¹—W¦Æ¢w¹iU“ÄŃĄÄ“®w°yÓŌ±‹N³#Ÿ_“dˆėr1Qh (,ĆFZ³mõźeÓzŚ?y6—™mžh[²ć¼v·½]mŹFŪĪ$<·4« Š¢6E7€”ŁÄ=nt™J-ƒ‘ģHJN¹Žµ|õ‹łŌł92PšKøū®š†3Ü}ĮӟēG%R|ā·xĘļwqWœćÆ_ĒAžq‘‡<ā%‡`WĪņ–»üå0¹Ģgs Ę@мĻõ‡Ā PĖ©ĪS)ķ ‡.C¢ńč7,ŗŅ‘nō¤3]éWŒz§.õŖSżźJ$Ņ³ØŒļA”ė^ļśÖ!*v„“ģgū×Õ^v±ÆŻģow{ŪÅˆģœ .G悊^›¬H»ū=&Ży•R%ßJžżšoKˆ£“P*8*źF<Ż"OeÉ[¾$”?ōå7ĖKržóó=5čGĻfĻ“žōµ&KęQo²Õ—›õ°ņ¬cO{“ńśö]«½īwĻūŽūž÷Ą0¾š‡Oüā’ųČO¾ņ—Ļüę;’łŠ¾ō§Ożź[’śŲϾö·Ļżī{’ūąæųĒ Ožņ›’ü¼ ;orafce-VERSION_4_14_4/doc/orafce_documentation/gif/TO_SINGLE_BYTE.gif000066400000000000000000000037611501757153000250240ustar00rootroot00000000000000GIF89aGIp!ł9,GI‡3f™Ģ’++3+f+™+Ģ+’UU3UfU™UĢU’€€3€f€™€Ģ€’ŖŖ3ŖfŖ™ŖĢŖ’ÕÕ3ÕfՙÕĢÕ’’’3’f’™’Ģ’’3333f3™3Ģ3’3+3+33+f3+™3+Ģ3+’3U3U33Uf3U™3UĢ3U’3€3€33€f3€™3€Ģ3€’3Ŗ3Ŗ33Ŗf3Ŗ™3ŖĢ3Ŗ’3Õ3Õ33Õf3ՙ3ÕĢ3Õ’3’3’33’f3’™3’Ģ3’’ff3fff™fĢf’f+f+3f+ff+™f+Ģf+’fUfU3fUffU™fUĢfU’f€f€3f€ff€™f€Ģf€’fŖfŖ3fŖffŖ™fŖĢfŖ’fÕfÕ3fÕffՙfÕĢfÕ’f’f’3f’ff’™f’Ģf’’™™3™f™™™Ģ™’™+™+3™+f™+™™+Ģ™+’™U™U3™Uf™U™™UĢ™U’™€™€3™€f™€™™€Ģ™€’™Ŗ™Ŗ3™Ŗf™Ŗ™™ŖĢ™Ŗ’™Õ™Õ3™Õf™Õ™™Õ̙Ւ™’™’3™’f™’™™’Ģ™’’ĢĢ3ĢfĢ™ĢĢĢ’Ģ+Ģ+3Ģ+fĢ+™Ģ+ĢĢ+’ĢUĢU3ĢUfĢU™ĢUĢĢU’̀̀3Ģ€fĢ€™Ģ€ĢĢ€’ĢŖĢŖ3ĢŖfĢŖ™ĢŖĢĢŖ’ĢÕĢÕ3ĢÕfĢՙĢÕĢĢÕ’Ģ’Ģ’3Ģ’fĢ’™Ģ’ĢĢ’’’’3’f’™’Ģ’’’+’+3’+f’+™’+Ģ’+’’U’U3’Uf’U™’UĢ’U’’€’€3’€f’€™’€Ģ’€’’Ŗ’Ŗ3’Ŗf’Ŗ™’ŖĢ’Ŗ’’Õ’Õ3’Õf’ՙ’ÕĢ’Õ’’’’’3’’f’’™’’Ģ’’’¬÷ H° Įƒ*\Ȱ”Ƈ#JœH±¢Å‹3jÜȱ£Ē CŠI²¤É“(SŖ\ɲ„Ė—0cʜI³¦Ķ›8sźÜɳ§ĻŸ@ƒ J“ØŃ£H“*]Ź“©Ó§P£JJµŖÕ«X³jŻŹµ«×Æ`ÊK¶¬Ł³hÓŖ]˶­Ū·p欝K·®Ż»xóźŻĖ·Æßæ€ Lø°įƈ+^Ģø±ćǐ#KžL¹²å˘’3kŽĢ¹³ēĻ C‹Mŗ“éÓcXĶŗµė×°cĖžM»¶ķŪøsėŽĶŪv ‰Ŗ{ ’Ķ0øšćȓ+æM|”ńåĢį@=rzDė(±+Ōž—;Bļ%Į§O]#ł„ēA¦øžnūöį{$&fżņ×%ŽĻų~p•ūeƒ¾T ~ ķw`E’Ö`v)Mū,Ȓ…~§€ aøÖƒ'yč1ÜP{B‰˜!A r˜ ®¤āBb ‹)®ŲQ‹)č—į‘” b4£I䯹qC®vćv¬ 426ā(•«Ż „‘®)ó]k7ŽP¤@“Ä dk1`ٚ—YńˆP’&“Ä#DZJ7ēAõŌ)gHŹÄ°4äBŚe²‚”q~GŒ@™ÄM=Ö­6•Wb'ʘŽĮ‡•^ą%„[†ź•›ŗ'”)cź[@4 …§zT擁樨(ZY«”‹zZ!1ĶY­yīƒk„ +Ę¢bhłź¤Ś j+Dä‰A+G­Jé$–7{Cs毩a¬ ©ēø@­·)øūÜp-A߉"7BškAĒŽ‹ź•z®ŠhA›J© žø”‘čth,:$›"œš¢;vŌgš/¼®Äœ»O#ļ¤ę§S »4S²+削¢‰š«57äµ(³\”ĖZLĻŹęIL}°¶ėå³meĖč˜Ųr„‰fœīBö^É®»öšk&b@Ś©¶¾fźv74Ķ]ŌĘ üt~‘x°Ó -ķ„©Żŗeō>™½‘Š’>tßsŠķ–  ś’/øÖ¢\ö@ݼϰ@ •€#ĖŠ±“<™/Ź‘›żSo ńĢßm eRg&(£eŸ¬‚®Š$M߯7ū¼Sz†4¤”vL«ŹD¤ÖQI1§Ź+®ÆśīCv¾[é,jÅlDŸ@b ŗé¬Ź>½äb4$ŅŪ’M‹¤6—ķ$”¬Q Ą£ČÓ Ė(G©ü’0ŸoPż×¾°ĶƅL•óŌóFŒ¶4œĪ€¬Ė^ōŒ½ŽŌˆbčŸŽø”Ī}dnx1ZŻ.eĄsÉė †ź·ˆ„„ķ£ ɔ;žhO/ŁŖ/¢9 µ0„<ŃuV ŗē…=$‰ŸB¦CN°ghƒŠūāĆī}„J+¢8®m_āI"!±IŠ±¢±˜&6°$ŪšĘĄHĆ *‘ŒŻŃāOņ=)ž‘Utcˆäh3&m%KKŃėIČBņøŃ"cÓ”E:ņ‘Āi$$[Óāń’˜Ģ¤&7ÉÉNzņ“  „(GIŹRšņ”ØL„*WÉŹVŗņ•°Œ„,2gIĖZŚņ–øĢ„.wÉĖ^śņ—Ą ¦0‡IĢbó˜ČL¦2—ÉĢf:󙩌¦4§I͜;orafce-VERSION_4_14_4/doc/orafce_documentation/gif/TRUNC.gif000066400000000000000000000042431501757153000235050ustar00rootroot00000000000000GIF89a Zp!ł<, Z‡3f™Ģ’++3+f+™+Ģ+’UU3UfU™UĢU’€€3€f€™€Ģ€’ŖŖ3ŖfŖ™ŖĢŖ’ÕÕ3ÕfՙÕĢÕ’’’3’f’™’Ģ’’3333f3™3Ģ3’3+3+33+f3+™3+Ģ3+’3U3U33Uf3U™3UĢ3U’3€3€33€f3€™3€Ģ3€’3Ŗ3Ŗ33Ŗf3Ŗ™3ŖĢ3Ŗ’3Õ3Õ33Õf3ՙ3ÕĢ3Õ’3’3’33’f3’™3’Ģ3’’ff3fff™fĢf’f+f+3f+ff+™f+Ģf+’fUfU3fUffU™fUĢfU’f€f€3f€ff€™f€Ģf€’fŖfŖ3fŖffŖ™fŖĢfŖ’fÕfÕ3fÕffՙfÕĢfÕ’f’f’3f’ff’™f’Ģf’’™™3™f™™™Ģ™’™+™+3™+f™+™™+Ģ™+’™U™U3™Uf™U™™UĢ™U’™€™€3™€f™€™™€Ģ™€’™Ŗ™Ŗ3™Ŗf™Ŗ™™ŖĢ™Ŗ’™Õ™Õ3™Õf™Õ™™Õ̙Ւ™’™’3™’f™’™™’Ģ™’’ĢĢ3ĢfĢ™ĢĢĢ’Ģ+Ģ+3Ģ+fĢ+™Ģ+ĢĢ+’ĢUĢU3ĢUfĢU™ĢUĢĢU’̀̀3Ģ€fĢ€™Ģ€ĢĢ€’ĢŖĢŖ3ĢŖfĢŖ™ĢŖĢĢŖ’ĢÕĢÕ3ĢÕfĢՙĢÕĢĢÕ’Ģ’Ģ’3Ģ’fĢ’™Ģ’ĢĢ’’’’3’f’™’Ģ’’’+’+3’+f’+™’+Ģ’+’’U’U3’Uf’U™’UĢ’U’’€’€3’€f’€™’€Ģ’€’’Ŗ’Ŗ3’Ŗf’Ŗ™’ŖĢ’Ŗ’’Õ’Õ3’Õf’ՙ’ÕĢ’Õ’’’’’3’’f’’™’’Ģ’’’’÷ H° Įƒ*\Ȱ”Ƈ#JœH±¢Å‹3jÜȱ£Ē CŠI²¤É“(SŖ\ɲ„Ė—0cʜI³¦Ķ›8sźÜɳ§ĻŸ@ƒ J“ØŃ£H“*]Ź“©Ó§P£JJµŖÕ«X³jŻŹµ«×Æ`ÊK¶¬Ł³hÓŖ]˶­Ū·p欝K×b xóźŻĖ·o^ļśLø°įƈ÷Q·±c”>Fv8Ylåǘ3s¼¼‘³BĻ^AkMś”苧 ¦Öŗŗ“ė×[O”›,mŲø1߆x{7Uß¹ƒĖް·mįČ]gh|ģņäŠĻ>’lz!7fO:=ŗ÷°Ż6Oø‚!1Ęܒ櫟žąx÷x•ÅȄ—Ų ¼±±§_Ļßm{ÕÕ%”É$ūȇĘ>ōe‚ąb(ø_¦õ_AļŌą>bˆ!ī3‰†b(£Ō„–ȉUXŠ "²(P "īć>(ŗT£‰8źd˜dŠ)„^yµ‰w‡“ć‘F„v£ŠŁWąvŹhø“NŽČ”Hf”’ =Ǥ@™h(Ÿ@c"(&CÕŚZ¶ —Hї\­éę;ĮyP‡³hsxz“ž›ł  ‚&*” –ŠFj#uѹ¤’fš£YŹ¢š†Z§y𦢦ś&„™ŠŖŖĘŚh—ŠõHY/­øęŖė®|*믱©ž°ĄfJ¬wĒ«h²Š1«l Ī"ķ³nNœµŌf‰-nŪ’f›c·Æėm‰ā–Vīøż;šŗčū+»^Ąė¼ō&搼õöھłöė`”½æž\ēT“-°O® ź›Ā]Į»jq’-ÜSĆŠFńĮR%\1Å ;*źĆs•Ē•ZĢĘx’œrÄ«<«ÆyŠŖĖ­ŠDŒĮƒĘ rĪ?Æl³¦8śQ=7Č«£Ļ4w*óŅO߬qÉݧ Ä"tß^4rdб9ųµ2yI5«e"ēŌA+„†Ų+šÄņE”&ŪMĄŚXSøŁ>P&Œ NfddW&øŽ”q÷Ģ åœQ»cAʘ=ŅÜÕāmŠ€”kDŸŠŌ·é¾’r@=4RČŗēMćå2Ā 9Ś]ŲgŪ]1“ł>^ŒŃ§ßŁøģyÖµ§Ģ +ŠžuĻ nø‡€]8ąūؕĖXŹi‰¦‡ŪMrąŪƒ‘/ó.5o é¾üDb`»ģ8”ŗ—Į«C]ėö±Äm‡$ä3Čć†Ę<ÕÄ XŚˆD€=y]ż“¶ RDol MVc½ÉĶ‚—ŁŽdŌWÄ-ƒīAįĘW¹*aˆ@łĖ‹‘"<½Šh ”ņ<ø'>"dć™x8"„np•1ĄåĘŗŹ4hx“›“Ē^)3!FŲA£p^ģŒ‘æÖČĘ6ŗńōRˆŚf³«äOz~Ė w; $C‰J8ś D i“H󸻦NDwÜŁ'„ Ȓńk bæ#J„lBäõ>ĆŗéŃHNĀćA€ø¼$R‘įė¤'—(C¼ˆa;¾»Ī”ō“8aI©ŃÜ,%Āź‘i‘óQčŁ?M¢†ƒĖÄHžl¬÷KS:e‘ S#“2gnŅ blGö>QŽ™É+UųĪéĶhŽ.#£³&MŖé4łk5”'Ž6Ö½éņ˜Ƨ;3ŲĶvŠ3“ÉŌN&Šm¦³™=(ŠB‚Ēy¢“ åęÅ"*Q ^ Ž #sÜx«ö‹£#)JWŹŅ–ŗō„0©LgJӚŚō¦8Ķ©NwŹÓžśō§@ ŖP‡JŌ¢õØHMŖR—ŹŌ¦:õ©P ŖT§JÕ¦;orafce-VERSION_4_14_4/doc/orafce_documentation/gif/Thumbs.db000066400000000000000000007460001501757153000237000ustar00rootroot00000000000000ŠĻą”±į>ž’ ž’’’€’u’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’ż’’’%+ L& !"ž’’’$§P'()*,-./0123456Q89:;<=>?@ABCDEFGHIJKž’’’MNOh†RSTUVXYZ[\]^_`abcdefgž’’’ijnlmnopqrstuvwxyz{|}~ž’’’µRoot Entry’’’’’’’’€˜½›Ņ@¦256_2e4eac3ddda94cc5*9’’’’@5256_cf13226c22f1dc7e*’’’’’’’’’’’’ 256_7874b7e0dc70edc( 4’’’’g  !"#$%&'()*+,ž’’’./0123456;89:;<=>?@ABCDEFGHIJKLMNOPQRSž’’’UVWXYZ[\]^_`abcdefghijklmnopqrstuž’’’wxyz{|}~€ t•`Ķ”PÓ ‰PNG  IHDR3xėÖŃsRGB®ĪégAMA± üa ²IDATx^ķ{LTWĄæø3¼–5«"«¶¬šm¶hÖÖX[qĶŚÕW­%5ń±ŃųGK“qvMVć®&l­ļ¤¦jĘGaYlҬņˆhE”HE­<e€yž=ߙ3Ģ€3ĖĪ8“ł~‡›{¾ūsę^rĻwĻė»WÅ8@DP¢–{‚ ‚2Đ ˆ † A1d"ˆ”YĀcŚŚŚ °°PJž1.v¼ūŽ»RrpöĢY0™MR ,ƌIs“¤ؐ <¦¤¤¦M›ņČĄœ:u –/_.%ééé°jÕ*)ī®)”.A1dˆ—Ž^Æ]¾NJ6>|ƒAJ„· @¼tŠŠŠą~Ż}ŲłÆ°qÓFHKKƒl]6ܼ{S¦ ¼.Łšé˜Yg“ģ:.` Äq£wQH$$Ō ź½÷:Ee¾yŽlģ`<*Wŗ#ßhž9ļ™{ļÜŻóŽSŽbc2@0+±åƁ`"€@0‹ @ ˜ÅLŖø~ż:Ž=Š”ė)¼ęÆikkĆšš0+××׳×obōżīžnŌŌŌ°²`v300€£‡Žāźå«¼ęÆIIMAee%—īĪčµUU[…ĪĪNVžLź$ą’¾óæˆŠˆBEUÜ\ŻPZYŠu«×1ņ¬¬,,Y“½½šrņBiu)j«k”ŅØ°fÕ$\IĄ³O?‹ė©×ŃŪÓ {{{D†GāüŁó‹ C^f6mŲww̟?ŸŖ`6ŃŃŁųųxhŻ“PŪŖ‘™‘‰č…ŃØØØĄŠe+œ’Œ–¶Ģ @II Ā„#Ą/©i©ųēśgģŪæ¾¾¾0 ˜ąį遤„$¬Ü°i×ÓšŌΧąķė 777ži3ŸIķø»ŗĆ?ŠZg-jŖk0 @ym9¾ūżļ¢¾¦6¶6č7ö#Ą'E%EP)UššĒ¼9óŠŌބǶ<(’ŌÕ×ĮÖÖeµexü©ĒŃÕŻe>Y[4µ6‰Ęo%tõvńŅäA½ĒøåqŅ ”²¼¶Ć¶hioĮ³»Ÿe7œ„+–bŽß !rA$œŁ>­z&ĀBĀPWW½­ĶĶŲü7›QU]{µ=tFݬjüĤöčn€Ņ¼RŲ»Ū£¬¼ +ļ[‰³ēĪb͚5ø™zŃ1ŃšõšEyu9ģģģ0Ō7…£­­xėæŽĀ’¼õ?Øk©CG[‚ęĮŪĻēϟĒ}܇äÄd¬Ū°ķ­ķęŸ*+4|üńǹ4yœ={¾ž¾ Bff&¢¢¢Xư³£%Å%pÕŗĀŽŃ¶&[صjääāŠńCx÷­w‘–žĘnPnZ78ŗ:āZņ5¬Y»ēĻĒŚõkŁMĘÅŅŅĢGŲ$£­µu³ņE¬$ƒĘēy#€@2ęĻå%\ @ }]}¼$+B$C7 ć%\ @ ž¼$+B$#+'‹—rE, $C׫ƒ½ÖžK9"zɈæĻK¹"zÉč韁“‹—rDō’‘”œÄK¹"ŪĄ~ō#ÄĘĘrI0ŠN§Ć믿Ī%ySUQ…¹ó„1œ‘­ųųćńŻļ~—K‚Q¤r°‘r±]žĄr. äˆU ‡QVUʂA“6¶¢±±}ŗ>T×T³ņąą ĪşCGW“ z/%%'OžDgחrrržžĪ\B齬ģ,ę7ž”4Ņ]=}ś4{Æ””<‡††p»č6{æ¶¶–½Å„ÅģµŗŗŠōČæŅ©äīLǤĻhØo`ǘmŲØlxI W¬BÜJ½…ĘŠFōōö %' —péü%Üø~ń—āqģČ1<ņš#ųō³OqłŹe¶ĻõÄėČ/ŹĒ¦M›ąāü„{gü¹xōõ÷!įb{/&:‡†³‹3Ī'œGŲÜ0ę²ćœśüV?°{?Ų‹ßüę7hjjĀ„K—ŲqLĆ&¼óö;(Æ(ĒŁ3g‘™+W®ąč_޲h4}ō Łgø»¹ćš±ĆlæŁ„‡«š”;V”Ŗ›«aļa®®.hl4,Llt,kØJóĆ8d„Ń`d>āʶImBK] Æ&Ā`0°:źI¬^½Å·‹ŃŽ×ĪlEYÖÆ]Ü¬\ ¢Ē؃śŗz š”pU@å bIī»I‰I0ٱ(øDTLņsņ”3čp9ł2ņró07b.Ž>ĪāŌ4Ō 11¶J[Øj¶ßl¢øl¤‡$/Š_˜įeY‘——‡˜˜V6ō0gĪ\Mŗ ;„C‚ŽŽ^‡cŊųōÓO”VŖ±üžå8uāī‹»=}=Li1ŠQo„Įh@QAjbĀcXč2„ ėYčz,_ŗœõ.(¬" ™Āīī[ŻŹöY²l †‡ R©Ų>ō·"­ųžīļ³H4J%üCżįļéĻ>ÆÆ·®®,jMÄüö}&ĀķŪ·É%yćķī ½†K9b“€҉؃“Ē "„Ąj³O§†ßÜŌ Ļ †­āŪ;QŌ+QŖ”lŸ‰bM“€ĒǶmŪø$#²Uo¾ł&6oŽĢŹwžā×½÷M ktæ±¼’õŗ»“nt[bT¾Ū¶Äõß“’(wÖw;##/¼šGŽčśt,4—@¾ČVP÷^.ģßæĻ<ó —¦„RÉb)Z'ŽŸĄw¶}‡K9"[ 'ö¾³/¼bw]9AĖ©žžž\Ča lÅČ*‚`lT•Uń’@®`ŖA/ ʂ£‹#/ äŠP0l3’ŹL06hÉV o„°J0!;uMu¼4½446|‘r2ø~ć:NŸ9Ņ’RL– ÉędČübŠ~õė_a÷÷v3{~£ŃČ ŽŲśæ 008€į”ah”fTD&Ād³ “U²{J‡F¾ äĒ Q™·QŒ,÷ŃqlĢJFu_9¶rDįŠ>tįŽīGe2.RŁŖ P*Ų±i²NŌŚiæč©čō:¶F­a›¬!ķa²łwÓq`.:hŲ6tŽżś~8jŁg™Ģ:6»Ö^˶!Ų±*ØUj ›ģŲęcŻłłōY”aGa«€­Ź–}OZÕqԚĶ—4é»ŅļęččČŅxż}żŠh4P©Uģ»Ņg“…§ÖÉ|lŽ€õ:=ūķķķģŁ~t ņŌjµģ}:oڇ¶§c/æš2†ÕĆųõ/eqĖXŻx”ĻüĆ’ü1 cŠŚŻŠŽŚÄ.e˳”%+# ė×­GFv~ś“Ÿāæ’#††ŠĮATŌV`׎]ųąĻ`ĒöØ©Ŗaęä?ü0ó dž)6&óÆ6lƒļ}ļ{Ų’ń~üķS‹³'ĪbŻ£ė°8j1?›‰#€üįĄóĻ?Ļ.\ŗ6 Öw¢ ›.4Ŗ'sįы›¶±µ17óÓ¼ †Mę¦bŽŽö£FK)» Ķæü×÷»óŲ$ßm›ÆŪ|z’²”ćŌ(Ł6ężØŽķg®£†K&Ģ5B”PŒģgž#Si„bÄ`iōI1ÜóŲę÷éœīvģ .`ÓęM컐2aĘPę;¶y:/Ŗ£W‚¬,éøwūƾ›y:?R€l?ó) ²Ź$¾~lz÷Ófåm¾łŸX°hŪn¼Šł\»~)؜¼ģśŽ.čG[_ŗ›»įīķGŌ×Öćµ’ó>łä–ą6/?nnˆZ…āāb`iģRf ¶qóFę9YŁX‰¾Ž>ųśłĀĻĖĆŹa“6µ¢ŗ®kVÆAfV&ę…ĢĆę#ö1“P°ēķ=xńÕ¹$°£ĪÜ£±Ÿ~ˆöĪvø¹ø1Å1ܼy“„«_¾x9˜§jVn<Ü=ąėć ///$^NĎ'vąOo’‰5Ś ą ę0F½—'v=`ד»ŠÜ، æ 4“6°”ÅÜ ¹pus‰„hÖ’^Ž^ųģ“ϰk×.=2bźäģÄĻdā`z’OųįK?䒡R¬ÉlY*Øy*ž;Ėrad°)ø'ŌŻŒU÷Æā„ŁĖ ^nŸ Ą”C걤`Ģäš’@®`4ń$;¾s|yI W„ųöøńWćqīĀ9^#°”żHp| ą[ µżGN Ų/˜×,„«·‹—rE(€oŒ6^{õ5,ˆžŲśńl$t^(/ äŠU.¾ņŹ+øļ¾ūø$=S½|ÓŻŻm5±’ļÅÉ'±õ;[¹d}!“œāRLŠ!±eĖ.Ż)kc’žż¼439tč/Y7†~/Y'GŽį%ėgß¾}¼ōUdō^dgg‘5ØØØˆÅé»tń**+••ÅꚚ›XhļŠņ ųųś ķF“nZģŻ³M MHĻHgĪž^žpt±’ķo‹ŅāR4µ5”ŖŖ ™™™Ø«©ĆÉS'Q__Ļģż ĆhGģĪ„¢°°QQQ\²^Nœ:a5LļĘ×°’93łé1™+÷÷÷3ÓhźR=™#÷õõų0 ŒDŖžĀ“ŁÜ‹¤÷Ȕ˜ ::=õz=3a&?bō3h[zotz/Ō./žkėVęĮĖÅKY];wĮŻŻ7’o@m§Ę€nå•åšńńaĮ;Ož> ­ ¶nڊų ńšōōDDxŌj5ū‡}öŁg°s¶cQˆÉ1…ž”ĶŻĶ(.(Fhh(V¬\ų³ńĢž[JfŠ ³X{{ė x§ ä/iéiČĶĢEn~.K<Ó֦ʒĮ\Ė„/±J@ć©©äĻ’ĢRMŌužČŒÆ\Ø®ØFм .Y”Ł™ę}¤„&°żüüø$ŌĢwģŲĮ„/ń,ąĄžxś™§¹$°”3§ĻąŃĒå’ąnLw/CLi[Ą€I8µŒ c%7BX€Ś4ūR{O.š’@®`d7 ;ÖĶ܉ډRW_Ēl¦1`÷ÄīvsI`)§NžĀßlż.IGWWŹŹŹød¼ł’ŽDKC V­Z…’xó?xķŌ#€ģŁæ/>#¢•źŖjĶ•~ ž\<āVı<ÖĀė?~uX·?’ÕĻyķŌ#€ˆĄųH½–ŠūVIo2«6­‚V-­“ÖdBV„ĪZg;vL¬ČƒRĢŒ•ŻŌ$U%Ÿń:ÉLd6,‡s Ą4ƒÖÓµ”.Z^’„Čą<^„°½rÄO[06Ź«ŹyIZ(„ٰ툟½`l`J£Č 0–/]ĪKŅb£2w„…­Öø Ą ę‡`ģ\½v•—¤…†hƒJimö„€¢ż“u¶±ų£‘‚¦”,€‚5ĘΦ ›xIZō&=ĖÖkmT–UāÕW^ÅĘ §mBP\Ł– ę—ĘEüłx^’{=śõż\²,\€OģÄ?üߘ6 ģ,`ß’īĆs?zŽKKiØo`ј¤ęÜÉsX½y5U#Į]'‹wŽyŽŽ“{ĢÆ3l† =$V­­­ųÉO~Ā„;  ø7ļ|ų/ ĘBŅ•$^’–³gĪJ‚|6„CK0ņWĮ˜puwå%i”e@“BŚŽlAaóŻ/.-FG{:ŗ:Š×ßĒźJĖJ™/%©©¬aŪÓ9]M¾ŠÖĪVć‘"NŸ9sĶ-Ķ8|ų0 )~żśu$^MdŪÓń‰›é7‘”˜Ä¢›’Æ%³z© ĄF# ʆĀü˜ lÕ¶2LN”Øę¦füšł²(Óę$Æ ŖI!¾/^øˆŒĢ ˜{78vü¶oߎĘęFœ;w§OžĘœ 9l{Ś÷ČGGP”W„k×®1™‚r^K¹†˜E1ø~ć:Ņo¦C7ØCGcāX4`Šv5Ēorór±téRD.6ƂP`k#~¦ń@ V¦•A…Õ_Üŗu ļ¾ū.öģŁcńóĄŸ`ϟ÷`ē®(©,įG2_<‘Ē÷¾’=ܼyyEy,*0į q€®G‡ÖīV Œ,GŅŹ‘ĘEƒÖŽV ™ZŒžį!įPŁØ˜‘Ōņ—£«„ Æ]„q؈̬LfÖ|ųča“5µ±Ļ“:$™˜“€½oļŠƾĄ%„»«—Ÿ—¤ƒœÜō Õ_°£;ļņåĖYØwK”¼ŒēΜöŪXH³QGĀŪ…ģn¬ė×±‰»ŽĪ^ ›§ĪœĀš‡Ö°;yHP’“Yn {µ=zõ½°SŪĮ8hdRµNZ¬]»gϜŶǷ!3#“ Č#pN€ł®Ÿ›Ėœ„źėźƒ¤«IšņńĀćŪ&ī,ōMAAÅ$ ¼żĮŪ¼$ Ēē%i¹xž¢©§«‡K_’œœl2Ę?98žI@ś¼žž“¹aóy &'‚p›7lę%‰1÷’ļ6˜Ø·”Õj­&%šXĄžwöąÅWD@±2UoSįŸ@^3Āx†wBsÅÅÅ\’†““4vŽRŽeĖ–qéK„°€·’ō6^żį«\XJKs ¼¼„Ÿ „“č…Ń,•֝LTL",ø`ʒ“ĆKc¾Š‡§6YĢLA(€{@#Ź8œ—™‡œÜ)ŗ˜gA¼$1¤BŒ”īŁg_NŗŒ÷ö½ƒ^ø]Ǝ—$Ę<ˆµĘZćA(€oįļžīļ°mė6f&}ś>^’³˜ ¹§«œ¤Ģ¹+V¬ą’ōy¦B15f­Ł”æžśė\²^źŖėąäĻ%éH¼’ˆčŃp÷żėIĄžžØTņõēNNNĘæżŪæqiź±JpąĄ<żōĢMÖIĪ";wīä’õBŁu·nŻŹ%éH¼–ˆšįšõšå5#čō:ØUźióµ·Z˜Ī’µāfxYÖč‡ōPŲ(Ų?3;;±±±¬~ß¾}()-a6Ō}ōįķē“ĒO2‡ŽšŚäęäbP?ˆ‹—/ĀĶÅ åååørõ JKJįéå GGfƽ÷½pótc&š§OŸfž[Fƒ—.ĮĪÖ/^Dnv.¢c¢‘p!Įó‚qüäqv>ä/põźU“µµaīܹģÜĘ yEEEqÉz™0Jµōń«Ź«ąéīÉ pīD„T±”]3r}!2RZ‡Ÿ{!›ŁWF Ų+ÅKėėėūāyąŻŲ±mŅSŅæšŅ¢}ØńõFŌTÕ ²²J…’u«hŪG~UUUl[[-ŗ;»‘~+µõµØ««c’{;n±5¤d¤° tAÕ××C£Ņ ĻеF.}{Rꦖ&ꭕy+aóưśÕØ®­fqŻģFŽ'Ą¹óēxIbHLjø­ćĀā!YDÕ7ŌcŠ4ˆ”~sk1÷ŖØRƒ2,Į4Ż1ÉłA£Ō@? žģßæ_Ę3Ž\—c……2ęžĢĢLėˉ'dŒ±/’ČJĖJYgW'»uū+­(eŗlć]™ĀæpwMvŅūŌ †Ģģ¤Ł26äŲ±c°vķZ)|qą ˜žūéįaįpēŽØÆ®‡ų×ć!vB,“4¶Ąž@¦ö{÷īuœ—¼Ž;ėÖ¬Ž9ŌMR˜ĘÖFŲŗe«hĀŪĮuī+W®”’ƒž]įąĮƒ°~żz)ŽÄŻįē›?‡øńqR£Į’¶QJCgX _ŽčīÜ{M—.]‚ÄÄÄ>/Épg¶mŪ RņīŻ»[·n•įMÜŻ_ƒ]w1¤ŗ‡5ŻŽĶ³ƒ`Ø87g5=b999,?/Ÿu÷t³ó¹ēYSK“Ō2f4Yõ­jÆ««R__Ļ*®U0Žob•7*ŁOU?‰r~nų™•\*ńŖ›U,//OÄ;::D¾įā®)Ö’ųĆʇ2Ꚓ’’>/É@ÜuĀŻ}ē¼ī¢©ŃQoÜ1Ų®DĶķ¶łļ›Ÿ«?ö”a3vŌX1Ź:oĮ<ŠÓĮūó߇¬Ģ,ążX”WBŲ±m4·5ĆŁsg!ūl¶ĮĶĶĖ…œ¬hxÜ_ś ŹĖĖ!99ņsóįöķŪ"Ž/‰øsēŽp+Ķ<™)Źóx~„%„R"ß ŌBį÷żwą ĢńćĒįĮƒ°dŃyŌĮ 3ˆŹ¢#¼La ( ¼6ī5č1ō]WOĢūÓ<ų”č‘Ī¢ŲFŒ­qńqpīō9Hx=Ȧ>|žv<…»5wE¼ęz ”••Į'©ŸĄĀd9½āZ›[!fTŒ”Ā7DGFC»”]JCז](‚ļ2¾ß_˜ūǹRӗŽ1€'Ož@FF†xźyJCCģŽ½[Jŗó:X4TÖTBõj1ēkļ 3ƒģÜlx3ńMøXt¢Ć£Į¬6ĆÄßL„ŽÖhļhmøō=zń*(‹ÉMO›`ģȱšźo_…Ś[µ°xÉbųęų7šŁśĻD™Ć ‹Éōü—ix—DĢ‹#xž9§s`éĒK…ģ ø|łrŸ×W”s5ĄHGށžŪCљīīnŲ²e‹ˆó.\“x‘]Į» ¶©F7蟼ÅZ’å)ĖAŃąü$@ii©ƒŠŽŽ² ĄPń¤‚żaģߜ9wFń<øq憌¹†ĘˆĮąÉĄĶ꛾Փŗ×ŅŚĀöŚĖ®–]ņ•+Wž Y€~xs   ŚŪ‡×“óćĒ‡Y³fI‰š&/cąŚµkP\R ńńńšĪ¬wś“†e°=bÄ)UUUbÅ^¾žśė¾M¤ĄĮÉM›6ydhį®ā®[·’’<’ąhmm-lß¾]JƒŻŠS™§ą£” "Üé»hˆ‹'+ż Z č;¶1öģŽkÖ®±yćń€N;vÆ?ÄīÜc×”Œxā%ˆŗ®g]Ā ČžW­R =℆:¼qT–ƒA8 ńŪS”^‚X.—ŃŁĘ9Ÿų’Y”sŹgV™AįćF«ŗ;»ńÄ|žŗt ŗ~õ:¬X¹BöČxN÷ļߗ’ƒ–––ŽéA\Q\\ •••šJĢ+ Ė>^&t¾&55fĪ™i[‚3FųQ^¬ĒŅ»­×[®æojŌ£=ŽÜč&ŽœŲė”gwƊ)<U^<’~¢1ń`÷0Ä4X”±¢c„éķ:\oĀzö–ÅęĒr,=Ń#0*$ FŽ «Axāb›žĪP)*aLTFT\Ēęéa\§ā:3æ°0[Zmęŗ(­0$źPµ˜^c= Lj“0^čŻŲĶøŽ—”Xų¹k¬b!\˜‰€’~™J“±cbÅłłd|ˆs ’ķé7)ڵĮ oĄäßM:_Cƒ€Į‹­-Gų|ŗ¬X½’f%ĮŅeK_Zå'‚2ÄPĄ‡` $ÄÖ?õ'p CJJŠ”ˆ`‚ A1Ō ˆ † A1d"ˆ!@A ‚bČDŠš?EįM…ō¹IEND®B`‚…#ķ”®zšė±,æē„ļžĖ’ÅW-k¢%¾æŚŪrH?«ŸS‰PNG  IHDR ż©¦äsRGB®ĪégAMA± üaiIDATx^ķŚ}Lwš/m” ˜Ź„J2¶ø˜cu”Å”ŃĢ8’ĄM‚‰ĶFˆń (BDE‚2C”tŗ‰,ć‡Ī4*Ī*Eƛ"Ā¢¢ ŚīīśÓĘĄ† ŠŲ{>—¦æēłŻõ^z÷Ü]Æ6F!¢$aļ„¢@ˆˆQ DÄØ"bT1*„ˆBDŒ !"F€’^æzW®^a±”@U ¼}¼YŌÓŁ?ĪB{GĖ¢™šåĢ ™Ė"³‹.ā¦ę&‹¬—ĀM°ļĀXdvKs ē/œgŃĄHl$Ēč1£YĘų`i™™™¬E,iĖ–-¬Õ»¾śū#::šµŽ•––ĘZÖmóęͬõ®ĮÜ×+++†E§ÕhĒŽc‘ Żb嚟6#3#eµe(//gY*„X±¢ā"dnĻÄāe‹±čŪE,köA @ė«VdģĢ@`` öęģEÉålKŽu¼Ŗ°±L:Œ­I[±6f-ŖŖ«Px¢žJ“¼līgKKKQų{!RÓR±>~½‹‹¦å®p ī²{öģA·¾[Čó®]»&Œ—ø)ū~ٵZ—-/Ł;…eŪ•µ qńqĀōü«„­…MmōŻz侔+l'Kźčč@SSŚ^·!iSŚZŪšģł3Ökå @Ž”ßŁ‰ZY­ųVćSßX7O7”tēīķ»ČHĖ@q^1NŸ8’Šœ > W¼¹ņMQJ’Ų;Ų‹!e$×pēĪČår”¦­­ Ó§OG`` ::; ūQöšŲS’}aŚ HˆO€·—7¾{šÜŻą6Ī Ž˜óņDGF# 0ķŠvL˜81·c0gÖ”ĖŹńꛦŸ»wļƲeĖ„>eeeŲ¼y3oPu©u# ?łÉOÄ»’ÉG}„+VštMM Ž~ūķ'm!߆ Æ" .€•Ź pórĆģé³QU[…… y¹”°gĻ,^¼˜§•J%&MšÄŪŲO*ājVÆZĶßė‹O>łóēĻŠ 77·'ĒXư %4·ė"58š³:!!§5õNuSS“ZsĀØååź‚‚uiY)ư°P­ źĘĘFµ&øØ+**x>+ÆlWņ²š“NŻŅŌĀók×ņWm )ż‘‘Į׳—––žõźC‡‰”Z]TT¤.-ķŁnCóō’eėØ Ž<ŻŻŻ­nmiåéž8zōØHŚ Ėy” fS°¶²†««+¬m¬įį適S§ĀwRĻUšłēŸ‡££#FĶÆŖ&Lął¬<{ÅŹ²«—³«3Ļ÷ņōāÆRĮٹg½¤Ī£G‡ųųx’«\øpėÖ­j`Ų£§Œ;Väkkk¬Y³FØįS__Ļ÷ƒ•••Č˜ `öģŁ<ĶŚ>Īž=«õg‡ūŸģ÷ŅŃŃ!RƒĆö™­­įū*˜ ŗœŗ`Ņ€ ,CfS Bw(„C€ , aĮP  †AX0Ā‚1é~Ģ$;'Ūč† Ž>Žšr×_ļĮ¢¢"\½z£F9ć6Ę ļ¼ūO767rC;;® ėl“vm 㳯>ƒ×hķöƒü±Śó'”ˆĮ Ž@}Ą A“ńrĄĖ"Ē8°!Ę~š”PĆĒT Až=V”””x’}ķ\~ õƒ6W µæL¾ 0ڵ§æ1+͟!Ńvt¤”Ø–W‹!e̦ €łģŻ»!'B“›ƒ'NpCS”§ŠŁÕ‰ÓēOć~ģ}œ=}ÉiÉØ’UįAŹ9t„G×6„4§0Cääd”t§V^‹k×®!3;å•åø|ł2÷ļ‹ˆŒĄg’L”Ņ?ł™łhnmА*fT*Æ;·w¶óńō---ÜDV#ƍ7 +’”“¢ėß[ŌÄTÄ%Ę”Ŗ² ¹¹ü–ŁĮN;Ī‘¦¾©nīC7‰æŒō ”ä—ątčiTTWš éķį·W¾-J韩S¦ņ}KHɵģßæ'jē,Ū—!ˆ£³#ʍĒ™!ČŻ{wQYQ‰ ^Ša݁€PS[ƒ¶Ž6<7ń9ܼ}ėÖ®Ć$ßI|hšP0Ø!ˆ&°EE Ż$ģXņŹ{ AŠ ŌÉėąį큧½ˆźĒÕ\ČĖ …ćĒó!Ö½”——ć÷æ’=Oß¾}?Zü£~÷)³l3•aĪR ““üć…Ņ#,H‰”‚pŠÖVuwW·ŗ±”‘›~TWW󼎄]Ł®®Ŗ®āå­ µęäāeXYMįłCĮІ …B¤śĘX† Ļ«‘| epa®!Č °GRNNN°²±Āč1£¹é‡··7Ļė]˜OŻ8ļq¼ü(§Q|L:+ĆŹ2O@©¢ķć@c£ ¤üŹĻf Ņ›īk)((Ÿ"Œ‰I?dUfāåe\;;;n<Ŗ/˜oß„K—t2ń÷÷ēiÖöĮœGĀd̘1?0BaÕ]`m/„vź1 ‚„ @ż‚Š;Ā‚”@ ‚°`(„C€ , aĮ˜¼d ųŒ÷Įøń=½CŁ®DvV¶PƒĆ:ä°éĻ#=3Ŗķ:ė°^’sēĪŠ06ŌØXŁ•+W %mXļ¼mŪ¶ 50™Y™pqv»»»Č6ÜwƆ BõĻžūńó­?j`bbb°jÕ*ćCśMši ‹N]s5!ŁÅÅ„Ļļéka]‘µĢėėó}-l2UĀü1›šĪŒ3¾üņK„„… ++ ĮĮĮÜäŲ‰c=C…φ"ön,N>…”“—#!)A’ āѕ‚\‹ŗ†ś†zņ~ķĢG@ äå唳£S(ż•“ōAĖĘl€J­BII Ÿ1ø¬¢Œæ2C–ęD]‹BmY-*e•ŲųŽF¤$¦ -= ÕUÕ((ī•ÖŽÖĪż¦?äƒqŗÕŻ(*6~ū«”±u²³×ļhÅI& Ėiˆ0ĢŖ‚÷ņĖ/sWZ[k[>ē?3ńtóDjN*Ü=ŻŃŚŽŠøūqšą u—¾}¹é†ŸŸ߯ˆ¼œ<ްXVZ†šźäęHĄÕĘū¬ŌVPYé6z0?$×ųÅ_üĄef 222ųm?ƒm›ŸžÕ‡ ”J%¬m¬įģ謩R÷l"~ŹęĻgkķķķ°··ļ¹Śwwó:·ƒƒŚmP“)ųÜõ½Ć[Y.{öģĮŒ3„˜ŹŹJī¬ÓūÓRŅ0ćÅeß·/Ąų¶ Ū?;wīä铌4¼šü pvźŪ•'::šW…FbX118uuuü7¤wXŗ8Ÿ˜’«Ģ±cĒDjpžu m÷ƒ.ĪE7nÜąŽI„40Ōoݤž;wĪdL%˜[Īļ~÷;”†yėŻ»wß‘h»ŪŁ“i“Pżóõ×_cņäÉB LUU~ó›ßŠ€D0Ōc@“a)P?‚ ō‚°`(„C€ , aĮP ōėP%“ÉxG&mSœõŲܠǀ%Æ ŖN-»źjĀųĢ3…ŠģĆóPW_'”ᨭ«ÅĪ;įźāʵ¬Rʇ2kŪ׀õuųÅ/~!P\Z e›R(ćĮŗ†÷öHNOFiA)OkƒļT_̟;_(żAżś ©©‰wž4i’ČrrršłēŸ eöžc/6ææY؁¹{÷.~śÓŸ>é5RA4==Ÿģ̐„Į®źl¶¦iÓ¦q=Ļ®gŠ” ¬_·^(搘˜ˆ×^{ķI',]÷åįƇ±}ūv”ō‡ĮŽ) RB—.OO:’\¹rE¤ ‡.Żv£££Õ]]]BõæėėźEŖ‡6e›ŗ³³S(ŻIKKćĒ 6Éj^^žPƒóģz?~\¤ŒG\\œZ©T „{ܧ'jÕ'†ź lVmIIIxšąėĻņ\¾|5U5ČĶĪåƒ…Ųą6؂żgeL…ę–f””—„lXółKēq=ņ:Ÿ”3:*W#®"źFö±ł%ł¢¤ō`ǐµ+ōµƒöŽvDߊŹ<0›Š„źĀŻ›wŃŌ܄{±÷y=o¼ńļįņ¤e¦qƒ‡ā»Ūßįžżūā“Ņ'é^&ŒŸ ”n“¶“¢IŽ„„Ų4t6ąāł‹(’”µ¹óą7ÕO”Ō?lÄåP©*ÆĀ×’ųūŪßpäŪ#ųņė/qńņEųמg ˜£’²ÕųmC…]SŅSq>B䘣S€Ą%ØŖØBg['ŗŚ»P!«ĄŻ{w1Åw äUrns'éYé°é6™i[U­°±ŚśņiĻmy ēᕹÆ`é›K1Ī|L›1 ¶ö¶ŠTDIż“S˜#Rŗ“–†-[·`åņ•¼AĪsŒ'źåõpupÅŌ)SE©‘§«»K¤L‹ŅņRŸĘčQ£!«“‰\3 Ģż§¾¾.c\° ?~ėĒø}ė6V,_??,Yŗ³ügaĻ®=xgĶ;č²éĀ‘#GŠŌŲ$¾Aŗ,XøłyC»Uå8 Ū¶nĆŖÕ«0sęLlX·‹.ĀģgcŊZł •¹žCw^śźRxø{ 0[7oÅŖ’Z…uļ¬C‡Ŗ“¦Žl£o/Ź%^ Ź4?–#ōL(ŹĖʱe˼0żńNż>P*” ÕyĪ÷į’ššŠ€ķv23žxå•W(rF†ˆˆŽāmHŲķ³¶Ć‡o޼‰‚‚‚'®˜'āŚµkyڐ°6f°Ņk ŹŽ3ussćz0ŲÓOOO”Ąæk×®]B‡ųųxžd†0 ¶Ÿ~ś)OkƇ~ˆE‹ „?t9/ž† ė~cåXō£ļ×éé'&żĶ ››k”Ą,³ s:ŅĘėŸĮ‚ŃŽ;žXxdCY:///”ŒCMM ~łĖ_>qZf:SRRxZęĶ›‡Ł³g „?†ó0;7±±±xżõ×1eņó ¬žzńāE”F–Ÿżģg"E†GżnŻŗ…ŚŚZČėäųķŽßņ<ź H&€¾Ī vŃ,++㦹 ³z @ÄĄ°ŖMļÉĻ @ ‚°`(„C€ , aĮP  †AX0Ā‚”@ ‚°`(„C€ ,“ ČęÅ?wīœEŽq™śüTĢ}ič.8Ot4cŻĘ 50ĶMĶÜ>«×¤°“…¹…<-eF…  $$' ©NK‡&Ķ„kł²å=–g€ĮFɲ %LĮ¼?BCCEjų ×\„RI~ kܳļ«\_Kff¦ŗ¶¶V|Ņü![šA`ÖŁMHy˜‚ĘęF“)Śš(óŹŹĖšžŠS§N!#7…Ü*›•S(xōč· gÆR…į–Õ~oäØ ĢHźKļĖÓōU®Æ„ÆĻŗc6€9ÜĘŽŠÅÅš‹øŸpå%åHMKåó¼4ė%īéĪ,°Æ\¹‚ŹŅJ}„‚¢ČėåųęĄ7°²–ī*91c{fßѕī®nīš”›“ĖŻ`jkjńųńc¾?ŖdUPu«PRZĀ-£Y•нwń’q\–ž¦øøµÕµB†Āl€£½#ņełŲ°a r ™ÉP+J+ åÅåÜÖ92:K–-Aü½xx8{pcŹY³f‰o’•U•pté1ŽŌf.ŚŚŽŠģülœ½pÄõčėŲ·wĪ„ŸAų©pČkä8wö7éü÷ÅcģxķŚ ɔ)S›+a(Ģź)Ą«/½ ’™žXŗd)ęĢ™ƒ?ügųNš…µ5.‚­‹-v’Ļn,\ŒysęaķźµpŸģŽWæ +͟T™;g.Š Š„Ņ†Öt(;`gc‡w×½‹ŁÓfĆÉĪ ŽĪŽšõõEsg3rņrŠŅÖĀ'$uruāüRĄ”ęn0U$÷૯¾‚»»»PĆ&¢\°`Įˆ»÷ĒĪ;õf ŻŅŅņ[pu·ŗßj ³/))įucFQQžņ—æš4;¼Ģ!ø·ŽĢŻ‚Ł×hŽ:{å«T*>±({ķżŽŽWCĀÜiŸvfó:|ōŃG<Ÿ“7o7x¹÷ķœ7nprK€Uß>žųc”ō‡I?d¶ąĢ¶yž|żOĒ<X]{Ó¦MB o¾łęSgDLL Ÿm¤g.Ļ®gpp0¶nŻ*ŌĄ°Ą,čm#>RꘚtčźźāsĢKx{{ 5<Ųv±ķӖeĖ–=ig“€² !¤»ćŲ¼łū)ŠYčõć v÷÷Ž{ļĮÅÅEä˜7Ā‚1ŌyaV€Ač‚°`(„C€ , aĮP  †AX0Ā‚”@ ‚°`(„C€ , $Q˜@BB‚Pƒć?Ē>c}xš”‹ēiC3mę4Lž0Y( ,4 £G 5š_Žŗõßė2Yņ²ņ„’>Ó§Oē¦*O•R%Ō ŲÆ/]ˆ”р}pęĀ“·“ e|ģœģ°ńB øø8ĄĮĮAä LHH¶lŁĀÓ>ÄsĻ=Ēm· Ķ‘#GšĮÕ£õ«_ 50Ļk¦×¬Y#”ōłöŪo±}ūv”z ś¼žø~ż:Žzė-­ N vad@Jčbl(«ä”¢O[šŲŲXu{{»Pƒ,RjujjŖŗ±±Q(Ćņ¬}łįƇEjpž=~R;žƒqčŠ!‘śž¾ņś#22RŻŻŻ-ŌĄ-ų ŌŌÖ ?/’<ųOp÷Ū°š0Ä|ƒų„xüļ’ż/īÅŽCš·Į8qā"£"‘™™‰ØØ(„ ćyŁ9ŁāŪ¤3Έ¹#”īČėäÜ=)6.–Ū§×7Ō£„µ÷ćī£ęq(%14÷„W"®  æuuu=ŽĘš„³«2™Œ[›•——s[3VåihlĄ„K—ć„s-R*”BI³ ^c½xYŻ”FRRņ ņQ]QĶĆĀł 1sęLø:¹bõśÕšó÷CZj*Ŗ+ «’A.—sg'G'ńmŅā±ģ1ʍ'”n°ąqéā%?zœ»$öég8rō4w+(.,†½DgÖŃ6BfV&N†ÄĮ#u3 ‡žuįĆq.ō·5?{ę,ŅŅÓpżźuŲ;Ś‹K$„% %MĢ&Xkžd2lŚŗ‰_)Ų$!kÖ®Įż[÷a„¶ā&—ć|ĘįĪ;ČHĖą7K_YФ„$Œr…±cĒJvnkGkt«ŗ…Ņ łc9ķ 4Čų÷8¹8aö‹³į3އ7B± h(2s2EJwšĶčźčŅÄ5V½µ ~Süąhė'ųŒóA›ęĶg čT ®¾Žo£ūķĢdGŠn͟ƒJ»6c!¹FĄ³gĻžĄ)v ’““ń׿žU(Ķל$Ģœ;ßj`'=óÕcß×ėŒĖ®ˆ ÖšĀ4ū ū‘±|fŖŁk¬9˜kė’%K„Ģ£×®]°·×\Õ4›ū ‹-ļž'»wļę¾€ 6©kˆėmd3 ±mµ¶Ņl÷÷ĪæģŠg{ĢÅwŊBeeeųĆžĄÓĶ­Ķpuī?Ą=znnnB¼~ņÉ'Bõx>ŚXkÖO—Ÿž™²tļ±dėĻĖi^õ±=ŗšģ¶3˜ćŽ;x:=-Óü¦ĮŃ”ļ9X#`kk«V€l~‡õÓĄü4;Ķd”FĄļ‘J#ąĮƒÕ …B«åĢ™3āS=P#ąČ#¹;]`>½W{)Ąvåśõė…‰‰‰üJ®ķݻʳY‘¬qŒY…kūŁįĄ\_{ķ5”Ąū°F9m`žžOĻ顜Łŗ› ćĒĒņåĖ…źaß¾}¼:© ¬q“Ż-hs`(L:1<Ø+0AX0Ā‚”@ š’·bzÉŻ˜8IEND®B`‚’:ŒsÜdźō4j’÷ī×’ŒŃż“ØŠŃ«’ß»_ž3@ycāļO­ip‘ŪŁßMdŲ!Ž4w)$eņNāp@ć+ósŠļõ‹‰m|E§É …ÅėKRŒ0ąēēeüsĶIż“ØŠŃ«’ß»_ž3RXé2AØ-õĘ­}|éċ:ĀC$ü‘©ĻČ:š§į‹™‘įčB€&ÓQ¤‰€Ü˜>lƒŽ Į䑃Ē)­\Ķkāķ- Ó®ÆKX]‚°4`Æļ-¹;ŻL՛]{[X­mõŻI!…q®ČÕdŞ•5®–ŃjI>£yw,p¼(%€Ŗå }Ä^~Eė@k_’г«ßĖ_ž=Göµ’ż :·żüµ’ćÕ­Ed’k_’г«ßĖ_ž=Göµ’ż :·żüµ’ćÕ­Ed’k_’г«ßĖ_ž=Göµ’ż :·żüµ’ćÕ­Eaßj×’bŸž)X~ķæå„Ƨżv­M7žAÖßõÅ?§_’ĒĒżroåMÓˆ3{ņ^“K_ljPNG  IHDR„³Ō#sRGB®ĪégAMA± üa2IDATx^ķŻ tTÕ¹š’¼gņ~'„b^–‡Ŗ ÅR-^±\„RŗŚuuõ®u½]ėZ„^«]µW»śpUķź½"D”`HBBx…!/!„¼ä9!™¼I&ɼļģ͉¦cÕ[5gēńż†Y³÷™33I8ē;{ļsęŪ —!³’Rz$„ĢB™Å(2‹Q dūTØ©­AVVΜ9#-łl­­­R hkk“JŸoākjnŌH%B&ßõė׳¶żEćŽ Ķ hhhjŸļʍü±’v?æO7Ŗ—ܤ2—‘™m[·”¹½j…g Ī¢„­s"°ūŻšõõEžé|˜zMą¾Ž¾Č+ȃ··7NäœĄŠš\N222ąT8ˆC‡aŲ<Œž¾„‡†ó÷*>SŒ°Č0?qI‰IhjjBPPō“ņõzł·/cĒŽČĪŹĘ@ĻJ.–šķ-;#]Ż]šńöĮ“ؾP ­^‹źkÕ(--Å¢…‹›“‹²‹eHZœ„ŚŚZdēd#>>ž c«‡Ņ!<8§OŸęŪ¹eĢ‚ąą`铧®O€‚³ČĻĻGį¹BlŪ¶ ƽžL7MčīĒ“?|‹€±Ö³Õ ƒŚnµ”„¾šVc52Že`Ä2‚Ēžå1\(æ€Ø9Q8_t‘!‘øVs ­]­xbĖ(æRŽ’Ņø.„„cQŅ"é§ äėƒ{"qI"Ž|ēMX†- El|,.V_D[Svl߁˗/£¾¹ƒżƒø÷›÷bŠ2ˆīŽnĄ X½Ė.bÄ<‚„ųäžČÅĶ[7±aż˜n™pįŅ“ÜhĮć?…B!}ņŌõ©.€—^üƱfÕ4¶4āīä»±ōŽ„X·GŅ ®¶‹baŁŚePėŌX|×bädēĄ+Š Z‡N­:§>*œ8vźQ5¬ĆV,Œ[ˆŖ†*ø.¤.LÅį“Ć0¶q÷Š»7?sŃŃŃ!żd6©Ŗuo“|9ŠŻaGFzV¬^¶Ö6¬żĘZ$§$Ć/ĀZ§:‹Žo£ééčģŲćŽ;T šėšŃRį>ȹy¹ooZ­P©TšÓųįüéó0ųe+—”¹µ™Æ;Õ}źB ‡ĆĮ)քwŗœüī@¦V«łŃ_«ÕĀn·óčĘīl]‡ŻĮ×_ęp:P]é256_43c5754f7c620078*6’’’’7256_c7a6a9a8d70a9ee0*’’’’)’’’’TA256_a6f154e7f71e9745*0’’’’v8 256_1a2f1313ba4ba28f*’’’’’’’’’’’’7l)B®ĪégAMA± üa”IDATx^ķŚ{LSWš/Ļ‚¼Tä!V‚Ź`q‚™$F64!&¾E1Y|±żc6 „üÓiāƒÉāDŚ"Æ©(l(*åaGQy å!t®>ņŗė==źŠN[,ėłüÓó;÷ööäöŽß=ē×Zq:`Ę"YÓW†a,K cĮX` ĘĆX0–ʂ±Ą0Œ%†±`fū@ü‘x„­ £‘ekž³‡< §YN“gükcs#ŁŽŃсüĀ|Ņ_UUEö}ņä ĘĘʐ——‡¦¦&²ßLö¬÷µƒ4š\m]m“Ø5jڲ\]ź.<ī|L£©§ī™Üļ £»©gSqõŹU¬ ] ]ā [ō&%ōōō@V&Ck[+V¬XgHoKO7O(”d?žfĪMĻ%SÕI²DYŲ¹s'Äébˆ/Š!Ƒ£Ø¤QßDA÷DEĻ_=…¼Z޲ŪeXźæ:‘ćĢdÅłÅp8Šhr477C’!A®(.]Ąõß®#łd2Š‹Š!‹06:F÷ü’ą’L ŅŅÓPVU†…7 {JćžņŅ3Ņ!-’¢ąJ’R’P|«˜Ü$ŁyŁōŻSCÕ¤Ā`Ÿy“’7Fī3朁ņž¾?€]»va޼yt· ÖņÆęC;¤„‘qų'u||XžÕr\˽›;ģ¬ķ°Ä ¤r)‚—Cč-Dɍøø»`ŽÓlŲø¼ßT†Ęd?ĪŲŲXŅīxŲõ35BCBIl žśÆØØ€››ķy«­­ ½÷b_Ü>ųųÓ^½č–_ˆŠŠ¢=f,ž>}‡"m¹BŽŠå”ø$ŗ-§…½ƒ="##Qp­³³3{I%%%ÖC0Kww454a‘ß"¼x…ššpdžĻDģĮXČJepuwEȊŌÖÕĀŪĖæĄĖÓ £7ĀŹŹŠ|ötĄ'€   89.fgg#&&†F@ZFö·ŸFĘy÷ļŗyó&9ÆĄ­Ņ[PÕ©žm8źļ×ĆÖĪV_ ŅM¬±eóX[™/‰~h|üÅņ&TžQ‰°ÆM+ :>æĢ”J„o@uu5l¬m ō¢«« wkībįĀ…ptv„³›3†_ćÅóX½f5Tõ*ŌÜÆAą—X±Ž¼ßTūN^ĖĢŌ]Ó4šĖćąą`“’/Ÿų§¹§§'ķÆ\^Že ¼za}äś7…`C €æ ĶĀ”"`kk+§;Y\^n7<8L{’?L->}ö”č ‘q>VpšIEĄš“e"""h4žF£!SõOĮ/m6oŽL#½×æ }.†Ęd_ćśT›6m2ŖŽšoü­>2:;Ū·’æ0[`fę™>„s†a¦K cĮX`‹üAg-»†hsQIEND®B`‚-U#(8<ęEć“ßµkßō³’Ąó’Ęė.ŽžźļĒZrÜh·śx]2š†øxoŽ)  šāŅ‰PNG  IHDREM²—sRGB®ĪégAMA± üaÓIDATx^ķÜL“gš/‚0®FepŽ™0=ĮMļ¼ ,39/AœŪ@a(ø‘9šnč#0ˆ& ÜUØĪ±YŽ’®gę6ō&Ž‹‹‰ē˜†-)²”£"ņG°P(ŚŅ>×÷å长S m}>äMßßļ}_Źūō}}ßēiq `Ę.9ŅG†aģ+ cĒX`;Ę ĆŲ1Vʎ±Ą0vŒ†±c¬0Œ³Ų“Z-"#"įčü+«1†ÖHˆO@hX(ML‚eĖhd¢#žK 7w7šļvĖm$īO„Ū‚©—[CšŸ‚‘śn*&‹Ž M›†Fę!z‚œœ® ¤eæį1įX쓘flKÆÕćü…ó42yÆä=TUTŃČ|[C·bOĀY W,axx˜deeŃč×£««‹Ńhj»vķ¢sę+++#½½½4𬔔\ŗt‰F¶±{÷n:7µššp:g¾ŚŚZråŹ§P(Čɓ'id{IIIDÆ×ÓČ$==}ŹüL„¤¤Š9ėa· cĒX`˜y¬£»…Ē q8’0͌gõ Pażśõˆ‰‰Aä®HÜi¹ƒ˜čœ»|;"w`õźÕˆy3ķ]ķh—·#żH:æD*š„ŸļģźDAA >,@tt4’»2³2”ŅņĖmA­UCT(ĀąŠ ĶXʃīųęŚ745¢ł;qŠŹŠ ÖØi4?UVT¢»·›F£z:zPv¶ Õ5Ո؁±;ѧģ£K­kddāÅ4²>„J‰O¤Ÿ +3 ”ŪB~ŗ`›\lٲR©Éo'£­» }š>„’9œĻAZ"…×R/ˆ?ĆĒĆżżŠėōXŖ] Y½Œė·ąX§Ó”“‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™šž’’’œžŸ ”¢£¤„¦§Ø©Ŗ«¬­®Æ°±D³“µ¶·ø¹ŗ»¼½¾æĄĮĀĆÄÅĘĒČÉŹĖĢĶĪĻŠŃŅÓŌÕÖ×ŲŁŚŪž’’’ŻŽßąįāćäåęēčéźėģķīļšńņóōõö÷ųłśūüżžž’’’“”ß.ö/±ø\}™>ƒõUW—~’ÜY¶Ó®[Ń …8QtyYyˆ’k<¾Ŗż UŖ »)CīßsqįÓ pt˜æwÜėßÖŚ« É x-ź5œłā ŅņŅpQz J¤ˆ‹‹CSSŻŹŗœœœ0ØÄPßĶX‡F«AÕ„*¼õ··ō|Ä’c…ß ŗt2›%åååŲ¾};ŅßMē_D½ 0@RŹ%\u®šōGé©R>†/ωķˆaCbĢųŒg– »mü;‚5µ6“Āmƒå{ģ+ĻWBą)ĄłÄķƒ’jxj<‘-ĢĘŗēÖ!66Ū¶n楳J£Ö@ŃÆĄ-ł-ųyśįųĒq§ž|>Ÿ#nw:;;q±ā"čVÖ÷Ā_Ą×ß~M#ĖŅéuĖåHܛˆ.m$§$Xé» , kLmŚ£äZÕ5ņÕÖz½kÖ¬”‘‰žč”PˆśŚzŌ4Ö@ēØÜ ē³Śō\Š^ܽÜ140„ö¶vx,ö€ĖB¾p|^ž9 ąĪÓśM­MptŸ›zVRR‚«WÆŅh2īźc"QĮ‹xŃčŃÄĒĒĆŁŁ™Fć)•J$%%ŃȤńĒF¼ń›7ąż”7ž\ņ$d7dxńłńōSOĆĮĮĪ®ĪP%??[ׯ_ēoƦÓŅŅBēf'77ÅÅÅ42Ńh4Ų“iLøw¹E®‹Pó] āć!æ-‡ļ³¾]“ĮÓӓo“Ó_œ†(OƛĖā ģD7oŽäē‰ø"¬yōŪŅŹŹJ¾p™C=¢FĄ3ČÉρ÷2oš}ÜP€%L7 h8±Ipp0ÉČČ ļ$æCd2ņŹ«ÆšĖTƒ*ņzŌė„č1TuҧźćóÅ'ŠÉįræé>14(ÉČŹ DzŽ‘£¢£$55•’]ū’÷Ćåæžl˜; XžY9łį§hōpę n…Čį&u?ÕÉY ¹ÆøOŽf%žˆä‹ółuŹ’]Nšlęēg˜a@CQ ­­­4z8s†ė›źÉ¹ŠsäxŃq2¬&’© u²:ņņ«/“﫿'~ž~$--ä‰ņˆj@E·š½™J?–ł=9n6ƀż÷ś‰(_Dņ„yD”TŠģ(­VK:D£ńlņ9®±Œ“16š.76ęsc§¹`nčč#Łļgõ°šf~™¹Ÿ0ī§aG¹}ē~Œł9jŽY ÕPīY¶MÜW¾-&Lsi&€; ¹¢<“æa.>šsĆĻdļŪ{ÉŁ3g‰įV‰ĻżR°IwyjœŒ±Ńt¹±1ǘ;Ł’‡›23ą¼pźKś¹bÜOƏ>rūĪżó6nŸå>XžŪå4²¬‰ūŹ·Å„ÉV¤$¤Xżošż/Ĉ±rÕJ8pW’;ż­,gžvŪ€³“³MŗĒ­O¼Ē7 c«ŽX®ćoĆ6@˜'DĒ­ģOŪO—LĘ ĆĢSOø?Ø=QČNĖFŌĪ(šĻb_āzp¹1żĄĄÉ_ņxœ©Õjl޼™ļ”ŸĪڵk±qćF™§¹¹43^cc#? ąķ=ƒŻ9ʉ„F“q=ō+VL?Ęü(z{{qšąA„„„ŠŒIOO°jÕ*š±­7n ®®nŅNff&īŽ½;ė+///ˆD"Yū·ą cĒŲ-ĆŲ1Vʎ±Ą0vŒ†±c¬0ŒŻžˆ}”˜,ßIEND®B`‚zmKN²Ō’%½€J!“Ķˆä‚“®ąG ķfBj·ü#śWüń›’d’āØŸO źńé7YÉgg{q¢Łi >+n£ß½b‰PNG  IHDR$f8äņsRGB®ĪégAMA± üaŹIDATx^ķÜ{Pך/ •^«2R‘ņˆ8Ś+S°^Ń20¾®õŪé8S’ŠśhqFv®õ‚RŠb©Š“Nń*«āTE@¤T­5 `øj@ˆX1į‘šČ¹ŁĶa¢Mø*°NĪgfg÷w²9Ɇä·{Īžƒ1Ć06ID× ĆŲ –ʆ±Ą06Œ%†±a¬±š¬X†bY1¬ÓÕŁ…•+Wb„óZb$+2Ō%ļ[]B$²aķŗµ4z q €a¬qčŠ!ŗe½k×®‘††™ō§.!zŻƒ5ʆ±Ą†ę¹†nMϚø«S™tvvB&“”žq=ß¼ŠhLϱFkK«ÅzmKŒ “w“cõg«q³ō&²Ļe£¦®w•w‘’K>JJJpāÄ žĒæ=f;ÜÜܐ˜”ˆš‡58•y r¹͚fO;Ž{U÷P­¬ĘÅ܋ɑ‘žĮ×’ė„_QPX€˜˜(ž«ĄŁ3g”ø­Ą“Ę'8Ÿw7nÜĄĻē~†žčłżm…x‡Żf^GG’ĆhniFs«aįֆ„øØAAAt/ėŌÖÖ¢Kß½^’R]\'ąģ Łt/ĆQ,†ŖQ…GõéU)ä·ä˜ę3 999˜ś÷©PŽQBā-ŸŸĀę…AQŖĄpēį(*.‚Ėß\ąéቓ™'QQ^…,„ņ®mŗ6”•—į‘ošūpÆŻ®n‡Ė›.ČĖȃ¶]‹iÓ Æq6īžīšp÷ąß‹µŠ‹‹1éķIĘćj6,/c÷¢ļŌĆi˜}†°°+ĘLéĶR\)¼Å rÓņøī1Ż£o*PČ u”–›Ęõ憗ėŅ“j ꁓŒs±ƒb"†«›+,^€{÷īĮ×ŪõėŃŃŁō“éhxЀАP  Ć„ģKØ®ŖęĶøńć y¢ź®žrĪƝį5Åːe ÉMہŖŪU‰EųIŠŌք‘.#įį偲[e€}CVāš!üēĆ[÷ēÅkw™a‰ßO÷–3Üūż÷>?į LĖß)t£ —.šW ½  Fų"C\}ʵÆÄ—>jdßi}‡sfĢĮӖ§šŸå€€ˆō"¼åžŽ™ś<$ü™<6.!į!L“€č ‚ćŻŁļ¢²¢³‚fĮo†&Lš€ŗušõóEhp(Ž9ŠŃāŃ;‰ńńŖ‘1óēχæ?\ßtEŻ£:øūøĆĮށ¾#ė88:?īŲŗ?ƅtMĖģģś˜U/€a^pżśuR__O#“?ßņŅ“hˆįŒK#ĖŲm@B¶nŻJ·„‡]0ż6rÄHaŸŻ˜^±‘€Œ©T OOOøŗŗŅ£#GŽ ­­FÖyųš!6mŚ„±cĒŅ£””hµZ½¾ŹĖĖ‘œœL#˶mŪĘß}"–3=%¦„œX€alK cĆ“ ĄŻ#ĶĪĪęļŪ5GG,žēb™Ø›ÕČĻĻś8ģ½ļa’Ē$™äę¢å ‹H$BXXFEK,cM€W«·&7ņ‘Ō ¦ūM§Q’ hąĘiēååaɒ%“d褄„aŊf½Ö\'޽½=¼½½i‰u8€7ŅČdĖ–-źąŹū÷ļóZbKÆVo !!ėׯ§‘u¢££_IæĀ€7øa•C¾üæį–öļmé w–µ“æ.Ń1ĀӟļLč»ōø_{ŸFF¬€al€ŖN…m;¶!>īåaɃž¶ļŲŽÄÄD|¹åKääå`ٲeŲæ?¾;šöīŻ‹˜Ż1Ƚ‹øų8$%'!#+E„EˆŚEkX\‹(ėt:;:iÉ_ĆŻėV*•xŽō»wī†ź© OTOč£ c®@Zåm%žšgMϐ|$™Ÿéø+fʏO1ōĄ]¾pķmgGg„‡…#hn"##1f̾ÜĒĒjšī<ĢNz'4Ö6¢½½Ö0°ž«ŸĆĪŃöÆęr™s^ZQŠóēĻcāä‰Ųæ{?4Ķ}›ĆĪŲ–™!IiŌ?ÜŌé3§ĻąĒ’ˆ?ų«>]; 3zķäfX„ž'•F}£Óé0sęL,]ŗ”–{ö ņ³Hdēf#0 §ĻžĘēk?Ēń“DZhį"$|“€/žõ~8üFOhź5ج®DTT’ÆRSSQUUeÖ ØR©ų‘jŻ€µkq§ģęEĢććžDDD 00F&8xš æĶµ¹®]ƒ\&‡——¼%Ž(ü­‘+#łĒ7£...&L %–5©›0|Ųp89 s ė놛łčęźF#s...Ų°aŒW”©‡SńÉźOh‰9ī7ÅM‹ī‰V­…ėŪ®X·zœœLG®ƒś„Nj. µZM²²²hddø¬'ńńńäėÄÆ‰®EG~:łŃkõä\ö9b8ĖĆˆDEG‘£©GIzf:)Æ,'æ_ł>|˜ÖŠ?ĒŽ³8q„¬¬Œ.ŃiDˆN«#§ŅNŃØg tėe/Nüą^ļūCߓŲobI~^>IIM!ŅėRśčą«®®&%%%4b„bß¾}tĖØ¹„™dfdŅČ2k&Õ(kČ·qߒ‚ˤ««‹/3œDłu·AOCÅŚĄ‘KåD«ÓŅČ2k€Š° LN—Æ\&ŗv,ėĖ÷¬ņV%ٽ‹((Ķ» `AĄ?Ųå/3dęĪ™Ė\{U¦LŸ‚ƶ~Łeßæö"–Ęp}_-’ˆļzрŽä:wīÜ)ˆ(Ü®‰5묫«CRR?£/BCCL#īnmm„‘°p’.k͚5˜8q"-a„`óęĶ}Ü3yņd,_¾œFżĒ¦3Œ cM†±a,0Œ c €alK c³€’9ƒŃĖ˧¢IEND®B`‚·f mšąĮ–IąšNūa„‰PNG  IHDREM²—sRGB®ĪégAMA± üa@IDATx^ķŻLWš/»»P©öĻ]«m£{ÅŽÕĶ—VŚÄ¤^kÓ¦R’$¢%¦—*W„ˆi"‰åˆ¤Tą8Œ“Va•„žiX\˟ŖÅȉ. Ų‚B’*–½ŻŁvf_g†—Z®–uüĻĖ˾ߛ7,; æłófĮČĄ0Œ&éč#Ć0ÄĆhK £a,0Œ†±Ą0ĘĆhK £a,0Œ†±Ą0ęÕ;EQīƼŠĒžņķіžėżČ:E£±Ī=ŒŹK•Šėõ“dz$IĀ£<Šw6½C{ʶ!rīłĆ=4š~š®6įĖü/i4>Ž’·Ķ§nŪtuv!%%÷Żķń %x‹Ėå"‰‰‰4ŅžˆˆŚŗ¹}ūö§ÓI#Ļć8ޤ¦¦Ņčę"##ikzZ·nmßTo›“'O’öövy;` °ŌY°ķŸŪPVVF{†łLhmkEQQŖ.U©±(‰ų®ü;œ:u vĪ®ö555©cjkkį]Ø©©Qū•±‹EmOwŹėīlė¤ć«:Ś:hėö„å„ŲśŽVœ/9U/­‚Ūķ¦K‡łDØÆ­GęžL,^¼ęÓfX.Zp ēĄ ,Ąö˜ķ’KZbš:&/?¶>ŅŅŅŌõõD”])j{ŗ«®ØF_Wn掁^“4¶ īJr:‰††µ_yäyMĶMØ8_ĘqīÜ9u™Ų>ĻśœFŽåt8QXTˆĶ›a³Ū°3ļƼ‹»gŻMGÜą ąĀå ˆÅܹs»%sęĶA„ϽšBCCń@čųéǟąr ··«^_…Cqłņe\Ø»N³…>Ųl*2!ģ‰0Ż~»3wćės_ćxŃqōōõ čxÜ¢9spę«3Č=–‹‹/"ūP6šŪ›q¶ģ,]sz C·­[MŠŽr½’:²²³µ5 3Cf"=7o¬x!w„Šæå €ü䢊ÉE/éᇿ+tzśC•š˜ ēĄ·ÅßŖ‡XāLv»’C‚Ī­óźĘž·ä/š8A}‚ €ēxpN/€spā‡Ąńœzųö’»<ŽĪc†~ķ™qHTŸsĄ:€>k¬Vė/ķAė ś­żjUŚŹ©Ēh‚gcÓ[›ąr”½£”KBŃüßf,zrJƕbĖß·Ą)8½)v‡žéAŗ¦o‘D Żæ­]7ÆĀ@æŹH’K‚›Œ<äžØžžžQŸ[©m­mų(ł#$lOĄ’'–Ą“ׄeĻ.ƒ!Š@מ}£NīˆßÖŽVyŽrž±pįBÄĒĒӞaµ?ŌāČĮ#ˆy?9¹9XśäRuĻöē0Ģ›?ģųŁ{²±ł½ĶHŽ™Œ3eg0Ń|¤'§ć`ĪAš"ˆõ8rųōrńUO=żžyöųłū÷ća2Ąč†KrĮ(! Įėx4^iDį±B #ßÄØQŲóéčü&—»N'V,[„[Š»Bī‚}ŠćFøä"ŹÅ 8#.½ r9f>†ņ²rŗö0%”)Iyćū±ūćŻĒC?„ĢO2±6r-²?ĖFzz:ā·Å#é_IˆłG 2>Ķ kū–×^y o®y”e“+ū«\•§’‹r%W§\•\x§\’'Wyæu(’Ģߘå`¤‰;·=:ŻäŽ+³ŁŒ†śĢž={Ō£Ü.kĪœÅŪQoćŗ_DpP0]2ҵk׊ŅŅ‚åĖ—Ó™’¼e¬iĄļ¾W§¾J‹KF ĘHU©ųčX‰PNG  IHDR-A7µ:sRGB®ĪégAMA± üa šIDATx^ķÜyPSIš/¢ąGG‘/PvdĒEuńWGݲvWkž™šņ^¬µ]/ŠA(Y•U@Å*u))-µœ (xāžhyd劀(„#H ›n‰‘@‚@~|õś×ļ„“Hś—×ļõĆJ«BˆEź ք D € F € F € F € F € F € F € FH‹+..Faa”ˆŚėÖčėŌWDķ%Ņāüżüįīį.¢¶A-Åžšż"j?(·~żzlٲEDm{½ģu·7t€ F €“ ŹR%Öų®ģ…LŌ¼#%Gę‹LS¢@>¹ŖŖ*„„† ēyā¢ćą»Į»÷īʒ%KT)–]wńĉPNG  IHDR±+“csRGB®ĪégAMA± üa(žIDATx^ķ{ōeĒĒ̤ĀK&–Š©% *‚‚\L¼Hjvźėt:y:Ó?žč<ŁQóR– ØÄE¹ ¦ų‹¬@⁂ ^0D.^ŠŲęó8ļ—eŽŻywwfwŸĻ9{vfgfgvvŽē½<ßēy*„Š’CvģŲ<óĢ3ĮĮ}²?l>|ø,/Z“ȹ_ģŁ³'øōŅK£µü¢@É-/½ōRpÄGGydōÉžüķo ¾ņ•ÆČņ£>\vŁe²œģkĖ3‹Ž„ix÷Żwƒ’żļĮĪ;ƒwŽyG–yķµ×dµ³ņj”¦b×®]ĮĀ… ƒńćĒO>łd°téŅąÆżkpóĶ7Ėūžš‡`ҤIŃŽŠv”Ü1{öģąć’x°eĖ–ąk_ūštÖÆ_tėÖ-Ść#hfSąš}ŌØQĮڵkƒÕ«W'žxbšŁĻ~VĘ čF<õŌSĮńĒ/ū²~ę™gŹr­Ą}ųį‡ŃŚGйīŗė‚O|āŃ'Ł£  ”Px\ŲT3f̐‚’5;wz÷ī-˦’œf €ß–‡7°råŹąŒ3Īć–Ō4!å ģķåö­ö ž¹¦7ß|3X±b…³@æńĘĮ˜1cdyΜ9b,ņ¶mŪ¤õb£@© i ĄŽ½{ƒĶ›7ĖgŸłĢgdķӟž“<Čo½õ–,{ģ±Rþ’žū²?ĶļēŸ>8śč£„‰>dȐ`ŻŗuĮi§|šĮA§Ndšķ󟒼|o)ā @³‘G ƒ€Š@AžĒ?ž,[¶,xüńǃY³fS¦L ^xį…ąõ×_žóŸ’Ė—/|šĮ`ńāÅņ0ół9ēœ#ĖśŁĻ>ūl0ž|ŁęĢ™2§äm4·Żv[pņÉ'Ka¾ńĘžŚ5kÖH­cĆ ŪA$Ė4›©m_|ńEłŒ+j}Ę>łÉOŸūÜē‚£Ž:JšŪ/æürгgOܰ­ö=餓‚Ż»woæż¶œŚŚŚdœļ<’üóå³R˜kZūXóÕMÜs߁ū÷­o}+ZˆŌ+’©O}*Z«ūģhĖž<÷ÜsĮ¾ši‘UoĄĄ~Wzxčšµā¾éŃ£‡ŌP4yh†ŅŒd4÷¼óĪ“&Ž#<|ń‹_”&$µ5$ĖqŌ¢ł`_…Žßlco»v|Ō‡~x“Č}¤ÉM¬¤ \üĘ(ł’lĄ{÷īŻ£=>¢–Ą»£ÅÅ µ6-j-Nbśē<ÄlėŅ„‹Ø­(ų įÓ„•@ €ķŒŸuÖY"Ė7nœŒ0³_Æ^½œžÜyóęÕÄ ¦…A1”]š÷æ’=4h,¦N*÷0Ž£G¶nŻ<üšĆĮ1Ē#–ŸÖ-"ī ­$Z“„øGcxēą}Ą€ņ]j5 ]2žZD?Rģ²Ge¹aĆgåųꫯ×\sM“– @mmmŃR< .Œ–*'|Š aA),[¶,ś$宩ޔ»{»Y\!,“²üöŪoĖ{Zņv?”t„]åŠ+¢µ »…°–ÖÄē9p¶āś¬6'N÷O=”kQ¬®Ź’ööö’ƒmČ[ūõė'ĖhĆĘT“W^y%ųö·æ­) -ŗƒ“ ćą¹æāŠ+œ-€reµ© €¢(łĄ§¬ŖPQZ˜Ō-€¼ų¹ü/}éKĮ 'œ}R?øDĶå‚&›QĮį%`„ßåŽCE7bĈhMQ*Ē«µŽˆ£ÜĄBšAĄZšĮ–,Y­Õ—r÷ČŽ¾zõźĀūļæ­ˆč)ińyv¼»įÉÅM…4˜åU«VIDIM A#øż.A¬‚«ć±Ē“ \`įuÓ§O—ujIDBlēū°n„ä¶y ™JĮ„ĆoV”¬qv(ĄdUqĮE >K“īųų ”_pĮ2źˆČ0BI’łĻеʁĀĆ 7HxäO}śDkBaĘ \!ˆ #ĮAčOĪ2;…a £ś /ś7Šč $ßCa'¦œV}ćsĻ=×xÄqˆpŲ§Žüė_’źŠŌÓzĮ€ŁąŃ·o_Yę>!|āž`q”rÆ “GQ’`?‡‰ĮÄ€h)žJĘž `(Õ÷}ļ½÷JŠŹ‘—1#ī±±·ŪcåöU”$ų<;©½hŁ]Ā…zĀåG^Ŗ»R+Ź…ųŅ52įĖÄÓÓ pueČŗ3räČhMQ*ĒĒ  B Eip|ŹŖ „…IŻ`ąø<@RŹāXüz@.=Ēwœˆ”€Üt·Ū ū÷󟐩Čuŗ%żū÷Ö”fĄ«µŽˆ£ƒ€õ"«“rēµ·—ł`ŸgėÖ­…—^z)Z;gžy&vRi\|žļ.É$™~ æ6‚ D? v’OŸ‡ē‘š’÷æ’żo‘5· ŸóĀŻĒ¾0Ć͈»¬QąśóFŅÄJėįmhÖ"r”ŁÉ‹‰HŚAŅ –irR°§M›&/ōóųĀQ ’,„wŽ'#Ż T €+IbA³P)Įūļæ_ī"&DWxU0žÕ„L1tSŅs ).Õ±Y *B |¤CŒCĆ燻 „ŸÉQĒäŒ(Ż0~pŸQk’ćȌC?™×öķŪåį½ųā‹EYXrŲ#>Ŗ7™®½öZ¹GŠūap“}ĒŽ+÷†üłĄ½ «÷ĻƾśjyOŠżū¹—ŽP"Āā»É½hĄ`Ąd§§Vž!²j„G¹~E„B ö k8Y®>} ģó†µw““{{©1€W^y„¶x¢µäŲē±Ē6oŽ|Ą}×1€ęĆēłOķøżöŪk>Ćj„ŲsÄÕ›Jå(“3‘׍ęx-¦…²?ē gØ6ć-äs ’”ĘĆĒ  B Eip|ŹŖVŠŅĀØP”F»Šß.•˜°g356!ĻI’†T YĢ'xNvĮxEASJmÉd ą×æžõ³Ī¦W•™\£Ń`°Ķ¤żŽ-I@QnŠ4n¾R ½0‰HųĻLž8˜“×ŖŅ\xUÖ€8ʹŒšµ×^+„waĒŽ›æiÓ¦ĀņåĖÅåõā‹/Źä+W®,lÜøQö/ĘĒ…‘5öµļڵ+Zڇ½=Ī X|ŒÉĄä!•bŸĆ^޹sg““F¾×ŠŸ’Õ{ õŹ6²ßŠ$FцŠdΜ9ņŽäQQ³Ć=ؔŠˆ · ÷‰ōh('¹—¼U™uÄD(™Ŗd•’äz”ÖÅ[ ȃyÉ%—ČCJ?ś|ÓōIĘw0³ i¾ŠA K_¹±•€”E¤K HĪD”ōŻ1Ģˆ ˜ę9ĖĢ‘ˆAetōķgΜ)ėÅóŚ34ŃĶųĮ~ Ė“’ÜĄyķ4dJs[%`%4r³Ō¾öø<{»ŻŲ°aƒ¼Ó}"%šö9Ģ2ź?ŗ_Å4ņ½VÜųüÆ©i¦NDhAs·8›n£@3Żžßæ&łĘ7¾!ĖŌΓЪ­Dū?|ųpY¦fĻ*[ ^ˆėÆæ>ZSš…L¼Œ>W Šé§Ÿ­)Š’”L €¢(łĄ§¬ŖPQZm4LˆēÅ34zź©ā­I’ÄÄ3&NŃ(ÄźćUV1qčˆqcRī3۟|ņIyÆµĢ‰Ųźų”U5NJøš&”"|Vd^G„¹P H’4ewß}wpēw3f̐XD^S§N•˜ŽÉįØ4jš²0Sˆy‘yČ­ˆŖ°äĒģgK…ÉLjBå s0ė—æüeQv¢Ņ$›ŹÅ8%gŠ|0¼’tŠ āGqDĒ“å{öģ©I802`joó_™’ BHüY, 2Ū‰ 0`@ōiķAÕ­[7‘(ŪϳA#˜r"É©āʧ¬¦6Õ ®6ŌTčå»vķ}R;ŹŻ#{;€L½µsžry i 2DZõœĖĻÄ׿žuéNŲ÷,É=TāńŗG€8Ź,ŚįĄ+V¬(¼õÖ[…eĖ–IˆėŖU«äõ—_~Y¶…MŅĀŗuė$tŠ«“Į–WŲ„-„µi!lžJ&[²änٲEBZŁożśõnĢyā4÷6åfĘ©&ö=" ŗ{{Ü(8”Ņ6üöķŪ·Ė}ØĪį3 \oŠÆÕ^ūŻōŪ²ĀēyФ£Ģ µ ³žüń‡Õ ³|†ĻėžSŽ£9eŹ”ą/ł‹ō KĘD!hŚ ™%×>yģŁ—h:ę Čc>{~MŁJį>01ĒL˜0!?~|šÓŸžT~+MsjēŸżģgkpĒw“'O~ń‹_Hčp3S*›‘Rœ]€$įĄģĒaL„yČ!‡ˆ! ) (‘  Łč6ōéÓG޿馛dŅ Ā]Ļ;ļ<™NŒfiēĪEØō  ĮÅņˆ#DČā‚ļĄP*«Ö˜p`ĄX!t±q…3‘ļ:u’p`&„ÆŽ„K—ŽĮ; 'aÕgøWŒеa_›ßżīwҵČbb”4„­Įż®•ßOšrˆ— b1iՔx*˜I)š^&ØØYučęco·»4ó.€ļ„)>Ķæ<ä*ńųܣԃ€øsŖ\mhŠR V¬5I™ō”.QµĆé·< ŗ5xK\TfōčŃњ‡Ļ `j`ę·Ė#øŽŖ=Ś®(y% (J>š)«ŖT”&u €ŃzśŚY€g!É-ń|0Zļāč£īKįŽ$覚0½ø™wÖÆ_/ÉE]šåqÜFń#“.Ą¼yó:d®õU.Ȭ)wģķ>’‹āļLr=Jóąóæ¦īą«GšĆ4ŌŌD¼ļŻ»Wjgü¼ŒŽdĀ‹ō×Ō†lG¦Źq¬sZojsüŻ‹=Ā×Ķ>®×”‡]E~Ąū”ā\ZčøO¾ »P”rüːhy?h˜|óq˜ķX„*K—.•H4Ü\,£īćē3 Må¶¶¶ą”SN怎ü÷<š€<ōe®a[9įG¹k«öu<żōÓ\“½Ż^FłĒż@ķČd+V¬U ĖøõXG ˆ  %÷—#Ńz¶²ų>ŲėX6Åū+́ϒźģ”S¢č9r¤<¤ŌāȁQ’”ä¦@­ŽA @c$ŗ^yå•2A%‚ÓåĖ—‹ś¾,Ż "ƌĪF£ųįĪ‚$J@”Œ£F’q€éÓ§‹”掠œä÷ó{Pb0ˆDó”ŠćŠšnm0¾6tĢÄ Ģ64pą@Y6čÄ ĶI&J@³eģŁ³§cn»ša-„®¼óbolG©Ē±’ūńóåšQ>Uū:ų]ÅŲŪĶ2*@ó{ćŽIBń}°×Ķ’bS¼æŅųüÆ©³PŹņÜ6LßUJŁG‹ˆ)Ń œj0 dčłīwæ­ŅõŠKb •6f̘hMi|ŹCjĄĆ–fą«@Ō£GhMQZ›L €¢(łĄ§¬ŖPQZmxāø}˜Qūrłń~Ēś+J%dŅĄ—}ņÉ'GkõQļŽ½£µl˜;wnÉPVqżA¹ūłč£ęBŻØ4^•5 Žr®…“ AŖEÖē‡$n7³Œ;tŪ¶m²l“‡ß£4&>n@ļ1Ä;3gĪ”É$ČHKž€‡zH=„µˆn½õV‘·"j¹żöŪÅ}F.A2Ś"źĮ£@‹‚ļį;¬š½õœ»Ī~O%Š% æ¢äo°sēNéߒÓm?¾n„ø)ōØżpŪ”ģ ŽD’™0R`ŽQ§”†cŽA5ˆ.ž‚F€ß•$2ŅVó)J–8ĒHö‰ü”…œ>+3ĶPP‘ō"a„ĄSƑ’kƆ "GEžŠžŁ+įŖ={ö#€„˜ "䲋p9+RaüüčŁO?żōčŒūó«_ż*³hD)¾¾÷½ļÉ2F°xęœI“&uŒšŪ¾łĶoŹżdl€YzmHT”¤š<Ł‚°$¤ĢzŠ*ƒfånM©nž1ŖAEI‚Ļ `j@@ 5zVą 48KÜ”«ā‚ (Ņ]ŗ6.č­(IÉÄ(J5Į8ŅŖsÅK`@‡ &± ,›y'²„ÜĘĄg‰„į”@“#ĮćĮŲb)ʞņņl6ĆuØXihˆ%/³K1{ļ (3ˆĶ 4ž&^ģCÜcBZ,ó9ūš¢›qÉ%—H¦%śŽ4cŁušŲ<ō‡D£ßÖœ¾7ĶvŽ}»00øŪL€ęs§Nd¹Qį~1Ƚ±į^<8Z«>e5µ ¾ćŠŗĮł/¼šĀh­žąV"ŗŃ#Äżśõ“e\L<$ÕÄōA „R:“”ƚBāGŒ!Ėx \Ń­ŪīŻ»;’ÆrdbźżąÄ‘õ5$¹GµøÖāļ4! ^Wl5śčŃ£Åą÷®ēd!øåpįqīfĒ6 \>\–‹ńDōy¶¼ .$šžųOńĆbÉh^¢“¦ßH8/.'öūóŸ’,%y}%gĶ?FxIńÅlBfÖ |ƈ8Øį]©æjQؒ`ŸŸ~sqŠ4{»½Œšh”iü~üŃü ĢęCķHӑū„Ź‚B3œ&zŸ>}äxCńļ7@Éq€’œY lX+€g…Š€w×¬ŠŽķ0š/]»v1ƒEōƒ(üųt™™}xĄ)šō’šC³MüĀęE2Mx¾żņ8h1ü6ęg«ŒndPāŁ0–V(č< 4łżÜ—É“'˽įX„±Ad„Ø%<ˆš-Z$óIņ ¹8·Nœ„P×Rƒ=X“š’QūŃ'¦§“(„A$Œ}UF˜)ōĢ"LK‡™Z~1żAŒƒU|Œ~^ާ%Š·o_9O1¢rj­ZB_ūūß’¾,ĒĶ Hŗ3㯦•3vģXłó‘”ņĒŠF¹Ę½d¶d^Ü7šč“†Šć¾pÆ8®8ņ ĖoApū/?0Ąj¼&üŒ×`Üł_ińhÜ}÷Ż©“ģ—US£› …i·D “±”ó-ęĮ›õ5Ųē Y““{{-®5’Ra!”÷°²•w_AÜsĄóųųć–.]Z˜5kVō遤(7/^=(Õ·©L N3Żż<Ó*ą~VŌĢSņĻ”)Sœ£ü“h)§ńŗTY„ĀsāJ7§:Eip|ŹŖ*„…Q (-Lź.i°‘œ6"ø-Óö·lL6x9Lߋ‘^\3.pūł„¼ŗė€8Ź07ņtµ®=É=Z½zµDÖ¹häū©d‹Ļ³S!Ź?ZԈ¼óĀoĶ ži„2X*£‡gyŲØy±ĢgĻ?’¼ųĀ ”˜c“IEųÆYĪĆ:ēÅēÉd#ģƒr°½½]ö«7„b FżÅu+Jš6،֬Y#…į rV^&…'Čdł ĮqRPéF †”ł‹Žu¾‡ļ›6mšO 2ŗēž{ä{‚¤˜uĀS™_Yz™§€å∬zĮµT ¢Fķ>)Ķ…s €xšR2\‰†ŠÉ@‘±Ņ ŸqĘRĖQ›£o¦’Ėi(ŠDĒń½l¾åS…QćcL(Ąų÷i5 †Ćh°Ž1łÉO~"€Ģ1HcO=õT9C9 V’žżĖjŖ1TÕ ’ķµ×Źo£uS™ˆcŲ% æeZØ Üb%)“œĒ­%G’žmČ3žüXå\)BćRX°`AańāÅŃ'é©VŪžž° -ķĆŽĪ@Ų]‘åøl=Õŗ&„õšyvR{J)›ņ­ŽÆ~õ«ŃZzBCVr:/Ÿ®ŗź*YFĪ8…K=IĖÉÄ(J|¼ŖT”ǧ¬ŖHQZ5ŠŅĀhĄRo‘ŠĆ™~Ž9ęYĘ{QJ5ˆĄ±„(„Čd ąžūļ—¼Y@PtÖYg‰k±Ržxā g²@—pŃEÉ2ŗAøt č$˜ŽJQ’āUYcā(ēZ0ŪwīÜ).ŗmŪ¶vķŚUŲ±cGaķŚµ29ėlŪ°aƒL,a&—0Ē‘!¬A +W®,¼ńĘ…uė։\öŁgŸ-ģŁ³§ć»ĆĀSŲ½{·ģgŽß¼ysį¹ēž“õ°&7Ū /¼ ūlٲEŽMūÆY³&Z« ūq}ÅŲŪm7`¹}% >ĻŽ÷I1HYEvŁI“&IśkDDĢ9‡e¢D„pē–[n‘f3 ’%a!""Ō€$Ö@ HMHŠ#Ņ‹įjä{ÓPŪ"2餳œćQņŽ<q iÄ$M:µCv\øöJA­r`%8»dü!Ÿc³ØīČ3†l—Œ#a téŅE $Ŗ<š³³fĶŠ7üå–/æürÉü‹†Ÿ¢?pą@ÉČ÷е@݇E z¶‘G•!żj’fRŠł %„mT~ųÜÉ1H–ŻJ ę€äœIņ²”t¼śź«J@äÉFqH¬šŗüśüĒwœl œęóSŅ€J•i*0qЬ łķzŁĶÖKao§¹Ī±”1ˆ>łh»y™uūó°ö”ćięļ|÷y9čŠÕ0ĒWņ²ļĮʍ£„}Ų÷pÕŖU]€Š`É»½Æ¾ō•äe?‡II=č5šChP3»¦§Žƒl«„Bi%3F–dŻ„¤ŪóĆž0ZS”Źń)‹© ŃoĶŃvī¹ē–”ö*JÉÄ(Š’|ŹŖ*„…Q (-Lź.麌Oæ‘aj®“S2įŚcąŠnQ&Gܛ„“ö$"Š’Æī: Žr®×CžšłIī‘­Œ£Yī§R|žļ.®­½{÷vŌ†ˆ{Ā Ö®]+“\¢D„ś qŽ™E—m“ 1#0ĀŌ}× bū£"ÄĀq¾—ć€ģĻ÷“Då DZO’ü|Ղ”f•’d_E©%Ž€‚Ž@Œz‰/Ņ^ŌI .‰0Qn”± nŗé¦7’]$¼H‰Ł—ķdŠ”š’aĆ0qāD)ä(üų~vLžBŌĢ–Ė9żŅ”'/!ēĻbJqüü•Āļ+EØ(õĀ9PiRPjtŅ]Q°™ś›BxĄ€R°©IŠNŸS±. gŅž° ›õŃŅ>ģķö@¹}% >ĻNj/Ąƒ>˜(v>Æ0Ī@pRŹM‘޼ųŠ+®ej}Z8®Zž1ė®».ZS”Źńń¤6 ¾9m(/6!Ɗ҈ų€ŌO>5µ_£æ“š+­Œ>żŠŅĀØP”F €čpYŗ^Œ“/‰ŪĒ~)J½I=8{öģ¦MaÅø€Éę[ “¶/æ< h%a Ęā !Čw¾óhMQ*Ēg°ī:€Fąį‡Ž–Jc߃?ü0Zڇ½ŻÖ”ŪWQ’ąóģüːČģ>ėR 9³?‰>I؉,˜Ÿaķ>ź=”}hżÉŚK-‡oœd˜H€É(“`ĮQū±²^²å¢Ŗƒ§žzJŌ}į”Ś™0‰J;ģ0I8JŅŠ &ēœsN0wīÜy1™…¹jhj\¤Āo"óŹĮ÷T¢q°ļReäČ6övīJI¼'Ȇł ü6C¹ū­(.|žg€,µhš]|é„—JaķÓ§äĒ攦P#ķ5r_¾žf0A=æżķo%ļ…‹ĄöCĖ6l˜Hi~s }bŒ0Ȅ{ģ±ąØ£Ž¹-ĶnŒ Fƒóßxćr~šŲHŽ Hb¾Y€1Hroøį†čźK3yņäąā‹/ŽÖÜšūq½©ĮƒG[>ƒf²#—īׯŸü^®I“m08¾R„(6ÄŽP~Ņą4hÓ»wļ­µ9©æ)ØNŒµ5}ēĪ„UĄ >¤Ļęag;53)¼YFŪÄɟvŚiRK£õooo—”޼PŠł‡1¢@-JįAKOæ‰(äü“:ųœć9ś{Rˆ;Ą1%?Pę7(.ĢqpŻfšq®‘ß`CėęĢ3Ļ”e¶abŠÆŠ ŹJ„žg§II=č5šsčN˜‚] ¦Š ½ FŅü14ūi±ŲĶ~ŗ;£GŽÖ„r|Źbj@œŚ¬a²" ĖA·†— ī Ę%HÄ¢ Z„RŒ+Š‹L €¢(łĄ§¬ŖHQZ5ŠŅĀØP”&õ‚fžmFŠ ”r’”Ņšćz4ztøC]R`fNžŃ~­)Jåx×aā('/,·½‘I#ŽĆŽnKćhęū©ŌŸgĒ» €ŲĮŹ@üŽŌrȂɐęŠL¾ˆŠń ±E. Ø’Q‹āwGc҃ć_G-G­‰4”5$źD“ńū“<¼²?ūń½XDŽE’LVa¤Į¼Āß+ĒÖĪS)•J¹„^xäŗųø)ąTyØŽČLĮž1c†ØōhV#F™Čt‰#ąx$ĮųĮł 0`ʏ/…rGšŌF{ĄqĪIĮĘųĮ‡qs`l0:»wļ–ó×j&#Ο$œ—ƒP-*JÖ8ĒØ…K„Ė¢f¾źŖ«¤§ņP#dA —“ÜÄŠB P"¦šRūöķ+Óh÷ŁÉ,ļųPP9÷ Aƒ¤f„…AK‚šćnŻŗ‰˜Ā1AAGlŅcŒ×Į5ń=ü4ŽC€ƒōxȐ!„»łę›ƒ³Ļ>;Zsƒ»žśėe„_qģĔ)S:Ā…łm×\sÜ~;æĆ–ÓJāw*JRŠ›ōō‰Į𤛄wŽyGśĆa“=ś$[·n•ćCć}R}j5¦BhÜb_<ņH“§¢$#mY„Ō^BmĢµŁ`¤žĄrŠķ)59(ыDZ .h ü¤(IńńØXQŸ²ŖB EiaŌ(J £@QZ˜Ōcøūpé5ø$qQV y ÉnT s*”p¹!ɜ„[UQ’ā5^‡ˆ£VnĄ<3žüh©2’ŗU ¬ŌŸgĒ;+05 ²_„9Ó§O‰+ ?©I…ŹYtĀ ēE“@.?ÜbüćåX‹P’Cš"!dÅgH®¹}ūöą¾ūī Ž<ņHQõqž»īŗKĪ‹"eźĮ‡zHCƒ’ĀłN9å”h­<ö=¢v/ž#ĄŽngę<•l!P¹ū­(.|žļ1š“ØķP±”nC²Ė²Qö”ÉēĮ'Ł'>s»Ū@!‡ŠI."šPöčŃC <Ķfōž|ŽŗŲN<ńD‘“‰#AĀˆ"Ü$ā¬\?ÉP+ş¦(YSR L īĀžĻ)05.5z}_"É„óõ¼£•GCĶ–B€t˜ĻXǐPˆį°5%-Œ†Ł/r[ÄGtŅ~Ó ę€k!„6†€ćųN»v­”;ļ¼S U„`ąŒ“VŅe›iÓ¦IkŲwģŲ±rߥ˜ƒ)0×®(IA`6nÜøh-!€8’ōo›PŸg'µ€ZŒŚ·™ ’¤ū@Ė‡Ö Ū«Ą-WĖ„“ŅęvWZ/€J„Įń)«*R”F €¢“0j„…I=€ųĘqhSƒū퐖¬T>„A&KY‰=•BĒ\”4d2ˆ»X¼L‹åB)tqųü‰Jkćóģ¤īIīį‡.¢\^¼#ŌAĢē¼š f–©A9E ADCģO­Ź~Ԛ( هĻpĶ”,döc;ŪŲŪeT€œŸķˆ—™ėą;x±nŸ±ߓōå*ĄF©X o¾łf“¤(Łā=@ŅN使’żļE’O"LRe”$dž}r²“%Ų$¾œ5k–ÄÜvŪmā#'Ķ7ŗ~t’dF/Ošļŋ‹Æ”ąčŒ‰1ʹ[o½U² O˜0AĪOįZ²d‰|~z“¶µµI 3ˆ²?²]Ņ„W ×S)ȝ“ E©Ī.ŅŌc=6Z;ś¾—]v™ģG­N—üw“aƆÉg2d»={öģ€9į„$m7 2ąĖ/æ\jh ė»ļ¾+ƒ1jyŽAźHVa¾‡lĆŌā†Ž½{æłĶoäū0,|Ž«W/)ąŌņ Žć“>4¢ßžć’XZ$iäĀ3gĪģ˜5ˆßG·O¦Ńe`;ǰż( ʦ6ßO|µ=ļŌ““Ī?’|هĻų^{?c ųĢr>3×暞«0x&a(­ę"Œ ]  u’žże™V ‚\sܾÜO“@TQ’ĄóĻóž§(”ø­ųĄŽ7Ötį14C|b@]9‰DN%:€D"Ńtb’8‘XŠI@ÜõÆ»²§žn.^ė#ke+ægåśZ"Ń•4śÓµdžzņ©l÷Æģ^_kŽ‹3Ļ<³éā$ĘqŗžōJ4ƒŽ"u&J' õ“ Ó^‡Ķ° L¶ęū³éĖ,»ęįō€n€¹qŽBwp•¬±¶R ĮIåÄdZŽ!·Ņk7®įƒ÷>ĄO’é§šņōĀ3Ļ<ĆĮ¾ö!jqz–ž†'žzµV£¾ŖžłmoŲøv;=vpŅ:”ؤ›6n‚‡§k““Žü«7…P’P˜æ‹Ņ²qÓFÜιy󐘘'ģµöč1ö 4(EåEģ;µõ“A«ŌāžÕ÷3‡_ŸÆvEĒŹLĀuvuę’tŠĄĀ؅ššöą5ÖĆtY¬:ŒµėÖ²F©ŅØF€łŽGwIj“RS_[Gøŗ¹~e ·»Zg-Ś[ŪŃŻŪĶ”B@` D¹āl”6člė„£“#S „‚½677CÆÓ£µ½µÕµprtĀņ•#&™Ōų©+Oqüüü˜w³»«›õN\]]™­7}6)?š“£.h}c=³:ó÷ŸŲÄ×LQäõ¶åŃ-\’RQ1Qšōšä5ÖĆt+‹½åi’žż¼439tč/Y7åeå¼$-W“ÆšĢC7.YÓŻ®,īL»¦ŗƒŸżģgŲ“ijBNO·oßĘ~š.Y/999X“h—¤#19ašńżŖ35`5C9)Š”2•ģŻ»/¼0uAhęz*ķ¤‚bŽ=šĄ\’R ę/€·7Ʊ¦»]Y„łvLå“毟„zĪ„ĘOLt9Ōb„Ņś–čŽKóhӕˆö“ÉČČČą%i” ŽĪīN.Y×S®ć‰'ž@DD Ęéń5 @ 6lą%i”%dk“Xu’*lڼ oüĖlÅj:°Ź9€©ęż÷ßĒK/½Ä%„LÕ5“s+Z7-BBBxĶäpšąAÉē›ŚŪŪįääĆ~RBĶü®óX¤,a&eI+ļ½÷/ ʂN§ć%iIKO3•••qiņ˜I×¼ *˜r.\øĄKŅB†[RfÉ#ōʍ,Œwzz:+745`@?Ąīād%Ku| ­½ ŻØ©«a¦åō~EEjjjŸŸĻ¶IIIaūSü2(£ AŠŲŁŃ‰¢ā"¶OKk ŪV „MĶM¬+%°Œ… ņ’“Ø(}³Ä ''Ϝ„Ÿæs KMMŒ%K•ĆĒćĢ…3H¼œČźČÜ|ōÉHĻ@nZ.~÷»ß±LBō~`` >8ų³Z=}ź43•¦t`t¬3gĻąĀ„ ĢæäFę dÜŹ`ūø»}ÕĶy2sšÆæüWętņ³“H¾• C·zƒž„„&S`2)&ē%/// ŽŒ»:ŗ`goĒ<ŌØŽ|&zśG|ÓG—}zŗ{čöwww6Ö¤» å#’Z ¤ķ(ķuoG/üēųĆ`™)&Gņjtrub¾ōłt· žüE&™Ž¶˜Ō&¶6NÉ,ŗK±I3Ó°‰ŻqČe60 å¹#ļ¹ŽśŲ»Ł3‰!ćū̶Ž6Ģ Ą n-·‘™µ­Ź–yRšŒ&ōö³;%+:orąŖ­©Eō¢hö݉ö¶v8»8ĆĪĪŽg}u=Ū> ,Ę~#sČjźl‚V„…‡ÆōżzVߊՀ€/–Ķ:ZĶßĶ\š @ļ@/K±Ež ē/„ŚA Ć }ķ}čźG°O0”čģéDw?\]”qŌ°ß¾9’¹yø±ć’/ żV [¼\½płŚe¼ńĘģÜÉyŒR‚õvõ"łz2\ł \<\ŽƒļDXLv?¹§ŽŸĀ–Ƕ0“óÓgNĆNi‡ų‹ńĢ]™ĢęÉĖ“ĪżfźM<“ö!454”””ż6”H$48kÖ¬Įå —Q×Tolzd¼&fćšM‰A„°€_žź—,Āķ¹ēp1ń" żųĻõg ¹“S-ćŠL.żœŌHAŌ`F]?)›»«Ÿ LUČk ßMækČ¼É¼ó𯬨DZjB™žÉ|DČuü”į“Ļ>ałüØūļäé„Õ÷Æf×őŌét¬l4±„Ź€ ęŽNĆ j“”œ„9sę 44J–^Œ‚©ŗh]Ši脝-^„Šy”ģ<ĘĖ„3‰I@“©µ³Õ|ćfeĮ·cļņ’“d§g›ŹŖå3 ˜””dŗt钩¢rj¾æ%|Ó$ čX€X”1wófé³±€·¹8¹=€?ž«V­ā’u×kXL $cŖ›”€7²y)ŸgΜ¹kżd?wģŲĮæÕ×`ż CĮX™Ŗk&==];€©`ŗŪ•č$c*‚¬ ­!݌E(dœ:uŠ—¤eĄü ?ĮŲ @ wĖF+¢0~„HFmm-/I ėŒŲ? ʈX“± 8>²²²°xńb.IGVZōĆzf imŠ*Ąī§w3ć±é@(  `|”””`žüł\’rŠ©®®ę’uAS/½üģŌv¼fj Ą„—.]Āŗuėø$øÓݮĀ@2ȓM o„HåJČ”’±}ūv^Č”īĮŠšŽ?†›7o"=#× ,åŲ±c¼$+BÜ A™†÷ļßĻüłcćĮä%\±ŹU€©\ņ©kØĆĻžåg, ńT)GG256_8a62740948e6184e*’’’’’’’’’’’’# 256_31d6db435bf77ac5*’’’’’’’’W± 256_3838e95525a33970*. ’’’’k·'256_f29948e018be491c*#/’’’’²^ ˜˜ˆ ›6@%{S¢@>¹:Ąuø+Öś­Å›—o°tÉR(s•Ųøi#ž=~†Ææüó¼ę‰½‰)Q Ÿ\ee%Ņī¦Ab/ēDOTYUaĢŲ1P¾Uā —/š²ų%ģŗŚ‰½‰)ŃUb‹ē/†ÖZ’GėĮƒøy󦈀 uN<…ÆžųŌŌŠj“ŠŲhP¤(ĀēŸ}Ž=a{°Ęo ś9öhyģ*@zzŗˆ s輀°µr,bj›6‰RC¾¾¾¢Ōvl޼Y”>n½ĻzQjżh@Ģ¢“¬T”,O[zļ”±`t€˜…ī0[·nQ}ėÖ­ĆĢ™3EŌ69rū÷7n*šŹ•+±cǵn”ˆYJoß¾EQQ‘ˆŚŽAƒ‰’a”ˆÅ3”Ś;J:%Å%H¾™Ģgy󱵵ń DdŲŻ;w‘÷&ODĘsčŒĮ®ƒEd%ż @„Rįʍ|īCStģŲžžž|m fKÉÉÉüM:;;‹bžžž›ĪŸ?æYwįn н{Dd%ż ąéÓ§Éd5j”Ø1NBBf͚…=zˆšfb ĄtYN«{³""ę²lŁ2Qśø ˆRÓxyy‰ŅĒłųųˆ’åY±b…(5ōųńcķµk×Dd¼ččhm~~¾ˆš.b>z(Jõµhxżś5¢¢¢ųņū‹ßł„ i¬—/ńsŁŁŁµŪoß¾ ؁3ēΰ£¼)xƒŌŌTŽNZZTe*dŹ3k÷gĖūJ”%¼žŌ©S¢øw’Ō5‹åääˆZŻųųī]QjH—qy;W®\¢HiLķs–••ńv… ¾/k›½'¶M£Ń 33³v¼—”’ÄßKkó<ū9ŻäÓ(.*†R©‘iååęĮ/Ą«¼Wéżģµhø˜xC‡ŤI“Šß©?‚~Āh÷Ń°ŅżDīDĢ©xxxšķq qČ)ÉAĄš””– éRĀĆĆy;qńqH<“Ē^ŽųĘż~R…=¦.u…+—®äõ68zģ(ŹTe8{é,īŻ»Ł3Yu’ŃauWŲ.^ÖgõŠÕ’ķxČ2eæĆcŒNœ8ĮŪ¶±±Aœ4§„§ł¾«žµ ī£Ü1Ģu¼ż½ńkōÆØØØ@ųįpŲt±••߯µČĖĖĆÕóWŃŃŚ4'•ˆńŲĶO»B>üłkŠre9æaē’vbķźµ˜6}šŲR_‹._¾Œ‹W.¢ø°Z{-1qĀDÜyu‡ ?ńńń(Ļ-‡­µ-ČoI/IGĻ=‘•“‰)²Ųt²D"AēĪłŗ®ģ“lLž1™×’ĖxĢžĒlĘmœO:N½œąņ„ $ŽńYŪłŠh5Čy›y–’?HŠ·o_ łÓ’Ģ;|Šę 898a䰑¢ÅÖ#ćI¦LžŅź“%q°w@·>ݐ_˜/jš'V‹u¾ė0ūļ³±yćfŲŪŁ‹- ¼  *UaĆś PŖŒ?<ÉĶĶŶmŪąźź*j€ćæĒČ#įääTaŲīæoó^ģĮ#ć‡9? 6>=ŗ÷Ą“©Ó°vĶZŒ1vÖvHy‚į£†ćś…ėxłņ%?ŒN:!ųæĮ äķԐæ–#>*žßG®V«ńčÉ#žG%223šZž>>(Č-ĄĢæĪäG‹.Ā”ˆC€µh@ŠTjš0õ!†øAā•Dt¶ļŒ±īcįõO/DFFņĆś½{ö¢DQ‚’وČ‘ŻŹ;Tņ­d$ŻHĀŲįcq0ņ ‚Ć‚Ńݾ»hŁ4ęĪĖ`cdddąģٳ"ŖvōÄQ|ēłś8ö5Ę~ģ­1ŹĖu ÜÖVD–ÅŠ{W(X¾|9ʍ'jŖ‹:†©žŠž½zŠżbbŖ‡ŸśŚ—„Ė ČW dw&xL€µõ»shh(æ:ń~¢7xÜׄk„ī ‘q’’’D©¾nŻŗńŗn®nˆˆˆĄ«œWųń§‘ņ(vvvXšÓx{yùŸ3Į/20oŃ<ü–ś¬”V8q€¹#vE`ńæėż&ļŻ«7² ²ųĪ”;)˜ó·9pį æ~<$ü’€ģĀl( Šó³ž(*)Ā‘£GųŚōÓk(Ų”qŌÉ(ōŠÅ%Řņż]ŚŌmŠč–* õn*Ā÷‡ó$“!n#ŻpčŠ!äÉó0`ąžĒ.†{ ‡’ų xw0Æ3„……‰Č°… ŠŅ;’AČߏ•ĘŒƒ}ūö‰ˆ4œ'OųLČ÷„ßJ‡ż÷ž¦®‹]bŌwPQ¬ĄöŠķü2ć¤oė‰?ˆ˜ƒ¾Ė€•••ŚŖŖ*iµUŗ•J„-++ć±ī›˜ÆVÖØ5ZŻųY[”®ąu¬\w×]ė:^ķ’r-…?Wii)V®y,+³Ē°mlaĻĻ–šX*•Ö¶]»oĶėdtYžÆuŸÆ™ŠņŠzĻÉŌ}½uo*ͽ X„ŖŅnŚ®-/«~?†sč§ļ2`Vv–öĀé "2ģc—ŁēļłÓēŚ„ŽKµgbϰNʅ„„šmļkWóX§«YŌļ:¦±Xē®i§¦£·V¦˜Ą“TĆĻF”šO_`S_ēŌ§±óŲ—mŅõ$­ļJ_mŖ,õƒ  ]Ķ`cᚄc§¦ŸÕf'ųjŚaåöŽéą'Ɔ¹¦> ˆ™ģĻŖn ÄĶų›8)=)¶Ōg¶©ĄģĄ¹sēŠ»woQCĢįōéӈ‘al éŒ3Dd¼[·nÕ^Š%MĆĪšóėfßRuĻ,㙢_˜źF Ęl €Ņśµ«s„ćP ĂQ ĂQ ĂQ ĂQ Äb’0’3ÜxĆś§IEND®B`‚ÅÅś#źā)<¹g7ŅķõˆšI¾„··yyy-€’’LOMć“Ožüóļ,Õ·ÄĒĒ#11‘Iœ•Ą@€R’U#ö½ł:“|‹J„‚L&£ Ą`0 <<œåŲ©¬Ŗ$ jE7’…ŅŅ’²TߢlRā퟽Ķ$ĪJą @ń§ķø0¦Q#>!™åŲ±µĻd^@hpKõ-ŽöQc£Zķ“œ–‚T*CFĘ.|śi±.bYĪŚŽü|?*1Apššó=­VĖ$×ų³}6¼mƒXy£Ńh©ÆÆ§ńāābś¹Öų»ł& Ē įéOŖ««Ż†ädg«`£248€ĘJōöõB£Ń čFž¤ļLĒ2÷!)) ;b·#<$ SćlŪƒˆČVŚ;ŪwõźU–źC˜+Ą 0ĮĒtÄśH.—³˜Ēņ£Åģų{ĄcĪß(ü¤8b}TYY‰#GŽ0 (™ yŌgćĮč`Œ‰PNG  IHDRzP¼usRGB®ĪégAMA± üa CIDATx^ķ XTG¶Ē’ˆ ( øć÷ˆ(j¢&īŃÄ1Ė$cL¢fŌ‰ļÅ$3™Ģ{WÄ.D„×·±4 ĒPWWĒs†SPP€¼ülŌ6Čø’Łæ˜ü¬|ØėŌšņöBNvn\æÕo­†ÆŸ/F²Ź2øŗ¹b²÷äśĻÜāƒĮƒQTX„ł ē楞xvγŲ€‰ŽŁg¼ōŅKŲ“yƌƒ"Ą?óēĶĒš‘ĆŃߣ?ūœ¶‚ŹŹJž«'996lą9 xk0–.[ŹsB½pŠnGOūMßm‚“«ŹJĖ0nü8̚azJaa!ė]õė׏—;vIJeĖXśų‰ćšöōFē®Y^›ĢĢL„‡‡3!aķ¤„„aŻŗu}Ä4ąž={ŲƒÉ”(NŠųzŲ<'4˜C(n w®yJ ˜Å ›Ś‡0¬Å u5O s£8`'æePœØ±kŻ4  żRWWĒf4 Ł“g0H­ÆŽ6:§ö€ņf¶`śbĄš E=x®y222šĪ;ļ°4­<}ś4[Ā­4Č6äÕW_å9Ó`ŽYÅ­ōšē)µ`Ģ 7ķŗ“JšęĶ›<§,vģŲĮS¦Ć*VŚŚˆi@AėČŹĪā)”(n°5h+–-Æ7<ŗųłł5tŻÉńć?fé–ųĻžƒ¾}ū²49 yį…ņ(¼[ˆŗŖ:Ų;ŚCU¦B7§n(-+ŀĮp9õ2ŗ; ›}7ōģßéÉé9v$Ο?ńŽćŁq¬Y½;’Ü(ÉXžųĒ?bŚ“i()-aCNztj V±ئƒPZdBMfŚüq^Ś2t³kŚ=óĢ3¼PW«QVV†žī=įŠÕŖģå—ŌABuU5ņsó1aüøvvÅ“Ӑt" YčģŲ]»ąXÜ1ØJUØ©6Ķ’oņäÉģI™āę7Š65b!5“’’Ā“ūĘR©®Ä/üvvvX0fNŸ‰§g?×^z .Ī.X¼x1<½=1dšŲÖŁ2?K/sWgŒŸ0K–,ĮÜ9s-ī.ķaÓ®gÖÆ_š\ūƒlÜgĶjż=iæo޼ÉsĶCĪ6–.­7°2¦©ØŖŖbŻa^7“1][ķŗ4 @ŻuĶ@I„……1”ÓŌ¹mŪ¶ķgŽ^›¢[·n˜3gŽY†ŹÓlيeo¦ ĀņåĖy®ż »­›ņlķMcŽ?QKE×µ»śŚ`ĒŽĢAˆ!“—5kÖ°4Y9=zT‘ĪBč¶śå/Łäõ¦s6tšō%«V­2ĻoG@In 䩖ŃvRRR¦„īŻ»'•–”²2•J%Ż/¹/Ż-ŗ+ÕŌŌ0§•••lßķĀŪ’üd”īÜ½ĆŚ±÷Ā;…l?!)™“ŒŠŠŠ†|Yy™T]SĶ>—¾‹Ś”–ÖŸ±ųū·~ŹSwJØŖŗŖI‡Śu›šJ’ĒÉlČ]Yk ’ˆńńńųō³Ońć?āvŃm¾G`)Rϧ¢\õp|"*nšéGŸbÜÄq<×<÷ļßoō čćĆŽI¹C7­{wä^ĪÅ“YÓąīāŽų3ń˜;}.SQY[‰—½„cdßE~ĒŽ‹“Ki6lXƒvyĒöšä iąččˆĖé—1dŠøtwĮ…‹ąääÄĘq4¾=ŗŃē½”üīwæ3Č7¾>h,’üƒ„ėjėöCSd郆šn²v;¹G„»wĀŻŻ÷ņļ1C¬ÅÆ.fūL ČÆ!łLŌpåņ 1œē]®e^Ɛ”Cx®‘ÜÜ\¼÷Ž{,]PX€ģėŁ˜2q ĖėņŪßž–éŠĪœ9ƒĻ?’œ—šÖP­õ ńCė"M:+EEFI©R„ƇKaŪƤ÷?x_JNM–6oŻ,żöƒTtÆH Ś$…„…°¶‘‘‘Ņ©äSRXX˜t$ī+#bŰīžg’üLJ<™(©JT’ü¤”"""¤ĆKĮ;ƒŁw¦¦„ņĘaŹ!@Hhż¹čC»®vŗ¦¶Fڰ~ƒ.ÉBB’ ßcZō ¬ķ!€ü€‘ņ ņxīē˜s <ąß:`Jčʤ-’V>/1¦yyyĢ©>š–B€Ÿ£-2Æeņ”~¬J`ĢB łųͲѰ‚6r1®oæ©¶¶¢żY½{÷fŽ=µĖ“7mōķ7÷&xķkCnšµóŗ›9QœĄ§ rׯģȜxzzbŠ AއĮٳgńÕW_±“ŗFąĮMŚPųśś27ÜĹsē°nŻ:–®¬®Dll,r®åĄ©³\ø`įœ…lŸ)!£:†žżūó’z–-«÷żxęģŒ>NŽN,Æ 9žÜ·o\\\x‰õ’œœŒ’ūßł$ŗvėŹK-õĘ=æˆē–FyӀ~žX¹Ź°i@źŹ¾üņĖO×ĪTŽEWŸB>ó ‰’·#yPžG Ą`,żµakĀ*zĢQ XÅ €ź į@ °Šh{hv@` ŠĀ%˜@`9'Ŗj«xJ ˜Å ŪŽ¶<%Ģā¦ƒü‚°|UĖ1’)’mQQĻ) $:wī\žk;iiiørå ϵŒfśˆ"_½jYĖæŚŚZ<żōÓčÕ«/©yļźźŹsMSUU…ēž{N‘± ¾~õqŠZĀė¢ĶÉ®]»xŹ4sžŚuĘužLCk;²·ˆŽ‰–ÖÆ_ĻKQžP~ ŁĮĒĘÅ¢šn!._¾Ģ¬ĒŹTeØŖ®B~~>ĖĒC­ŗ`Ė|cbcXLżņņśøģäy¦¤¬„ķ#r®ē0«Ą¼Ü<ääę@ž³Ļ9“hX8.KC”ŅÉ*²µÜ½w—§,Œ|Č[`²2³ąėć /O/Ö Õ„E@7¹Č²ŌV”®Š[®»i;æ8|ä0¼Ē{#2<’Ż ³gĻĘžØżØ®®ĘĮ˜ƒl)éSӟĀa?`ŽÜy8wž¦xOA§ĪŠµk½Ljr*Ā#Ćq,īŹUåŲ½g7®e_cķ·‡lGüń¬ ?Įk«o,²°Õ{­Żt¦¢FƦƒ~3gķļÖm·o’>ģ;°߬ūĮaĮfVŃ0@ūų™bÖ©›vf¢ŪÖZ7śķō•ėŪŹJŹXœĶ¬ü,¼µś-ø÷tēWóAZŌäēå#å| Ļ™ŗ™ēĪiy¬œžžŽ÷ߟ„éÉLkÜ÷ļŻŒÜ Œ:Š=łi½yTdJJK0qĀDäŻÉƋ _dcąŽī½‘œ€ł³ź×É?~<°ńŪ˜’ü|\H¾777vSe]ŹĀccC×.]Y0ĻŃ£G³6Ęšķ·ßbŲ°a<×všé§Ÿ²“ŗZķ‘ŪńĘ+o°¼. ėéµŪU×T#** m;¢¦¶¶ö¶xįłŲ>SBžä!ЁP©Lć é\³āģŽ­;ĖkCžNž<Éģ ¬ (:uźTžk™‚üŒ7 “¼&±’q@@V¬XĮ÷rH( ’Ćbęk‡JĖK„ŠéŌéSRtt4ópņĢIÉg³t%ūŠ“qćF)lg˜”W'I§NKåŅå —„[·n±1fRR’$÷¤ˆ½Rvf67ķüa§”x.Q:“tF:{ī,ūÜŃų·‡¹u”;CŁ1ė£)€ŗN-…IĒO—B·…J×®]ć{LKK:€šØš&}@#­ŃdeeI¾Ņͼ›’æ’Ļļ-Å ??žjžÖ\ ]ȑHvN¶$÷¤;…wx©y0·P©TF KѬ¹¬“iG$B4ŅŚß®®¶NŚ»oÆ“ń»¼¤Å)[ė°5#‘²®y·öŻÅ$ę–\)ł»:Zމ5ackƒ…Ļ-Äź’^ĶKQÜ:¹›7ßŌļŪN³“Ęæ½@ć_S® =­…0ggēß “vąŲ±c,m)č/FóפSŃšż÷ß3'­-AŹŽ×_ŽŽŽ¼Äz1Ē:Å _?_üfÕoxN h° ":°@`9'ģ;ˆą „PœP׉ࠁ„PœØ³i}x+@`ŹÓHB X å €ö8—-“S”ē ĖW“ģ€ę‘5ń\|÷ŻwYš¦„Č‚ŃnÜø?ž˜„ig*JKK™ÖŲ±cy šöŪocņäÉ<×4d3°téRōķŪ——X/VįĄĒׇ§šēa,i}Ųl޼™§Œ;E/n±øsüvÄ€Ģ÷Ų7oąśõ묌ģłÉ|’Ž5eł·ņ!’™˜$=ŸvŁŁŁĢJ-ę` ’Ļ%³ņ¢{ę°dc/_tęąJĘÄŽAMu ó  MŚ„4öNßĆŠŻ.@ś„tØkÕH<—ˆ„“ ģ³oÜbõĢĮ;wŚä ’v>OYłéw<l’.ĆӊąĢé3ššš`ŻŻę6Z{OŖKĖp©¹?~<ß„n ÅÕkW¾+W³ÆbĒ t馅ļ5 $@)ĘŁ+h~æk×®Õ’~²¼'åĮƒė½6ÅÅÅl£ƒ¦­µnŗæ)P\ ²²’9„hi£zj䳎ƒ-`ogĻ֏×vØErZ2לGYY»IP'’ßģlX{V_>{zŹ3o:š—ÖStĐØ­©EFVŗ9 ¢¬e6ej|Ņ’³Ū:[äßĶGJR R.„ĄŻŁq±qš扊ŗ öäŲ¢-PļBsžģœ8ź5»MA=!}ķČ ©ŹŅJ&Lśöé 7÷Ęõś¦„®±ęh“{Ÿ|ąÖSNõž™ōA: ķ¶Öŗi’v¦BqJ@½N ō ­©¬ŖÄ¶ŠmpqwĮ¤É“p ņęĻµī®īĢӏŖT…žƒścHß!>z8»)ČŃÉ©“§ŠŻ¹;z÷źĶžJ󞝇’¢ö¹ŽŻq8ę0.ZČŒ\ŗx‰Ż$—.]‚«‹+Ę>^ßSj$xNōDģŃXŒ= vĢɅKO&r²sPx»3fĻĄš”ĆY›Öąć惷Žz‹„uBa{Āš«„w„]W;M?żŽ];0lÄ0d]ĪĀ“SžDžlŸ)!EŽ­[·č”3å ę=Q{šā¢õ;9éŌ©“ˆ,£ū››J"00§šĒ\Ź,²©—Ÿ8l«©©į„?G~š7Ō#Ē– 9%`sĒŖ]×\×­9ZR’#–¦JĄFĢńŪ)®ąļē•«Vņ\Óųūū3]5AzĶ4 ügŠėäQ¤ųąƒXš”ž–v±MŻ’#F<ŠųĖ_žĀ¦[‚z^sęĢ=sō”'ä{åŹ–¶ĀŻģPYÓM6öü5 ¶‡uŻt|¤§1”¶(N%Ģ!weķä—!Š@ kŚ“ĒČĘžæ†‡uŻtŃW§©M`>wukķŚ¦)†£8PW%¬K”8`goŲ@ “Å €¦¢ŪÓ£8PSŃōŠ6@`Z”ē8ČæY޲W`ZM+÷Ś “f”aķ¾ ČĖĖc1õ ģ(<7aL;SѱcGŗM Ifč_ļ™gža«­«X (ƒ†1ēÆ]÷a\7}ß)́ĒæņtuB X Å ²ę3–Ō ©ųīūļXو½ų~ó÷HINĮ”C‡Px§…ųްaĀ#ĀńՆƘÜWß}…‚‚KhŒ’sü§ćH>“Œč˜hf,“5d+.^ŗČņ›7įĄ,ŅīĒ ‹ČcIN%žj•Ge²“+.*FDdīßc†U–ęŲ–T$hDq:€/¾ü‹.⹦!ņU«V±ōÅ+qńüEōļŪٹŁX²x Šļćó’żĆ''”T”`ųšį̱‡»»; o¢“s'TUbõ»õ1ÓöÜϦ!ósóį=ٱ1±,¼r…Ŗ'ŽŸ`aĮ1xš`£ķ²ÉŹqŹ”)<×vŽ9‚÷Ž{„Ʉ94$o,Ó<44“įxµŪ>›|Š{PoÜͽ‹U ‹%ߣ”3ßkvī܉1cĘš\=III įĮćāįéé Ē.?’EրäҬgĻž¼Äz‰m°1Š›7oĘĖ/æĢsMƒ×^{„= ‡ŽČČĶ@éŻRŒ9’ł (/+ĒSO=…£ĒŽ¢K§.,>=ŃÉ<—‚‚:»:Ʊ»#F Į„)¦HYõö;ocÉĖK0bōn d‚ƒ¼õpźĒF?Ę̇‡?fœYļ¶mۘ2ĖTģŪ·Ė—×ūN¤Ÿ0`{V¾¦ß†‚n@įv»ŠŹ lśnœœ *WaÜųq˜ńŌ ¶Ļ”ŅĢ™3y®źM1s`™ń'ąé剮]~$”łAčÓ§/±^öļßß 4M %Ń% ™šŹ`cžĢtĖUå¬œŅ“Æ¦¶F*//—ä?+#ÓY*£ś“’¾żģóŅ.¦±v“Ÿźr—˜„5ķčsdįĀöƒ¹•€gOžm2ƾv]Żv••ģZŠ9Õ©õ‡o+ŗßIh”€tżć~Šci}%`#ś®c[Qœ £]Gž22péÜ„33±µµE—Īõ.­(MūģlķŠ„K6•De•–ŹØ>ķö¹gŁōŹčQ£Y;ŚOõźYPZӎ>G‰Žˆ½¦xµŹpĘ”“»tNc]’™Óģ,‡ņÖųūā7+[^ąėė‹=ŚOLņˆC®°MExxøĮóčJ|ķŚµ,Msɖ&%%ŗ®'’š‡?`śōé<×4¤Ø}žłē…[p«š ƒ ś± Ō%–Aq ƒ­āI xdQÜŻFvePœ “@ ° ŠÕ¶Õ<%ĢņtB X ÅM5,UmZK® śłØ@‹qž{ī9žk lzīÜ9žkž®]»6,C6¦© Ÿžŗ”ĄĆĀĀ`oß²į¹öŁgŁ,kĒ*üųųóTó˜cYäĆʘsjm݇qŻBCCyŖįĄxĢńŪ)®æM.ePŽ€ŪxS6X’Ķz9|›ü6aķ’¬ÅŁ g‚?’łĻX÷Õ:ģܵ“Õ=+ף“ £²biŠkŸ’˜ĀL|O'žĘå —ńźāW‘š•Š‚ėmČŁHMaNQi}ż·ß~ĖŅuź:¹)$”4h·#¶nŁ ×¾®PŖPXRˆ’zėæ ”LÅ'Ÿ|‚žżŒ:L†YÓ֓§Ob옱pģŖß€Üõe~ ­r˜»ę·kxĪ4(NжB„žąå„å(®*f7gIY ś¹õCu]5† ʂKśmņCæż˜Q9—pusÅ“Ÿ`ķģ=ĄśB5(*(BnN.F>>·ļŻĘÆ) Ž<¶‡lĒÓ3žf7Š‚_,`J¬ŌÄTÜÆø”†"óz&ū8¼&z”—{/ÖĘŒQņčÖõŪī‡UKź¤č¢]W;]QUu’·}ś÷Aqq1;ĻéÓZ6Š1ņ… ńŻ ”!<øLü±xxMöb>tįĮĶ €öˆ®B„ģŹ›ƒökodŪOŸA[ń½āĘöņ›v= ’­©G¾XM]Ż“vŽXtĻ©9tė^8{”Už4ĒŪ–ćn‰ę”€ō½ń§āYZB h^™I÷–ŒˆhæöF¶żō$¤Ķ¹»sc{łM»^÷īŻź‘oVESWF7­·$c¼Ę“Ź€ęxÖqÓ÷N<•疦ݢ££QXXČs4ž_±bĻ5Ķå§„„ń\ĖhŗŪʶ3...Xøp!ĻÕóõ×_ĆĶĶēš†\»½ņŹ+B`&Ś­mē‘ć@ °b„¬!«ųĶ~Ź5a»K²IEND®B`‚ˆōĢ՝tåI•Š@%§P}†č(T4|ņi…šo§ņ£Ź6hŠ@ 4-9œ•q™’B( Ī¢Ö¢śā÷f@÷€sø/æ# ­ æÆ;‘kčv{ģ±Ņ÷&ž­(qœĖļiØüvŖ§Žüń×@3‰„ĄĢCb†Œ€!ųõ£Ż0ˆæ?˜ ޳gOÉ+śéhT~„].|ū©ŲŒÅ i5kÖL“(4,³²ę įĄļhĢē°ń'my‚iņGä{{±ÉÄt+D· į„*O6Oņ®~ĢļüłĄ1?z‹„’¾v0õ¤+O²ŽČś+Ū”EDR§³ x]€t© ĄLCq`œ‡K9éś?†"˜:źŪ·|՛h j2_ÕŠ]‘TBģ}Ų­hčĮO`$]ńä¢A‘Ā‚“q j"ńčŽYŹÉ)0¢GxxX_¦ŪƓ€µk×rIp7Ä*Ą8ųüóĻY§©xśłųჽ°Ø.w{_Š'‡Ģ|}'–&}¦CįĒŗ»»Y“)śæO Ō°9¹‹ģĄÖA^^/ īFVf–I£Ń˜b£cMfĄk§Å/Ģp]pO(cmdd$—¦žšŚ–@ŗįŁŁŁˆewåĻŽČ‘l¬NQOhx@ńųpćŚ \¼x‘ß ž7b&š“‘ƒōœt\½|MMM0_¤,ųdRb<¼<˜Ą‚(=~Y·²PU[­£i7Ӑ™•Éö£s(,,„·Æ7 H9™Šq)x¤µSTT4uł­ź!„ÜLĮó/=%‹§ĒfBVC€!ó£­­ ­,ņl^aņ ĢĻü<üćĻ’‹¢įбC¬įRUU…[鷐™Ķ”ŸĒ.Ęļßś=V=² { ~äa¾5U’…‡z.,’®Y³}Ī_:ŖŹ*””²ķ(*ļŠ%+°xébįŠ‘CčÕõB­V#§$· nĆŽŽv“Ūųgįįį¼$ų&ŽśÆ·šĢīgø4õLØ@Ńp?9ņ rórQPP€üā|”ä–ąvńm¶}vn62s3Ł]5+? łŁłČĶŹEaq!2ņ2P˜]ˆ¬Ü,¶/m“Ÿ—öŽvv‡mhl€«£+l‡mYdŻ¢‚"īy×Ī]hnjq21ėāĀbֈ«ź«XdVzŸz Żŗn8Ū9£±® -Ia&7=—EY-.-†qĄˆķŪ¶ĆÕĶŁ9Ł0 ™080ˆ%ĖF“q[_{‰œ¬xyz±|w+ćV¢²¦ߣś¦&{rp¦ōČĪ}:{ÖMöNē ӄV(–=Ł{OEąĒīNsƒvufåąé§Ÿfer9„®TyU9*J*XØn ”ŚŹZØ4*ØķŌ_X„-‰Y’`[ŸbćēęęĀwŽļHøī!óńškŃ֩ʖ׭]ƒ..ح؅ÖU w'wŲØmpżĘuĆ?nE|¼|Ų±'‹Ć‡cēĪ\²^(öæ5¦ķžU°„»MFÓŁ³g¹4uˆI@ė`6Ē‘“¬¦p'?’łĻ±téR.I-Õ8;ō>¦‚®®®»'q°2zzzŲÄ­@¾X„˜jöģŁƒ_|‘KK1÷±eĖ. äˆ0¶€”!^Œ…°°0^Č”,@i~Ę%Č”,Ąhcä%ĮX ŒÉy#€Øj^Œ^Č”,Ą8,zć!''‡—rE(  킱óČ#š’@®`d (;äœ%7B| łģ/Hø€Ė.ó„<öŲc¼$+B| ŠaŽ; //^#°”sēĪń’@®š-¬_æÖo@hH(ÆXŹ¢E‹xI W„)š× @ 죠“6F8ŗ8"nqneÜBŸ¾ƶƘ4‹ćC£Šš½w#-- Ė—/ē’@ŽĢz`4QQ_‚[ŠéuŠøhX“”° o6cmØi`wŸ±j±Ń± dq _rėÖ­)K.³NPĄ¦–& ¹”.,rMdT$T6cĻŠJ=ŠTPV}ž>žX±>s| TĶnāņņr„„„pI Gf¼ ÆG†Š‹ŠQSWƒać0b–Ę <,“Ī«_ߏ’āahŠfįAį˜>>Ž>ę_›o4K8ž<6nÜČ%™‘ €üé Š ŠXۈÖöV,^°įŃįpqqį[L &óƒb PlƂģø9¹!(,įS~.ÓżfĆ÷“ff„0 (Ģ/D}m=šŪšįāź‚õ­‡£›#lm䳊A1;;;‘˜˜ˆŽęxųx 00 .d±gw»fņĀju³)ųhoo/ó×dż#šóöƒ­ĀzV6‡‡†QßX„‹ PŖ•Šjµˆ Äüˆł| ė†Ÿ'ó6¬K9c‰PNG  IHDR£eĄ’sRGB®ĪégAMA± üa'IIDATx^ķ @Y’Ēæķ„H1ȞķE¶TcƾļÆ1d'†wĢĖĢß0 3öe˜A“—ŹRŃ"F˜‰!ūƒD *{ZiU÷VĻ’žÓ‰äV÷V·žŗēÓ<Ół>÷ާē^Ļó»ēüĪļü~‚ p8µD“żęp8j7ŽĆ ‡£ĘpĄįØ1Üp8j 7ŽĆ ‡£ĘpĄįØ1Üp8j 7ŽS-B<„äŌd¦ÄC¶4’łź?LÉēNčüsõ¦Ƭ¾FŒĮ|+7™ŖDdWҜ/ēŠ¦—‡Ņ2Ņh[rss1|Ųp4nҘķįTÄTu~žłgÖĪĪάU4d?SбnŻ:ÖŹC‘æS< 6°–b¼|łRš÷÷gŠSQš!‡£ĘT;“­[·bŻĘuHLJDh`(īGŻĒ.ē]XµzģģģpōčQąÅ‹šńõAă„……Ń×»pCō£h¬Y³¶¶¶Ųķ¼›¶7mŚ„,I}Ž*ÉÉÉĮ¹Óē˜*=2ćĪZ2ä ņČćæūžo/oŖĆĆĀņöuä1‰TBŪåAąõ@Ä<‹aŠ#ŖŠŌФ7¾±”1’q)™)ȑęĄHӈŽĒGŽ ++dffāļ #5!¹’\H„Rśz²æyćę7a&Nœˆ×iÆ1dČ 2zŗzō9ŖäŸ?`ó‰ S„#<"ß}óŽłƶmŪ°nĆ:ܹ{[ފ ›7ąŅߗ°kē.\śóź™ÕĆÓGOq>ą'¼xüZZZlOńÄÅÅaĒŽ“Mzk×­…‰‰ ¾ūv;`Śäiøqż½‘/_¾ ėnÖ¹‚ĆGCOŠĆų©ćaØoˆŻz`—ć.Œ›8;¶ī ßüŪģ·aʤ)ŠŅŌ‚iSś7e×®]ˆgJ>!!²ó8|T;ķrĀÜ’Ģ„ķ¢˜4iڶmĖpóęM;vŒ)ąJŠDߏ†¶¦6Īž? ³fŠ×ÖGfv&4d?f Ķšåœ/aļ`™¶3aļbi§Į×Ū1ÆbŠŚ¼5Ņ5ŅńõœÆŁĆŽŽÉÉyĪXņ¾h;Ÿū`ź“©L½Oll,–/_ަM›²=œ| °xńb¦ŹQļCŽ5l Œ ŲžāŁ¼y3–,YBŪ9¹9pŪķ†ZukįóqŸĆó€'¬>¶Ā£ČGčöq7ܹ~’²üĪ]8‡żĀø¦16Ūo–}õuLė F­055EŲŻ0Ō2Ŗ]}]¤§„C[[“§NFMÚōļ(ĀīŻ»1gNžW¼(ÜŻŻ1yņä·Ą’¢?›7†y3sŖå±~żzz³äSųļœō=‰‡Ń1fĄ:uˆ¾Æž={āųńćčjŁi™iˆ¾V]Zaų€įŲü‹ģóūn \wEā“D“éŌ Œ {÷ī숊Qš<6n܈eĖ–Ń6įMę:zÓm§³=ļC ĄƒŠ«W/¶‡“φ šĆ?0UĪ 6¼Ü½„Œ“ ¦J¦:ĶČŗįĀõĄėLɧ*Ī„ŻdĆ,¦>„ĻĢą³Vł#J€PC óĀźˆ†¦l¬Ėę#m­ŚŅ^G\ˆsš»l0Dń!€ģsē?n® H÷žŪoæeJ>ä9ƒ z;P„;wbåŹ•Låu½ĒŒĆTåįįįo¾ł†¶WÆ^Æ¾śŠ¶ų ’’’ų@ŖˆÓxĖ Ą™0TĢæu>‰ MMM|śé§LɇŒ}ĆĆƙRŒzõź”]»vL111ø’>S•‡ŽŽõ5ˆc255•¶„K—.066fŠ“ś™+353NuF•@”>€½d ŁLq8U!J %т¶ĄFŽŖg$ @SÜ'ĘįpJ‰8‡Y9ČŃČaŠĆᨠqō“ %(ĢįpJ8‡dščę&8œź‡8‡ä‡8•#Ī!€Žl Į‡ŽŖg ; R0,…-iŁ­Ŗ±±±”‘lŹæ’ž›)ÅhÖ¬ ĪēīŻ»ørå SŠŃ²eKōė׏)Ž˜Q»Õ€ž=…“Ō4¦JF «·oßĪZŹQY9׬YĆZ±£v«Ɋ8’هĆįØq€¬²EŻ »K“œ„{÷płŹeŗÄųöķŪ8sę nŻŗ…¬¬,„=ƒ4[JÓhņÕDEEŃߍ ū‰+Ūp&īekq8Å#J€ĒA|ŚćSč׊g{Ї,‡ĶϐCR‚>›~Ł„ —.Š\~‘·#Ń¢S œ½x)I)ųļ×’Å”#‡`ÓĮīžīTÆŁø†fŚqtrÄ¢oaÓĻ›°jÕ*zLE Æ-)ū<Ž9‚yóę½]y?ÆR_ĮŚŹšjyüōÓOųśėwéŗČ’ā’ūæ’cJf¼G!žy<ŗ÷,:£ł¼.\ČG̼¾ĖQ€½.{Ń“QSčé+–„óōéÓō$¬ŗ$'`Ē.ń,ź,,-`ŁŁuLź`ż†õx÷ †µ \`ÖōYš:ę…–=pęāōś¤ī…ÜCӖMq#š~Žų3=¦",X°Ÿž9SŠCz#$÷`¾Ų»{/ģęŲŃvQ5÷’ž÷æ™|}}iZ“|Höā#Ē`ŅųIlĻ‡ĢŸ?&L`Š#fˆ“xŊL•3Ĉƒī…ŒōŅ„“uē…ŸVž$$%& £¢¢£„£ĒŽ Į7‚gga斍45ÕŅK…[·OaõŚÕĀŹU+…Cn‡ٰ@pÜį(,^“Xxśō©œœĢŽ\<ååō:ąEßCq”ä|óꍱó»SņįNĄŖƒŚ9A¾ųKŁ/!Ł{IĘ[S8ģq€ysstėÖ šzš°›n‡iÓ¦ŃŌTĖæ]Žśµė£ßš~˜c7‡vßūī]]]š|Ņ”Ixłņ%MZ‘ōŽž§ż™*w‚ļ £UG¦8œ¢„$ĀŪŹBŗŅ5¢ķ¦óRL74kˆŽ:Ņ™…†õŅ}F¦F0«gćZĘ033C£†`jœ—ö»nŻŗtNßŚŚš¦Š®H˜4@Ÿ”}˜*VŻ­ŠŖy+¦8œ¢g€ ‡Õx9°2łåQÖ×sŌqFöƨኧ#…5ņ§ü* ’ūÆk×®L)ÉHœ˜ŹŠŗuk 6Œ) 44ēϟgJ1Ś·o2Å3ź—PÉP`§:£v9sus‘+Øg]§"g$ l ĖDZŽź§pĄįTāœ(C‡ĆQqś²s‘#šŒ@ŽŖ„ŠĢŃä8œ @¼C‡£rDąéቑ£G¢¦QM¶§xHŚĘ3U9<}ś»vķbJq<ˆČČH„œž¤Šī/æüĀąāāB „*CJJ 6mŚÄGĢØ]J°ƒ^…Œ“Ņ­¬,J“–‹ĄS‚qJBżV’į?ŸäpTŽ( ) VŚźĄ$!Ȃ… °qćFüņk^7Ł÷ø/M³åāź‚čˆhÄ'ÄĆ?Ąvvvōy¾~¾H“ŽĶænĘŚ k‘Ÿˆ¹³ēŅ×Ī’~>ż]QäfęāōEåÖęząu¤¤„0Åį( ) V–źĄŗ:ŗ?~< (Ź‘ä źEĪœĒ›7op1č"2Ó3‘œœLSc/[¶ )q)8ā}‹¾Y„ĖV`Ļž=Ō \¹ŽĢ§™ģØĆQæ£čfŁ©ŅŃ”}ü}Q¹TćõD”NĄßvž†¤Ų$hė(fbccįąą@Ū¤ē°xńbōéÓ‰ ‰čÖ£ö9ļ£É6[µh…‰“&ĀĖŪ ę ĶqūŽmü°ģģܵĘʰf iŽ{vģAāėDŌ6­LI&–,^B]¤'AzŹB’”:tč­p§ćN|5ļ+Ś.ŠÉ“'£]»vLAAA8zō(S€D"Į±£ĒšÅ„/Ųž!éĖJSĒ€SńėjåŹ•L•3Ō 2Ź’,;;[ųß’žGŪ[ģ·²ī=Mvėź-aÕśU‚%¾ł —Ī]ę͘Gh$}Öė”×ĀÖm[…M›7 1Ļb„;v;w ū\÷ŃהDy9żĪų Ļ_%9“^% ~gż˜’wVTé§8¬¾³9ŅįrĄe¦äS’ø|岐%)ŽjqPuPæY©lSÓµšŚščłIO¦JGĻ{R?‡Sā4äęWbPfČhяŹÜČ9”yĒ+n“‡¼ē·•å|9ÕqFö¤)ĮŒj±=Åó×_QG`eR»vmŒ3†)Å!ˆ”-jnnŽŽ½{3•WĶHŁā $­Ų'Ÿ|ĀGĢØ]J°ƒ.1Śv4 ōyJ0GķR‚%k$ó1,‡SˆŅčgéC*O ‡ĆQ%¢4$(FSSœžI§:!Ź»,K7 :‚SGUˆŅ čģ䌣³gCS‹÷ʃˆˆ:SPģš5ĖėĄ‘ŚĶø8»Ąv–-ōµõŁNY õå§OŸĪTÅA¦8I»……ŪĆ) j7  ”©Ł§ü U+zÓŃį’†bGœ>ķ,†÷ŸŽ?v<ž'=GųķpX“µ S°ę-ĢqŠū V­\æs~ČĶŹ„oܹ«’\Eæ^żŠ»Oočėķ§!ÉNŻŻŻŃ°aC¶§ģXZZĀŚŚš)õ@ķœ€ÄiE €Ž6C*łÜęĢ™ĆŌ; ļ÷’ŪĶćļ?šüåsŒ=†:†øqūź5؇W)Æ0¢ļlßµ«W­Ę÷sæĒ°YĆĖn–pŪļ†ö]ŚcĘäŠ(fÕ1™™™åę$Ć’<…$DQ'ŌĪ HĀ€ym@ÕŃÕ¦+Ο9‘Gb¼ķxš9©k÷®0kh³śfųbÜš=틱#ĒRGŽÄł1 × 6tŃSŸ®}нł9UQ€7YoŌ6@E`h`»YvhŃøl¬l0vģXjpG…=zŠU˜³ģfĮ¦‡ }~7«¼…õĶźc꬙t”y;sŗSµ„0Ō2¤9ü8Žjg$ ³3żŅÖR,)(Iˆ™ĄTłCÖŽ·iӆ©ņ%<<žžžL)FÓ¦M1xš`¦ŽQ”ąōéÓø~ż:S š;w.ĢĢĢŲž²!Ļ@f3āāā˜RŒ¢yóęL‰UśD™ŠÕÅUfK™*UęĢĢ̼¼¼˜*Ź£2P>„ĶKXUH$‚»»;Sylٲ…µćõė׉'˜ŖØ]N@ā9–S§¬ŽŲ•ĖW>øÆDi“t“Źä …2żüüh!{÷īŃö•€+xōčmŸ?w/_¼¤ķ®ž#*9—øXåŗ“F.š<ę9œ|"ļGbŪoŪpņōÉŖa“s“”©QśS³’ÕÖŻ¬įäąæ3~4€ÅŹŚ Ē’fŠÅ—3æDе hdjĄŗ§5Ī^ˆ¦Ķ𲣩’V¼šūhß¾= dᔢ4$#p® iā( k&7{į„>DSŖ ’ žčnÓCF Aŗu0rÄHt¶ź sssōŲ;ņņśĖ^śŪŽß ѐĄŲŲ/¾ łU ‰V“÷^ōōōŲ38åuŠ WWWA"•0Å)+Õe@]Q»Y€ģ7yN)‡£ZDä伄YSgAG‹;Ė''§*WnżįƇųłēŸ™RoŌ®.€«“+lgŪRĻ4‡£īØ]]€½č ŗLq8U!J@ŹPIéBi‡£JDiČ2Ʋ¤ćp8Š!Ź»ŒWāp*Q}]ż2%įp8Š!Ī~vÕZŗĪįTYD9 č꼆ÉS'+\lĻž=•²:ķõė×X“hQ™ęŲÆ]»†¦£Fļ%Å@XXS•GZZ¾żö[Śvtt„–ÉT©$éģ AƒŠ²eK¶“œŁķŪ·™Ŗ\H’Ö™3g2•™žūč£˜*™””,\ø°Ų„ÆņP»„ »w) ¬ŹŅ`ÅqäČA*Uė…ß’Ž6MŪĄvš-²2³hQ=żā{">>>t‰lY|äÜe]ś·Łl=ybōČŃ040¤Zd9f̦YגVŹēčÉ£Hz‘„°0Yw hÕŗ5h’¬Z½ 5 j°g–/;wīD»vy9Μ9CĒ®ŠK~včŠķłš³! B¼<½˜–}}tµģ σž“\śÄ±Ń Q^ U°f͚’rE~A‚ļ¾č7ØjčĖ’|OžU} #3C¹Ā”|ų,€‚H Ä¢¤rˆµļڵ+SՇŗ&uY«zb g€Ž:2Uu„PÖĄģ)³”­«XĄÄźÕ«1cĘ ¦*ŽS§NĮĪĪN顎‚Č¾åŠ«W/„ŗy...(˜Ģ™T"A4• qā-^¼˜¶IIõٳgÓ¶"ÄĒĒÓ ņYäćįįO>łDµ]`ńņņś "3ńĶ;—©’¹pįlmm•ĪkØŹ@ qfrqĀģé³éx^Hö…VB£e¹@_½z…Ē3„¤ųi³f͘•.„ ˆ!Ģ÷āßæ_éé9Rņ¬ ó°4ŸŖ c÷V­Z1•‰RTöö)Ķõ¢vĄĶÉ “g+ ĢįTgTiD9Ņ~£ūą•Į8•#J`ØeHē{9Žjg€$įp8*G”€,ƒē—Ć©īˆ¶ Bß$‡Sķ„ AHč.‡ĆQ-¢œtuvÅ») O’Uyd.\ģU`…–ĀĆĆiłgehҤ † ĀŠ«WÆ2„dŅ€˜āˆUNŠs-€‹£ĶTÉTÖZe‘³_YÖ¬YĆZ±£vkt3u!xaGՈŅ@‡üWŗĀ ™Y™š;ėGćōļŽ½K“ķŃĆG4CiGDD !!Obž 5=Q‘Qˆ|‰čGŃ4ĆLjj*K'™uRÓRö Œ¾Žäøs÷mŸ?žę(oH:t²¬“,ÄĘIJ‡S<¢4’ Ņ¹&ōtõh2‘{÷īŃL8d@Ÿ>}Š q\ŗt‰¶}Žłąāł‹š÷óGhP(<Ż=qĄćœœčM~7ģ.]œrķź5œŽz"J' IoE¾‰åŋųķ·ß˜’õ¤™pŽęŒŁ’É“&Sƒ0xČ`üōćOhŽ¢9ŗv銶¦õ‘–›\„ŻƒT*E-“Zhß¾=¤RtīŅæ9@š"Å6§mŲ¾c;¾łņ¬’u=“4“P’£ś˜i÷~šč’Ų¾};ķY$88˜®4Ė{Ų»{/ģęŲŃvQL™2å½ŌY8räS@–$ GŽĮ¤ń“Ųž?~<ĶNĆ?YYYX¹r%Så õˆ 77·2%y“łFŲ“mżMfŃŃŃBl|¬°ź§UBrZ²°ą»‚×!/įü…󂻇»°nķ:aõO«ūmöŌ!÷Õ×_ —Ī_®Ü¼"„Ž.^¶nß*dęd [·m„Ē{üų±£ø£’ ˆš ūĮS¢—ä|óępōČQ¦äƝ€UµsfHŹ–åU_Ov¶vō7ÉLĘņ$+ī¼¹óP˰~\ņ#ś÷éī=»cģȱ˜e7 óęĻĆŪ)Аż¬_·:wĀĒ–Ć¢£Ś4iƒéS¦COöCzäx)©)* Vź3¢üO)7-X˜Š[”čdՉ)§hDi “ dƒ&JIŻśyhČśk²™Õ7Cż†õé¾ŗÕ„]jčÖ@š5h¾<’cĪ“¾)ż»µk£¶imś\Ņ5'Ē2­#{Löi‘ē‘ću°č ’åŹõė£ļš¾L•ėÖhŃģż„šŽ’üó·ŪgŸ}Ę}Gڳ4ōļŪS¾×t„E†!<:œęAČŹĢbĻR²8©ąß&›©©){TqśöķūŽ1H&§‚äę梆¤zõč…/g}‰ųøx¼JxćŚĘxõéé°0·(õĶŸĻŠ”Cß;aƆ!<,œ=Z½„ŠĶŅE¶ xJ0ެ+'3˜šššo·ĀT’&qc<{Š:Ձމ½éĆ„£M‹6“GPZ ’m²&22’µŠ¦¤÷™œ‰Ģ?³„gŠŃՁI]ŽDjb*}~dT$¢ŸG³g—ž‚琿‘D1Õ2{÷ķr¤9LqJ‚xŹ÷ģŁĆTb›}ƒ²–|Ä< @>G¦*UĪˆ3€“3Mø©ØĄ×ײ ˆ)Õ3|ųšr›'&Y‹/^¼Č”b“hŃżśõc*o°oß>ŲŁ½K&Jr ĢÅŹĢŗ–µk×āĒd*7bٲeL• ńņ™‘ŹIłdddąōéÓ;v,Ū“łĢɰDfΜ©tl†*}¢4n®n4€¢)·6oތ%K–0„ZHŗp’r¼wļŽlOِ}ĖaņäÉJ]ä²o,_¾œ©¢ €¾¾>ŻT͉'°jÕ*¦ņ ’$ó°¢$%%QĒ^a@ü idßžčÖ­›B@Łėīäɓ4 ‹žžŪ£jgéŬh€€ €D"Įė×3ÅG¾1ŒŽw¼‘Z™ŌīZ?1’B87+š:uź¼÷-] €8}{÷–˜» ӂgfe Æ!Gbāb„ŌŌT!5-UHNN~›j<&&†žNKOd˜@ĒŸŃ¢éžāˆ‹‹d]v¦ŹŽ¼Ś€‰ ‰¬%ŸĀiĮåł8åGQ>€÷ŅŃĖ.­ų¤x&ä#ė) 2£Ę”āØ]$ ¦TvZ„ģõåfåā¢ßE¼L|‰Ū·nćÖµ[šńõĮĄoæM¼¼½čļŲW±øqå9·°°@żzyYƒ+“GQš ņSœ*ƒ¬Ćpģč1Ł7*ÓUQ<¼<š2ö„ģ3UĢY {{{¦€}ö”e³–čŲ©#¶9 %>£ĘB ĖhbŚ„>wįW õ4 Ÿ=†żV{Zīkš Įh×¾;Š|Č€,tiٲ%ŪS6Č¢żū÷æģŪ³³fæŸ8“0Ó§O‡„„%Sy?@ABCDEFGHIJKLž’’’NOPQRSTUVWXYZ[\]^_`abcˆefghijklmnopqrstuvwxyz{|}~€ż’’’‚ƒ„…‡»ˆ‰Š‹Œ°Ž‘’“”•–—˜™š›œžŸ ”¢£¤„¦ž’’’Ø©Ŗ«¬­®Æi±²³“¶Č·ø¹ŗ¼Ō½¾æĄĮĀĆÄÅĘĒÉŪŹĖĢĶĪĻŠŃŅÓÕģÖ×ŲŁŚÜķŻŽßąįāćäåęēčéźėīžļšńņóōõö÷ųłśūüżż’’’++£ūī5 &’płņe± ™„õü±™āHCCƒ…˜4>;;kinn¦qwøjÆcšp(ēįƇLZ}ˆoĢbv¼ķsµŽ8óvœ—n:īīg9ć/Ö6źėæ²ŌÕÕ1i™L &”——£ła3š”MTSMŽO’OFG5hjnĀćÖĒø÷õ=(źčéė”eśśŁV””!ćŲxÖ×ĖbĻČčżg­w4XĢŽļM<ė†Ņ›eebrr’„2@­V£µµ•%ŁéļļĒ… ˆ0¢¼¬)IÉh}Ņ Y† f҈ƒyyōŻ*yŹa~nSŚ ~ē=üåÆÄ[9½)) ģjāTTT`ėÖ­L²322‚³gĻŅ—ßžļä±+UUU c’ą“įŅ„K4ŽüM3nŻ­ĘO÷ē@=IŚ8¢FL|é„1üö7æ£eV›ū÷ļƒhmźčõzŅ)Ų»w/Ėu¦ØØ±±ģÜ9;O¢źT!3k7ČX›ęõHҰgĻtuu£¤¬©‰‰0…b§$-­Mx7æŁÆæa­ģ%}ōäü8—|u1$…˜0>ö§OŸ¶pĮ_T |‹u¬,0zÓhw“?žųo0萔Uk7ŽĢ} ™ŅL“«Śš“ė)~’ᇓœ7\æ~;w„aÄW'ßś]OŅ3¤,יĮAHR%LbøZ;ŽgxÜ­-[OkO¬ŒHž°z˜ĪŠCaI$:žćććŸš†Lś}–kå³¢ĻǤ™!.é¬q~@ŪPZZJ\ę4Ļć€Ķ'1õųóŸ.#cwQ x%1[¢¢139ˆ­[02Hż¹ūsYg|ó*Ś»ŚQ__’ĆĆįpĄķvćᣇāöŽŽ^ōōõˆėBßl6£³³ó‡ėdž’‹E\÷fęn3†ÜC¬"ó…Żn‡Ćī`ÕOKx±[½¦ū&h 4x.ä9¶u|ó*†‡‡ŃŁÓ‰żū÷cppPü¢š®5”ōh©ø½ģlö¤ī{ȍVc+ŹĖĖQ|“Xü³‚’¼ƒĮ ®{«ī¾nčuzžˆ³†ŁvX-Vtuu‰ĒJhĶfė¾¾>ttt`Ą6€sśūūÅķŽŹbµ D÷Ó–ōąpŃa•į£ŌšęŪoĀĻߏmŲ¼ €°%aXæ~=BBB…RŖŚ*„…ā+åHŠOĀ×W¾†L&_#“< F{ެ¾¶;¶ī€B”`Ļ9’sy…y8Rx½=½ųäš'b_{J‹6s¶§lGEeRv„ ģoeČÓå‰!€ )Ć\‹1Är‰PNG  IHDR@õ]©¾sRGB®ĪégAMA± üa *IDATx^ķŻ TTuš/  B3\š,G8j mĒ)ö(ńPB÷dj%ˆHėY±=éŠŅ†I”v “£å.˜J¹ę¦Ę3u3÷ųą10Ą ĆĢņ’ūW4É@^3Žß‡só’Ż;sĪÜļÜūŸ’½c¤ėBˆ$‹ß„ ¢ DĀ(‘0 B$Œ€ £ DĀ(‘0 B$Œ256_5ca65f06163082f(’’’’’’’’’’’’ ˜ 256_df5c3c559487929f*’’’’Ņ2256_6ab426aa68982ec3*’’’’’’’’’’’’-×256_4f104d92e98e83bc*’’’’’’’’’’’’dŻ€ £ DĀ(‘0 B$ŒN’€¶Ö6\»v ZVT†ƒ½ģ±­nĶĶĶØ­­Åp½“LLLąģģ cć{ßß.W]F»Ŗ]“†©‰)œ]œadd$*†ƒ@ņrópśĢiŒ3FTśÆ££UUŲņŽQé¶cū(š°µµ•”•“ƒō½é°¶¶•nŽÓ¼±,b™h Œ“Ō49v¦¦¦¢b@X‡[ff¦®““T“†R©Ō­X±B“īöĮčŖŖŖDkč­\¹R§P(Dėn^^^āÖĄ Ņ©ÕjŃ2,Ō@ˆ„Q"a„HĮł’žGāŪ‰¢5øäĶr¤$§@Ó©żPYY‰ŒĢŒaūäbøPäęaIŌŃ\‹/¢Ć²Z O@hX(ņOäóyłyłųīŠw ĮŁ gymØ<6ö1”+…Z„i øÖ¶Vü\ō3q•ĮUvµ nvnŲņńŒwĻ?2,Č*Ą¦ČĢĶDśéX»a-Žģ;"ī14ĢLĶąžœ;öģi qlΜ9½ŚeeƒrvļŽI“&‰J·³Ļ"ó½L¬’d½ØōNkk+&NœQéĘv§óóó1nÜ8Qé¶ōÕ„ˆ‰‰ææ?ÜÜÜų†×Ö܆ŌōTģß·ŃŽĘ7G¾AéÅRÄ®Š÷ź›ččhüōÓO|@Š/]¹rååå¢u·cßCÕł*,YŽ·½”ąą`“··÷i Pnnn•† b˜ŗ@§Ńh~sŹČČųÕq—®\ŅŬŃuvvŠJļ°qĖ—/ļq}III=ŽØ®®ÖĶ Ÿ§«æQÆóŸźÆS¶*uõ õŗseēt•u•ŗ”䝶ėgė‡[uEåEā^}ĒĘ444ōų·Żo@^fž.é³$Ńź=6 +{\_O“ŸŸ’­čĄ€±w™Lö›ÓżŽi\w®N‡–ÖQé=öø}Y_ƍL=ö¶ö˜;/¼šĀ^ ćĻ£āZ_F£Öąŗā:\ƹšöƒźéļbÓż/F˜˜hõ ŪŪči}=Mś4d˜€ čå ”œ*­ĮćįīÕ›VóŪį Āńķ7ßāpĮaø{ŗĆg²–E.ƒ©™)6¾µv¶÷žc0˜źjė`ņ{Œqøį҆€€Ąū)oŒūݽĒėƒįĪw?¶§pēŽĀ­yĆńicmƒš°p˜Čīķ7x˜Q˜0Ēx×ń¢%Mę–ę°{th÷:ō!F°€€äääˆÖÆ;xš ŖŖŖąāҿ޵;©T*"99YTŗmŻŗ•ŸŠėąą *C+%%{öģØtc]n޼Y“FBBŽ?ŽėӁYēēW_}Å;‡€ėm( TTÜģeHöööprr­nr¹œ_€d8yzzöø±1ZķĄ^…ac,zŪwA@Do€č} €aļ`łÓŁŁI“˜(ÉPö=€ų­ń(;Ys3sQ‘®šĘ¬[·3Ÿž)*÷G{†‰īˆˆŒ=ZT¤ėčŃ£üE1s&ĄĆŒ!z€¦V«Ń©ķ­¾£ Ä©;ŌČ=”‹Č%‘(*+Õ¾Óėˆ Äٟo^FS§ĮŖM«ųķĖ•—÷øŪ—•bŸĮNž<™OOx>«WÆņ:»6=;æœÕ}gś¢¾¶Z¹sų|F[§Å‹s_ä·YwČźæ¬Fń¹bŽ>W~޹õŲAĮA"^Ą%Õ%ŌČkų|Fa”@­¼–ß–7ŹįģźŒŌŌTŽ®®ÆĘ† n?öK/æ„ģģlœĢ? ___”””@-WćdńI¾ŠīÖ²ÕEÕp“wÄS¾O!((ˆ§±ĢDūQö|„ e‹»?ßŲØXĶBņ;ɘ0e‚˜Ū?zVvV0ī4FżõzŒ= VVVČŹĶ€§ 91mŖ6455aēĪXó·5Ų¶k¶ŗVFV0õ0…±¬ū)ŚŁŲ”¦”Ę:c¾<Ÿ>Ż ŖėPB ģÉ؃ϲ>ĆŃ¢£(’”-–-ü£¹ķŸldz>ĻĀŚŁ>³|0Āb÷·>īSÜ1Ńu¢X!ėóŸ#q]"ŚŪŚ‘–‘†i“¦a„l„˜Ūż°jÅ*’žøh=öĪZ\\ü«ć2÷fĀČŅĶ7š±čO‹šQĀG\ČĆ iw|ŸöŚč5|w¼Qш%įKšį–ł‰/ĻĢxūöķƒÓX'~ńĖåÆ-Gܚ8,Z±'ææ¹Ū®‘ką5× _ą­o!aujÆÕņ½‹ ĻM@Ē’:°`Į|}āk¼ūö»Čł2Źv%ŽXńB…`žēß2żĮĀ&22’?·Ž`Į×Ó /Dæ±½ŹŽ~o¢½ƒ=Ņ’™ŽG{TTīĘ®-čččoooQé½TSQƒ„Æ-EāŽD<īų8²Žfaqąb~Ü_R^‚Ć_FZV?T`N’xQÆFaoę^ŌÖÕāĄŽ]OŅ5õ5˜7wfłĻ¬ٳpāō Œģśa‘ŸŸ"VF`ś3ÓįįźĮ;Ć_Ē<æyPš(±pįBžŲ‰É‰5Č {W6¼|¼ŗžƒĄāšÅ˜ävļ7ūŖÆČĆļć>ʙĻ 04!~!¢Śķ”vlŽŌÜ+ė›ļЬž]I–aĒžŖvÆYŪt¬¢I‘#Gņ«»(•JžM¶ĘFĘ|öt[”-ütU#¶õjfe3æ»0Ę-ģ~¦2S~dfvs}옟­ĻHfÄßĀÖ5ß K@~‰}„;{½nŪ“ ˆūkʎ ™ńĶQ„ż ½īąŗ¶Q¶›Ė6`6ŻŚųv9) K‹»6~ĘÖĘöö„ŲĘÉzJmlmųéšģ>ģņO|ćgŗž, īÜųv?3s³Ū?Ć6NĖ‘–°0·ąyk2ČÆ…&½ęm¬l°~Ėz¬\ø©ŪRæ!ņ¹X¢ō?!ÜŌ?LÅŚwÖ"lv‚Cƒqøš0›ÅÜC@ˆ‘™Źąńœ ¾,@cM#Ņž•&ę<½č˜1cæŗŒŌ:u ®®®Ō@zķzĆuXXXĄŅĀRTśfŲ€]¢©¬¬L“ČóĻ?Ļ;u Ć„įC}„H!F@ˆ„Q"a„H!F@ˆ„Q"a„H!F@ˆ„Q"a„HšrŻd·:Ü2+IEND®B`‚ĶBō?čÆŹulŗĄéIEND®B`‚dHJMĀh—ŽGų `¤ćHDEFaź“©Xŗl)JJJ„-%9y'ņŲX&­śVųM÷CčÜPHō L™<¹y¹°5ŲBoŠćņ…Ėˆ‰EBlt :n«sŗŗ»0fĢØT*(”IeBž÷Ŗć|}}'¹f©f!==«Ō«łC$|¼}µ2 ¶¶¶ĀōA_ ĖmM“÷“šö‡ ĖXĘž}ūqīĀ9ä͇£“#RRR ŃjXƕćŽ0__ܽ~—%,‹?IeļŹĘ„«—°!~T3T¬§wę#‚£×ėQx¼ŗ.Ė ŽŠŠ Ö2³3Ų”ĖŲšūŽ›7[=7¼ĮW2åT%\>qĮ©“§ ‘I “É •K2'Eæa‚ßa¹ŪŪŪ±2z%"¾@§“S˜žß±GŒŗ2{Yē±?ē6å‰PNG  IHDRÕøö.NsRGB®ĪégAMA± üa2dIDATx^ķéÓU‡[qßQe Bˆ  D6!,ĄFĀRĖr©²Ź?Ą*?Y~Ą² " a' BVIBH‚IÉFd“–„L „-0ösŽ>/÷ķ÷vĻLOwĻvžŖ®éīéémīrsīG*!a]ÉG£OĆ0ŗ+ £‹±Ą0ŗ+ £‹±Ą0ŗ˜BG¶mŪ̘1#Ųc=¢=ł°iÓ¦`ģŲ±ŃV&L>’łĻG[}yå•W‚Ė.»,ŚźĻÕW_ 4(Ś*Ļ|ę3ĮI'ÜsĻ=ĮæųÅho_^}õÕą’K.‰¶ #g(Š"L¼•^xAÖ’żļW6nÜXY“hQåłēŸÆ¼’žū•0#Wžzź)ŁæjÕŖŹāŋ+kÖ¬‘ćÓxōŃG£µŃ}|šAeėÖ­²®ųŽw™7ož|†Vå¹ēžė÷ū¢˜={¶|źż½žśė•÷Ž{O֕j÷nPJ ¼N°bŊ`õźÕĮ‘G<łä“AXk×® Ž}÷Ż`żśõA˜ń‚§Ÿ~:ųųĒ?ż*ėÖ­ >ń‰OD[õf¶`ٲebMüéOŠö–Ēē>÷¹`é҄іaOnM€¹sēŸüä'%³ä#‘Ļ7Žx#8üšĆƒÆ}ķkĮņå˃}÷ŻW2ŲŪoæģ¾ūībcāŅDŲ¹sg°}ūöąŠC 9äč¬~f͚%æ½ē9ļ¼ó‚—^zIösMå_’ś—d.÷ŽÜO #LńŠś^|ńE¹·}ģcĮ!C¢3Ć5×\ :4ųß’žœsĪ9Į[o½%ļL” Åż”ļ£L’ž¤O—Z’,“2ÆwŲa‡_ųĀ¢­:_L.ųLU· '¾k¹ūB«"Z딚­M€²‰7āę?T»wƀ… Fkõ‘›¶ńƒoūŪŃVXģĻT2„@mī¹ēF[=Ģ™3'ųō§?mõ…väȑŃVī¾ūīą€ˆ¶Źƒū„IōŠC‰…āćõ×_Ī:ė¬hĖ0üųņ_-Z†QYóŸé £‹±Ą0ŗ+ £‹)“€So޼9ŚŹ†]…!Cˆ £ł@[°ēž{F[żAY˜źĀĻ~ö³Ń–a“&-Ł@ļūÖ­[%ę½ &raŪwĖ’%K¢£üüē?’ńžŽ…ļ £S)¼ @-Mķ‹ŚŠæ÷Ž{/ųŅ—¾$jĄ×^{-Ų°aƒĻ÷|šAƀƒmöėņĆ"ŠļvŪm·>ĒŖh( †)9ńū;ŻgJnMŌvqgʰU xÓM7 Ž;īø`ęĢ™¢Ś[¼xqš©O}JōØųFŒģæ’žĮŹ•+E:Ģų8ųų揗Œ­LŸ>½  礠”°pæóݛˮ]»D ųģ³ĻŠZŃ5ł›„0ŒzxóĶ7ƒÓO?=ŚŖBūØÕi—S`¢“‘“įæüå/K-ŽØ‡ĢŹą=ˆWĄ /¼ –™9ģ°aĆz ųõt›ßį °×^{EßTo͟?_ ®õo|C %%kŪŹ0Ź$s:„ČŸd5‹xēĪāŃ?ńė¹ŪœĆ„šœV„Ąaa%Ÿ.&Å5ځ¬é“P ŸE‹%JtžO<1Ś ä:IņĪ;ļßłĪw¢­ž<ųąƒb‘ų  R“Sa4JV Ą¤Ą†ŃdĶ&2Œ.Ę Ćčb¬0Œ.¦Š>„?tĪ!Ņi†O;ķ“h«?(öŠųˆwĘ)3źN­p?ƒV­Z%Ć£>N=óĢ3£­šż,$'ŅAšö]Ē·¾õ-Y' 2īV‚!d†ƒ_~łåąæ’żobd4#ūķ·_“ågćʍ24]jÕÕČÜG¾aˆ<#UęHū¾Śo›( ½ēzŸkΜ9ŃZsŠ{š>}ŗ|śpļ;ķłšEXˆŹ'AjÓØ%ŻŌś|¾‡¬æ/„ ^GBo7pŹ”)ĮĆ?L›6-ųūß’.!±o½õV©1ņ€Ś’øzY@ŠLPĪGy$X°`Üć¤I“$ iÜ÷ Õ”ęįYĀD*B§žóŸ²N<ÅĒ\YDQ¢ęąY©‰‰L„’ćųĻŹ„pņäÉr?X=Ü'ówŻu—X5 .y;Ć{æķ¶ŪÄŖ@ņŽ ģö»h½!ųÓØI&Ņ…Øæūģ³˜‚Ļ<óŒ˜KŒ·cņa>ń=cģČYG*œ™śłēŸļs~wA ŒŠ—‹āŠÕšūīĶ]0ńų J@¤ĄÜ«å÷§œrJęhĆYKtI$ddŽ’&Žū\ś>ųŌ…ęĪ€$C³ ĮąY0gł-ͱ©S§Źļł/Nص&愐FI°Ņ~“žśkāŠ„’“f`ܟā±Ēė}6äā4įŽ“ø>*R¢ųi ž$ó£Ö,#Š&ļ‡÷MZ8śč£e*žČŃQ«bā'-¤=’ž%¤5žÆ|å+љz ģj͉42’>¼±\š™ n`×®]ņłę›oJģ~ŌzŗÜuÕLżžó„A֕jæUSŽ`¢į-s„ ·¶±%P§/XgŃč=»÷Īūtń=—6ōYx×< ĻÄĀūŃwϳé6ė|ś‘µ¢÷¤M€ų=ƒ{ßŗ®i‚{Ö{Ņ’€ū.ó?š5¶lŁ­}H½M€°÷żžĒ÷_ÖCÖßī @­„Š(˜ągŸ}v“ÕLĘ$ŦpZ`MĢcœZ j:…hŽ$ĶZōÄOH8q—‰'¦vx Ö“4ķ’:µØYµC‹ć›ßü¦¬· š^°TšKI²:pVĆ*I#̘ĮĮm%S-}W#k'`”§ĘœĖĢQ¼ü’ G3ͦ[ŅŌ[@ó”Õ §œ%¬ eI".anö³Cf’{RŅĀŁJ£ W{¾f@³ƒę^X['ŽĄĻÉó¦A³¦M5Ŗ„ļj“d`i1ˆłąƒ¾ j^śņ„‚'Ž–ļ¬0Śš Ƈ¶ś‚yMēćńyĀģOt:wYóŸ)¦A“(ŚŲ¾…ęV€nõ«_‹€OFØ·( 賦yG? Ūīyā‹Ń+Œ–‡¶ų_’śWé(»ńĘe,:†0ž¢˜!¹ß’ž÷2 iŌŽ5ŒR˜={¶Ōź.t2Åz‹ÆżėŃŽīæ’~éŌ3fŒŒµ“É÷Ž{o9öĄk€±tĘÕO'“łé•O‹āĢ„¬ĒsL“Õ: × Cė& ™ó@4:Žit6¾ō1sęĢh­?_Dš ’h­õH“OW#ė»2 Ą(_ś@N īƒa1ś’ęzČ CmLAߊ yžīwæmÕGÖüg€Q –>ŖÓŒĄ: £‹1 Ą(_ś “>4č4ܱcG“'iŲwFŅ„Ft&Ŗ 8ĻūPdk‹/}0AL’Ї};øÓėŸŒFŽ)ėøI'ł©0_äG!²`øżöŪsńĮ ū‚ .ˆ¶śŅŒĄFŒRš„“4Ćwa­[yöŁge/ŗ—_~Y¼čšŌļš"|żõ×å{ö³†{Ķ“ėćQŗ}ūöhėĆŃĪÆ×bŁŗukeŻŗuņݶmŪä;–¤ūX“hQ“֟fŒä Qf£³”ęÅü&„.Œć'Yˆ|šĄg¤ą¾ūī žzź)9L˜š5Læāi‡7'|„Ÿ{å•WRćJ FAČõ‰‘4"€ŸŽUŒBp,ž­tŽš`Ä·OMΧÓ×Ō†€*hxVŸņĻå¾]ø÷C9$:²>²ę?ė4JÆ9¤æī¢VHüńxŽdR׃±nĆd*žąrLĘ£©@&ĘõųØ£Ž’ą"iø÷”‚!2¹ÆĻõõX…!ёG) ™Ž¾ –0us_²¤BzĪųŅz ĘÉj‚݁/}¤„¾s›yį^3ķśIM€Fiµ&€u¶8ÄéĆdL‚•üćG[Ašē?’¹©BLå‹/¾8Śś_ś ƒ/ &‹=łä“%~¤vÄå–įŻ€0uI±łø>UtĀx…8"5 Ķ f±öįv¦ż4‹āŃ ­°Cqß+5ҦM›śŌLń÷īF¦sĢķŒ {%ĢtrցuĀoår+)XśØŽkĢž=[>éXŒć{—Y߯õ“ »vķ’ö.PŌśÕ$²Ł?~¼Ō$D×eżę›o–ŽØx 7nœ„# 0‚ļ½÷Žąŗė® žńH§R]£¹ŠéY$Öhqō½Ņ  ē›Ī1:²čŒB+OĘ}’ż÷££{:ψ·‡»,Žv˜²ō¢ó{¶/¼šBÉōtzaŽŅłD;`¾Ó±…‰É88Ńkė ČA(u_˜,®Ÿ%Źp7Aų1ķųŌ’‘PāĒ{¬ģS(ĢćͲq¼YPy`&^1øļSÜØ½ń÷ī6š„ƒ|Š&€žē.¾wœõ½›Šā„ljĶÉXŗ«,£vØ% mQ؏æŃi’#_<ņsÖüg€atYóŸ5Ź £‹)Ō §y¦Ž„ę%ńÉ$č,”§Üūu¦}j$žzP¼1ÕŠI–¤śBNŖ³ęF=d¶Ą)ņĄ× ¶s›ŲÅJ*­Äż®!”Üė§©½ŅžĮ0ŅȚvJi„ב)«Pµa0œÅxō–-[¤ęf¼™±jjj†Ø’n5ŖA„YĘæ¹8ŹGwųĪ0šAnM<”˜Ų*œ3˜y 欌I#Ēd?ćžĢK/7²L¤|—$•T®æžzqüpQ‰%b<ŖÜ±h÷Ž?żōÓ„ a[D5˜ä£G–ļ‹oµ½öŚKÖkg>? ?īÅõu§ä]F½hŗ® €<š™ n€QńFšf¾Ź²eĖD–Š\•YV7nÜ(žÕW“&@ų"*aķ*ėŠ{oŚ3b%Ģür½Õ«W˾¢pÆÆM|ČńwÉjĘFÖ“SŚ(5 µ?*3:Ĉ¶B„jf:與Ž% 5eVčH«%‚ µ>Ń`ø^VģFĄ·µ—a4“BG0ē™BćŖå#4'\hÓPĮ~ć*œ` ģŒ‡l‰-ąń•¾å‡vX“eµ“uĄ„@†ŃdĶ&2Œ.Ę Ćčb mėmÖ¬YĮī»ļķÉĪżƒü Ś DGĄ‹>pPa’Iøį†JķōC—@ū_'}L»>ŗ€³Ī:KÖé;ÉéÆéż$—\r‰„äNź axōŅK/¶Œv sœ |Ćī0ą;ļ¼#Ć^|2ÜfŒŹ»ļ¾+Ÿlóė,£ū“ˆ_ĻŻŽ’ĪżĪU2$™v< zĻśõ룭ڕ€ī:ļIļS?¹÷,čyõÓw÷ŚF{õ?ĖĶ RM\ŸŠ‡h®ˆ[®ŗźŖŽĄˆ`ņćųšĘ„v$ša–‰ŌJo8ź<†é“FŒC †ŅĀ3ŸqĘrī;wö% Œ³ "śhł>oC-[¶¬7d3B%˜"#ƒ ’õU«VgŸ}v ņnyVż«ˆ‘Ē:”§y^f×įłuQŸƒ$xǼŽ/ļ–č@ų*š?)($}!­Ö…ōLdäzÉ­ aÅē]GīĖ N0$n2üóĻ?/… R`ĢyęF'#bĘ3W<ǐ°5€cfuq3-ƀč P’xݹč‰#ÆŹAQR D=H½āŠ+¼Qlņ€ó³] ī›Ąģ»$ćiF©Č³#U¦@[±b…dV  »Š¦ Ķ öń —_~¹ü> Ž?æ!dA7ßxć 1ł]ßs=ĘhH'ń5A>¤(g ˆ_O·1iQų¹øĒ–ķ ”Ō@ǽOßūĢ=Æ~¢ĪLk2ķAÖ’¬ŠN@j¹šĘśL𐪩WčŌJ MĒרQ£dż¶Ūn+5l6.Ń\«Ņ®’öŪo§žzŖ¬cQéÄy¢„čdt­$ü#ÜV£õÉŚ hB £e”@¤łćƒ¦„ĘU­>éo*š[qē·f’5’™ĄhYpĒ‚ņ-ōė(X5ōcųŽ+jĮ²ķĢ0Z–“4å~ĒH µ1z:Žé „łÄ:¤t–Ņ Å¢`?µ7V“ŅéŒC£Od…Z£WµZzĻz?V-Ӂ‘ RW,2ŃĒĆĄ¤I“dō‰ž Ćčˆ‘Š‰ŅŁy)ČųŌę{ļ½w°råJ±$~ń‹_Ō4™c‚ó1L˰u³Čš’¬ `“ >¼W;AĪD%.z ‹’‰©Č>†5UIFg˜ŒŒŽöŒ‚žƒŗĢŽeĄ2ĆŲxŽÖĒéõqm§ iK°ņĄ†ŽŒ¼˜;w®|¦„)÷;‚ÉųęŠ+÷ś éą„™dĶ…6˜7}ńā҉lÜ(ŗK—.M,…é1&ų—°ÖR>ؽøG5ńŠyéć`ĀOųßČ>Ę«‘¼ņžØ9Xē]aåPÓR³0ÜÅžų9ć ×}_ Åß»z »Ń‘JĒעÉėr?ørӹŰ– ’)ū8·{ޤŽ^' Ļ„ó\øK«Qč(“¼(Č:VL[sŽj/uwÅ­¶lHŚC)ļft2”ŠIhgŃūN9pą@iV$µŃ¹WuXāŽ-÷zķ…)#8IPH!+ė(€) £Ț’L h]Œ†ŃÅX`]L”}tv1¾ŸÓ%ś”óūUIA!ŽjP:h’:įŠ‚N7ÜR÷įŽJøŠÓÆĮ9Ń5Ń H‡(#Œ[ćFėƒqkā7ŗć×Fk“¹Ž |ćč~ļ½÷ YWX÷Ć2žüčØž™…}ǵš\Ą”)S¼Ē±Ōś<,ś.ųæ|ß³ Ļ`–e£}ئ Ō>:8…7ØłXT.ŠsCvl£rSG ¢ąņÉ6~‘Qźo“·†b]÷c øĒ1†­ 4Ōż\ 9«{l‹‹{żųā{īįśLXX08Z¹æ­uqßŪÜŠĀųqFgęq‰M~#ĶÄIl oDŹX+ŒÆ2$Śź3ӕ# kIĢEÅb“™­ęĪ;ļ šr$ĆÕä >)0’UD6*żŸ˜‚ˆB>įYbŖ×ļ )0…&ŽeĄ’Į\œƒLJ‰ˆ†Gž³_žņ—rl*¦š;v¬ģ#4»+O„šEŽ[kt£łųņY›ōƒ”›’Ü×L(“€„J K¢ę|aqŚsĻ=E”‚ŸÄĖ'… !§–Ƶ²š8Ľ¦®£qē‘4#{`Ĉ’©Č@[‹^=+ˆihw“0/÷ ć{ C I„AXØėŠ›SsS˜QŲQ«SŗÓ¾OĪGĻė^‹ĀpŲ°a²\‡Dc“ī’éBEB„Č“ó¤„~ĒPäAR@3܁iĒŗøßµŠ;phĘ˧KŅó䉞×=hADk=pæÖŠ^TK/a\™4iR“õ!…ZMĄå–š¾8ÆĪ„9OóĀ5Øœ3`!ó$yŽi¦×ÄH’‚2Z`ŗa=ä ļļĒ0“‹Uį«&XQ\ŒüI²ŖaR`Ćč²ę?Fc€at1VFc€at1VFSč( ?ö×2ÕR½żA2gĪĀųpÕwØ U”Ó*Ō:L‰XźŒ3ΐuäĶ 1Å%’7¢!I>P&2'‘Ž>!Hi„”EUēŸ¾¬ßsĻ=‰aY„)EyιsēöĪVœĆ«§vZ“•/™Gį(ņĄ'D(Ræ^šĀż®l!P-ø÷Wės¤Wå’M»÷’_»vm%Ģ(²Ž*ø÷>cƌh­?ÕŽuXÖ43P‘’YÖsļö»Ø,h$‡ŸO”ÄCƒ’ü£H‰8oŽÄCģwå¼qā×Ómj{j·4v„ĘBf¼aù܃łžOäĮŌĘ|G`Ѳpļ/ž\.¾ćö .ĀŚBæĻūć]"?ęłŲU¼s–/_.¾ė/‹…ĘyńGąõŁÖć³opŽ;vČŗāž’n@ļ‹ė»ėz’ś Eć¾CmšŽćøĒłp›¤=ī?,XS}Rņ&ė¹ ķ¤6 oLfÉj®Q£FE[A0uźŌÄėø³ąÜ|óĶāÕJPėą”“'O–šŠµ½ĪüĆ{u}ūĖ‹‰IFÓ"Ńi‰σ‚•XęžÕĄbŗč¢‹dż–[nI“ü° ™V< žkF]ӓp;£ó&k' łF5’™Ą0ŗ+ £‹±Ą0ŗė0ŗ¦&GKįƒįٟżģgĮõ×_ŸØČb/¤„2ē? €<(rˆĆ0Š"-Żjķ4•  Ć›7o޶j‡Põ’5’YĄ0jŃŅ}÷Ż'JÕńćĒːņ„ ‚æüå/Į¬Y³DX5eŹ”ąŚkƕHĖķ€FWr÷Żw .3ĀŹP¤ČqP2j—(üP ¢ ä= ”wķŚ%ŽOØŃŌćp†š’„°š„Óc4Ž5ŒvBĶz7Ż¢Nu©· m4’‡²žÖ:®ē#Ō}XIØRšöŪo—‰lŠĒ·ć?¾”<”õ·VżĄ,Ę;.Ķ! IļqĒmÕ&.ęr³@ŠĢ TxjŠJøyˆ~œŗ| =vca@ęüGÖč܉ApąĮ©‡uŅį3¬9e½Ü4‚Pئ޶*•·ŽzK®>•7Žx£wß;3[åĖ—÷:@mÖgĮ}?³gĻ–Oß³ūņš5ŒÜ ¦Ō©ĮčĶĘY‰ų8³Pė“d觬ԙ‰óPcaą¬nĢŌlLG‡.øDFbŒœė‡…Žøó[\ŹŁ÷½ļ}/:smąźM$),Ü¢uR™VI`Õ! ·h¢Åēm_ō"ó²^¬0śį y 8PD˜C$Ć|‚“[ėAÓ„„4£`^H<;¹ƒš B€L` ¼ )šā$ć³Ō3²V(\x ‘< Ę3^sĢ1ŃŽ|y͚FnøMõg³ņh4· Šźh ÖųÖ0rƒH6˜£IQyH2Œu×+}ä‘Gš€&Čȑ#›G”VÉÉ’K-VA-X`€m‘Š’^?qūh+ØŌčk“ŃŪ”ķÜ­dĶ&n"ōš2—o”—Ś%lćy+c!x&…•ŃyXŠDØįіūBn»0LĘ~ŚÆńc‹^’&*1Ś+J„ą’„ĄÖ% †ĘÜcÕügxģųƒÅ”„,ŗsļ‡8ōFūc@‰qzč¢čœ.ˆ]ÜcµēK€qł8 8āˆ#d_ŠćļŽQ~öĒ €’”#M…¹óāą ā;õ!ĪQ±!j) ÷^Xø?£ż)t€Ųń3fĢ(d^:¦P†©—˜zŹ5ģ~ō#Y7n\éóЁ† Ŗ.÷=ųąƒŽĢŌōn ŸvlŃą’Ž*™“”ZzÆŗź*±|ģā-Fv2ĀQäO‰äĪ ƒƒĒöķŪ+›6m’°I” Ł«6ĆéǶqž ŽŹK/½$ß%±cĒŽŹźÕ«£­¾×ē.īw:3.ƽöZ‡”¢ŪķrOYÕZ­H-ĻņšĆĖgü’€Nz­@Ö÷YJ ¼Žų]3–Ķüt8t¬\¹RM|GԆĨřX«‘,PŪ¢ųŖ×dž¼iÓ¦óēĻöEĄ…DÓ1ZÜšx(Å'ådYĀ$įIFF#¦RdŒ8|`²płŪn»M„/|GĘĒ”G9tčŠčLżĮ9åč•KŅÜĄ;ŒÄ†h…ó)*ŒgM¼¦–,Y"Ī-8—pŸ?łÉOäū" kŇö:œx˜WŸ’„éĮÜ&Ś]wŻ•(u5ꃔZF˜Zŗ ącéŅ„•0sö:™ŌCZ€‰]Üļ“ P&Śč6“ @:ˆcM€|Éś> ļ\°`A!Wø2¦€4-’&gdČj̘1²~Ć 7$FZ) \Y™Č“•&Ę,ƒo¼1qØ—Ž3Ī8#Ś2%k' łF5’™Ą0ŗ+ £‹±Ą0ŗ˜BūčØcü_‡ąņ„Ą‘Ha * ÄØKņ—GÉvŹ)§Čz3utxßmżśõ2üéƒįȓN:©ė: |ČÜGY†!m0N« ¦Ż£Ū0ź%ė0`iJĄ‡z(˜:ujļükŌŲØń˜LqöģŁĮwÜ!Zy–eĖ–É1Y &­ÅS€sēĪ•č“Äæ+›§Ÿ~:Z3Œę‘[ą–[néēų: ļ5‚Č|Q,ķ·ß~ūł-eØäˆ5ü—0ÓØå0“Ļ;ļ¼č,~PR p>Šß 1Ę]Ö h‰PUhü%  … /F-ßψCį¶ĒŽ+ūāįžQ@®]»VBqF=वmŪ¶Önlٲ„2gĪ1ŪĆöJećʍ•0CˆCa¦ ƒLŲfLåjŽ@ŌĄ±ˆóŗųš8į˜Ä}­[·Nö…Æ ZŃZÖ0!k ŠN@œ~0ÆŃęē ŒĢĆd0}śōŽõ8˜Ū:‹ĢųńćƒįƇĖzYPóÓ É$q _|üŻ@ †Q+Y; -85Ī7EĮĢ2˜‚9Üq>ńĮ1:Ńe³¼Ņ(¬ø?kŽĒFZ²0 £²ę?Fc@įÕ' ƒ€‘ mä$‰Aea4Ęč,ĢhCDĀšŪ·0—ž2kÖ,ļ1õ.=öXtFư é Kf”Ä·ø“X2ÖĖ>21V¶ŹĀČAü·IKRąT£;±&@ɇ1ą#ĄŠå(Ūq܀Waf[b'2¬ČhC”d~šæśÕÆzGDŅ@ué 0@Āvķ‰5Ś2=:–aƆE{{¢Å9蠃zUkē'¢ ”+@7@2dȐš2?ą˜„ēt—fČ”ęSØ€¹ŹR9]¢$x‚j MjA2—Lf­ŻČhÜW™`v«×¢ūžJ#–J²šŸŠ°YH„󈣟TS<üšĆĮ©§žmõ€npfI’!ŲLŗÜdµ -HÜō^ļ³Ļ>ўüĄégūöķ½ź?‹Ø} »':-ą? ®ĮećŃÉ'Ÿ,ėī{B”DĢD&ńyOķD@fŗ°Fį½1"Śś_@ˆuÜ®“F øw›Ü£5ČZ”ę €>Ż}Ų†­¬X±B¾c{Ū¶mā €.?¬ÅEĻ'ĒąD’/ū™ōĆÅē Ö¾•õė×˵ŠĘ½~VĶvŃą§Ÿ ž'š½§éÓ§GkF³Éš®r³&NœŲOēīzS—Yo |A‰Åsß’ž÷%S“Oi2°ˆŽ;hŠ Y“ä Čć ¹§]«ų¼1©1qŃąÓtųĶo~#߁±˜ By'­VJÜ‚āžpĀ 2Ņ@ēć±Ē}ÓĆ5×\ÓĒ£ŃhxµžžłŃVķŽ §š`éŅ„’¹i»“©1/qŁ%3Š£=sęLi§ÓV~ńÅ„mO¦abdd2Æ6ōśųąüsŌQGÉ~pļ‚8“¤0¢€ūHŗNd6ĻJ„ę”;÷šįCA€~·m—¼ś%ŒĘɜĘ(ņĄg‚øM€$˜Ä£÷ß8IM€øłī½5#"P«šżÕp›ø3DZ&@ėŠō&€Æ¢öĒ/ĀĖ-*É C;įˆ@¤æ) ,Œv4•Q*Ņ4HŠSH •¤ŁrÉjZ†QYóŸ  £‹±Ą0ŗ˜B›ōŌ3/@’ŠÅ£­D):|‡a>UŌł†+‹å!Ći CjōaųxõÕWƒsĻ=WÖĆ€aXPō䣀D՗$Fģ“4äj“>™›ąyu NÖŽĢ“ß¹ßµĀ(@­÷ŹŌ鍀ųŠŃxņÉ'Ep•„Od“ii*Ü,¤Ŗx”¹0¶Ģ>jܛnŗIĘł÷ߘą|rį…öó@£ÖKŅʧAķvöŁgK­Ēłq¤QūW!į¹QbRŪb0*P¤ĮĻ­ąĶ§AJć iVé-ŗ <µöF·ĄhćņµšÜsĻÉoXń¾ųĆŠĄ¼ ńē%¬{\čc“[¶l‘٧ź%· ,ś™īø°"Ģ”øīŗėÄ“ez,!Žm>M¾ļ<µĄD#˜@ˆ€š–Ó  @fWĻ;&A„Žąˆxź S^tŃEņ}ğ‰”Qš¼z×ļß½×°V–¦ :}„K {¢¢¬ 7vb”ōćŻūT}\«l #?4ż×Kn€$,Śąī¢ ›ļ®øā ©Ł;ģ0¹ŃøŖLń§–EAˆ,2Nü8üģÉ\X!guV“·āĻÄ6 OŠŲ.ń{EÕHķ4ŗ^ų8—[Čųś²¾w[ZcÉJ”€Héœ«Ē‹Ķķ«‡É“''“ &¼ųā‹eżŚkÆ †*ėe>jŌØh+¦M›–čaĒ,B—_~¹¬ÓlRoĄ, å„p£™ƒ€' >qÜ Tö#k'   £°ĄČśHÜžāhĢę`¤Ćµ(°éŌu›.F2V¹ö?ŗßżć6ŸA#ķŪn"ė’aÅ«ŃXŒ¼ŠĻB"œ4i’Œ2īœŒx¬Y³&øēž{d*vFD,4yė`@—ƒ©NÅ& Ć¢ąS*¢ėŠć–Ž£ŁĄ>Ģu<9ŠŒ^0"C܆#Qdž£ōZ,LžjM€<ČŖD2š >’nø/ż7oŽ,Ÿ.ī¬ėØ Ć‚”Z•0ÓĖ:æe?ŪÄ{ą;Ų¹s§¬‡…Žl§AHø°p‰¶,}U#ėū1 Ąč5:q”ʧ»Ä­öŃ Žž|Ļ:æe?Ū6å;ŽÖ^¹ēõ-EĪ*m|ˆuv9hų”ARcŖū@O ’f‚… O.œ“T·`é+¬ļ§Š€„DūZ oāį­ŃŠSūų ±žy晲~ļ½÷ö- $Ń\_ē0 -M[8)¦>RÅJyß/Q“N<ńÄh«ŠŖųŅ—;ĖRś2šłHJFę’ |mא°ß„ā&¶jģ§M“ ŁĻ6Ÿ„ ēų4ā×s·9‡‹ūz;ėď-‚gžy¦Ļuh#Ó6NbƌŃZ„2sęĢh­ŚÕoń>€Vŗ¾t}ō9ø¬Y³¦6%¢­ĪĒ÷~ja·ß…DeACŠ+LĻ/žxŗµ—I,iŽzė­"‰„}‡Cę#ŗ}zŽqvĮ›ižüłŅkŒČÓoß}÷Īޟ0S‰–^ÆÅ¹>ų`ł=µ‚††”Ā (Ē!^ĮSkņjöpĄŃŃłƒ¼™ēĘjĮįŗÜ_Rœ¬<žōXœ›ÆX±Bf bF$÷łźóŠēÜ,Üķõ0-Hūœ÷Ä’ØŸī’.ė§»Ōś†‘”»ūń’ÄŪ«†!FŽ‹ĀčiHŸI}:šnY,ÅܚhžŃ­s:^6Ÿ˜a˜`x2Õ5®¬hö™)ˆļÕ#ŽĀŌøģR8°ĪƤiö1łqiÕė”uGĖNfĒ'ĄĶ ,8’p,™ Ópɒ%Ri¦üéO?d: :Ž÷@ā¤-M‚&ĘĶļ;īøCĢ9ž‹ß¢ē'ćĘĖ;Źā+”0GĀĄe]ߐ©xśßéž8ś]ÖOµü–LNv÷ćāŒ'ۘĄnŠ•µk×JÓK›r L¦ķįĖĖŸ ā6|„ ŗÖh•šĻöŌNüzŗ)֚²®øĒ6# HZ ,|äÓ%­ Š(YMÅVDŸ…¦cÜÜ·&@mŚ H ŒeŠHX«$šå=zt“÷ßæĢļSq̘1²~żõ×÷™4¤ 0Ļt$ ¹ƒ%‚hĘ–:x ŽBҜ‡Y ¹Ć JVeRČrŅĻ™ä׊idķ“a@£©0ļ…š%A)²¦S°ĄhKŅŅ ¹ŌäŚga$“5’™Šhihżķo‹¶Œ¼1 ĄČÄK ’ÖĆĒæžõÆ„'Ÿß±żŪßžVF.®¼ņŹho2Œę31)2T'cM£exōŃGū Ʉᦔ£ń€&cżµ(śčąDĀ0s·aM£-A؃†ƒ…±{]gA¤Ż"ēmf¹SIŌĢ,³Œ6„Lž“ÅboŲ0ŗk5Į”j“ѓjeœ—=ōPYw›čõŹ+ Ō”kdČyU‹l“+W®ź$܉L,X­Ÿ.\æ‰-[¶ˆ{s7’õ=[Ą( ¬ü" Š7&^‘XDĘÓ—_ܹ‰Ģ\…Œt²_+[<€¬žČFė‚éND'2%ń˜×1© Ą Čōęćb‹3™›uÜ»qÅʝ— dv"!‘±Éü4pŻĘtĒA wnf3ę\49§9ōpݰ"“kŻG+ī—mDFī,ѝLÓćX@ēA†"óѾ§Ö&3ā“ĻōęńŒE &[ć¦ j}āP@ š!N1TüC¾'taÓ8®Ś„Ø3gĪLœÜµ›ŅdÖgµĄH$^PK'EÕįX_@­_Ļä°õBMŸĆ €źZąę‰Ž»ˆ€“˜z:ć/L˜0!ŃæžÄyŁe—ÉśøqćÄ$-ĢŻK/½4Ś ‚«Æ¾ZLjH`u6a&ÕŠ`¢ECfŅ™‰Į-H&Õ;Dé‰Sķw’t]š„I&IRŅäųłĻmµ™ ; €<šõBŗž{ī9™‚(-LAľcā×s·ć‘`Üļ4"лѤD“)ƒųżŗ½×qÜcŻõ­NšN7ĀP^Äļ‘užĆv%ž< ūDĒw|»õŽs³ī»ļ¾~A< Ąyųį‡K[H<ŒĻr ^[\–8m{Č2>%¹[ćk¤Ś‘˜©nt ¬HķJL@z™© ŗI §³Ž59±Ś·I±żˆ›Øm̱GÜ;jQęŚÓx‡¼[7"R0„—ŖœwJĝZ=ūZ ,Š=öŲ#ŚźĪ² /¼Pā2ź@Ą…čUķ8”tEz8žųć£=u@Pj„‰·2oŽ<‰ż&īŹĀ… +”ÉRY“hQtdżÄK<ŻĶ8 ÷ķā«ĄŅ„K+Ó¦M«Ü’ż•;ļ¼SöIü~ÕšÕ°ī±ŗ\•‰'V–,YRyā‰'*a&ūó$~ˆ># 1)]ŗįłć”¢ †Ÿ6ķ5bćQR ><6lXtD~B;>…•" w¶¶Ū—P6I“ƒÄįø .ø@zʼn–\“ÅŅé`d±<;Üš>šļ¦s"k ū48·ŪėĢ µIćÅ )iOńŻw߯”s4{tv" hFŅø-cę:{¢¶Ė€±ūsĪ9'ŚźL/^œŲ)‰~ąüóĻ¶ŗƒB Ć0Z“Fc€at1VFc€at1VF×’Hl&Pn“IEND®B`‚#3«"2 9Ē@Įx11 `füųĒ?ž¦“ HHĀ’Ć|Ō^å½ &Ć|ßā ¼@“Ÿxж“%Ś śČµ(Ÿ k Ż˃ĪłµÆ}­:īøćŖ’üĻ’\š©Ä  X$X·n]ņ?¾›^ƒ9“^ņÓĀßAf#ė~z‘‚‚…,p2b”`%AųPšEą«Ąńˆo…kųaģŗė®ŻōGŃĢĪ<óĢĶ&ßąHĪ_µjÕ4' ³Ī:k*gÖ_ŽC^‹FJB¦Cy•óĆ]vŁ%=ƒóÕ[Žņ–ō’§œrŹ“8ĪKŸŲ’Õėߊ;æ_ĮāĄÄ(BŲÕq@ćĻ•gä`#_X ĀėND ’Ī7°å:fó湒äAĆĻÕ8G~ķ0µŚn>](Å7×~ÉIɰZ­ü=öVW*•üĪŽO£ŃĄétņēČģ’ža:6?¾yŅ˜lŪfŪۆٶƶSZßcu„J «Å •ڽ ²Ķ^Śž™ūĄ~DäG§‰pe“Ž ’"0&bP€g±Bė„•jDNŌ Āeūā‹sČä @„KMI•JDnˆpŝSqD~ˆpÕR‰Č‰pc£cŠōRČ‰ZDøŅ¢R„Īį¾1Ø @„³š­ŠzÓu"P €—y,“ŗ‚P Ā-_ŗ\*¹Q ¹ltōeŚŽ°ÆÖŌLŸœ‚sęĢATT”T#±D3m~lŅóO›¶ąāŋ ä÷éąķ·ßĘóĻ?/ÕČD,žNƓjDNÓ:°¤ŒÓ!ń"óź«Æā¹ēž“jd¢¼“yXæa=µ˜1c,ŽUWWó;K]f4y¹©¹‰§6«««CgG'OE6ž<[6<2üńėŒw^Ćī·n\&“K­½“*ŽČoĘ€ŪĆ·QTTƒŽ€·Žx i¦Įßߟ§z>uśĻ’–[‹ŚŗZ¾ćææ’}tõtįźÕ«h¼Ł›Ķ†’āxyyńוń<…£ī[ś»éҧÉ°jÅ*:ś 2sĪø;2åååųĖ’üėī[Ēē,ČÉÉį)ž»nuńīBThģ;ōz=āĒ£®ŖqóāŽČĄH8\ī ‘›‹cĒŽń‘¬¼ļ­}X}’jéCČdČ>‘M×2sŗīŪC>„;w¢¾®>Ų°a’““Ž+W® µ­¦AFĒFŃŽŅŽÕ«W£žF=Ÿ—`X; ƒŹ€x>ų oüōĒ?Åźµ«q«ē–ō)d2°ŌšDŒ3Č~įŪĆšńóń–j÷mph.ĒFĒņ)œX9$$„§mīėėĆšŠ0ęϟ«ĶŹgA2ŪĶčlļäļĒfBņ5ųB©QĀŌiBXD_žeŃ ąg««¬CBJu˜1-¶ńųśūņĒØČ(DDF !!±1±ī'ųī.@Tož³¼šX°poź³el’ožv÷÷óē;?óUw~ņłjk„‘Ū“n°\ņÓå:€½{÷b×®]RLd³Ų ŃQV ¦õ•€l4’ėvōčQlŚ“IŖ}}X‹cīܹRLt"÷Śųu˜¶`²üķoć‰D>ēĻēSČQßĢ9 H¦­e)Ėhē„.÷t.] "ÜŖ•t% (ˆpCżCŌ„īzÓu©DäF€÷ŻG¾K]A(įNž¼{‡†ŸŸō ™l,i+ƒ‚L0fCbj"<„•+VJKÉdėėźCPxT#ršR€eć­¾¦ ļZČ3‹ÄRšĻ–biiiŲ²e 0eū1öļߏ;vHKfÆŪ·o£““”Ł Ć؁ȹ‘RČ‰Ęˆp]ķ]4(Ȕ Ę.#ģ;ŹŹĖąp8ŠŲŚ“ÉÄ'óliiAem%>ųą>·¼ÅjĮ‘Œ#øV{g nik᯽Vs yyy|½āŅb  ājåUXl\­ŗŠ!óŸ<äzću>čõė×qōųQ¾~QaFGGq«óŸD¤³ūĪ„!õõõ(»\ĘĖååü‘|5--R‰Čmʀ˝č1õąč‡GłN8Ų:ˆ¢Ņ"œ:yŠO'rW zū{ńŲęǐq$=šŖŹŖPYY‰?æńgŲ¬6dŹą;ėÖ­[±fÕ”– ¼²/]ÄåāĖøxį"œcN¤IGWW²³²ń ßį³Żsļ=(..FŽé<ŌT׹wŽĮšš0Ÿ/pøo˜œžŽé§%_] Ī” ĮŃĮüč’śū‘}:óāē”ų|1 ņ `SŚ p)ąu€ĶśĆvLo_o,^²M=Mųį~ˆĢ£™€ø^wOĖU\XŒŽīÄĻ‹GWs¢ēG£„«…}ĢfŲN…`’œN÷Ū*pāĢ Āź²ā‰­OškœīŪ}ėļƅKšąĘ„Ÿ–|9ĒrØ Č” óęĢćMńuėÖ”¦¢¦nžž÷§ńŌæ>ŏČpļūZ½–ļlŌžš‡‡‘{&©±©Š85ˆ‰‰Įąą ?ŸŸ””›ūęą‹ččhÜl½‰Čy‘PŒ)ŠŌŅ„_’ö× eŌĀG’'ŒF¾Ó’ę7æAnV.|}|įRŗų,6̜Š9ĀĻĢlŹ6"ʔ> ĄŽÄ|‡dGdwq¼™8¾œ½f|'P(īˆę^ī¾±ål=f|½ń;Æ»ol=f|»Žē1.§ūµīĻ™ųŁ_·Łv »£”‘”RČiJĀĘw:ö8qg_>q™J„‚Rį^ī^4¾œ­Ēīü¹ ļĮ„õ&.߉ė2ć˶óóĒ Ļ“ÆęlŃYP‰ü¦T ąŁgŸåsóĻvģL›ųtÖ“Lī@µD˜RWZ,©$λヒķŪ· ?Āk4šækyĢd—J.aÅźŌŖ`J€©`Ļž=xrĒ“P«ŌŅ2ٲ2³°éŃM˜‡˜‚F„łøŸOäńšĘ‡iē„€'»ū~ēä‘Éќ£4(µ…€ĢęĒĶ—JDn<°ė”jś³Č)"4‚ŗ‚Š–īAć¾9ģ©FäPXZH]A(x`ß3˜-§ß¦Šõė×S @ŚŅ=čmzŲ]l$Č„”¦Z‚ŠuöļŁm;¶A«ŅJKČdĖÉĪĮƏLæS999čīī–jSūĀÕ?ŗŹ–€‡Ż»wcēwB„TIKČd³Ł Ńk¤ŚōńśėÆć™gž‘jSŪ’ųGüüē?—jŸ .€„N „‹ž,rŹŹÉ¢.€ “„{P»Ōp°dD6 ‹¤ŅōVQQńqfk–™Źj³bļŽ½hØm€ŃhDO’ R,õK7×ŚŽŠŽŽ^^…€öŸ6Žmi„\urņšgŽļ}<¾åqd¤ešń7ßz“ē·ø\—.\Ā”“C0™qžüy~źólžYž±Š%®…Ę<ģżß½X¾l9v½² CC|€J„Vݹ6Ą½Ŗ*˜GĶüĖBj„£¶Q>`ČĘ F­£Šit9ŒUkVįÅ_¾ˆ°š0ōt÷š”`l4µw ŗ‚ čhļ@ˆo“žZt“u <0Jo%_ —Ī…[Ę[ˆ ‹Ā˜r ¶‚żƒ1fƈy„żX°C€F,#<ķŪ`X q9\ äAĀewĮĖ× CCCŠ«õŠ4üčįėå „VÉwÜßw?č@P@œJ' Ž(JžžvĢcfxłx6šĻåewĢaAmü}ŲęĮŖ8œwŗE,б2æbR©ü$“;č±LĢģy¶\£ž’ź± Hģ÷n&²æÉ /¾€%‹—@­sĄŚėXš“żhooGŅ¢$lŚø '>:ŹĖ•ŲōżM˜>æzłWHNLFhH(Op;Y× |V`’Įd‚·ß~Ūe·Ū]ÕWŖ]ƽņš“”L¦āŠ]N§SŖMśÓŸ¤Ņ'</ś½Ųóć÷Éän©H„æGcXӛå L^’Œgw=+-%“i`x@*Mžc_4¶Įžæ‹@]ūŽŁ‡üųP+(!ˆ\l£6Ž™nž{ī9¬Y³FŖMmeee<Ƶ' væ³;wŅ…@rbÓ±ļ{ßvü²ÜĶöisżūŪž£ńźxPéTP¹hē—SrR²Tš^ŲÅH§Ćż³)x`£ćvžˆČÅ[ļĶĻ*łQšĄNeM·¦čtw©āŅĒ““yQš uił;D>ߎųm ŗ‚Pš¤¹ó}"ŸŠ²Ši3˜6ÓPš`UXļĢLdĆ®B$bPš µŽ™q˜Čē¾µ÷Q@ Ų|(€¼²ŽQ>QhK÷0ź„£‘ĢRSR„‘:­N*¹hÓļ2ą™‚€ė˜•š£2«Ø®JDnČįS*§§„ćHŚlŪŗ +ųœ|¦N Ļ¢¦¦†Æ’č£¢įzJĪ•šZׯædzóÉ'Łó)KRšįža4ńžŽ÷‘•ž…ūÖŻĒæ™Ę&°,+*Ćłsēł4Ļ?śŃ°}ūvž¹öŌ‰ShjoĀé3§łĻ;26‚ĀĀB^&_Nzz:] Ȕ ƒƒxåæ_AŚį4DΉä“Füž÷æG_WōžzŌUÕ!4<”O–©Ńh°0q!"‚#’Q>”*%=[’ąĮƒhøŁ€Šy”xķwÆį'?ł 6>²‘OĶĢžÆ¬ØDHLņå#uy*Ÿq7(81óc qjŠ;Ņ‹vc;¼ ^|Ų7Žx5 50ß6#ķ@Ś‹{›e DŲL»äĖKII‘JDnS.ųśųā—Ļ’÷¬¹5U5|ÖXÖ䥂˜(©(įGāw-ĄīŻ»qīģ9$$& g°IK“ ²©ųśZ½¦6ŌųÅ³æĄ®’Ų…ĢœLxyyńē-6 ‚}ÜMł–ZŽü\»~-Žxó |ļ RRČår!÷† 7ø¹¹A”P   ó~œ‡Ā¢BøŽrEww7ŗøĮČ ©D˜^"‘Xü@(žž.??ŸE==|ųµLž7<ĒXƱ,źŸĒ÷:ÆźźjÖ2éŌuĀŪ×'‹ObŽĻČĘĖPüg1f*g²1>N/^¼čużĖŹŹXˌ?q”>)ÅWÜŠ_EEEج¬dQßÖEÆC~^>¦ūOg™’öNJ„ż&”Eƒ§””µĢt „š„BŚö4÷ü\ŲQ9"œy"""`/·>›ŸļéÓ§įģā Åg Čķäp”: }2np⣠ŗt]Āō¼…į įīź.“‡£‰'bĮ‚,źéžżū¬eāźīŠĘ¦Føķ’:ńų·yÕÕÕ±– ÕvąēprtBSgjļŌĀó Ļa_LūāģģÜėś?zōˆµĢž6?…ēxOõOPP¼¼¼XŌ7~™žzŚæ“X²b ģģķXĻæąĪ²ןG#7SSS…WFF†ńuĒkÖ30Üķ€1''ēķgßÖŽf=Öć’<<{ĄČŻF±čżŃcĄ÷| ČmŚ‚£ĘöĪv–xy XŪPkܶq›ńĢŁ3Fī*Œe{īĆī)€Ū§nˆ‰‰^kÖ¬ƒÜõ ’æ|łņ·Ÿ=yŅdÖ#nK"„?œ į6ķüóaogŗņ*ž OØÕpį‚ÄäDŌ×Õ³žwŃ7Oˆ›ę7 b7ąhĮQģŽ½›eĶ†äÆĄÜeŃGĻ÷1ąæŹÕ«W³Ø§„„į©Č`Ø©©AVV‹Ģ’““įčhś-ŚݻwÆ×*;;:ŻąüˆŽÜ܌°°0Lš4‰e¦¾©å˜=k6Ė Q „ Ot @ˆˆQ DÄØ"bT1*„ˆBDŒ !"F€£@ˆh’ĖæÆ’`IEND®B`‚ Ķ›7ē¾ĘøŚ"•8{ö¬’œ#+Y¹©ZĘd5 p(žč?ŖæÖüĒČ÷)žB‰PNG  IHDR*\2…‚sRGB®ĪégAMA± üa€IDATx^ķŻPWš/‚EP”Ź ŅZ<Ōz¢ā8-sʈÕ9ķˆÓ2LĻöPŌz"ŲnøC G’$˜«ZµćŸÖ?Ä”ō®õO½©Ų‚ˆP0ņgŹW-!Č»y5‡ Į`Āž>™ģļķŪö—ģ{//\BDɑŻBDˆ!"F €£@ˆˆQ# y¬é~NŸ9 ƒĮĄJ¬ V¬XĻQž¬ »ÆžłŖkŖY4ø8::béŅ„šööf%C%ņŲåĖ—įėė‹ &°’§W^^.܇„„÷OJHHĄīŻ»Y4ø444@„R!""‚• t @ŗį_ķśŗōĘÜ>ƒeŖ("b”Č€JMKEåJ™ż£tuŚ’(»ppp`k&Ÿł ŖrĪ:‡¤”$d¦gā½µļAUÆBƟ3p±ä"«Iś %2`œ%ĪH–%ćQė#¬_€IH\ŸˆŠėˆŠŠĀ‚Y XMŅ_Ø@¤ņņņPQQŃ핹±±»vķźs/ĄŽ;ąååÅJŗ«©©A~~>‹ŒöļŻ7W½‰’oJą3Ń/ø¼€Ŗ›U›†#ŸAҟ’X́Å÷š½ꎋæ—?6¦ndŃ Ä'"> …‚ėģģd‘Ń„K—øśśz8r€­YvćĘ ®““”Eæ¶iÓ&¶fRüe1wæł>Wu«ŠSÕŖø{?Żć®~{•SkԜ”DŹ\ Öģ €žś„ˆ%BDŒ!"fó6€2>€S›‹ž/:©©©3f +1iųwöģŁ©£”•<½ŽŽÄĘĘbźŌ©¬ÄDŪ¦Eņ_“įęäĘJģ'xN0V½±ŠEŻQ€mōÖp<’8ʾ)c‘uŌķj(v*XŌOų`Kńńńlķłcn¤Ū/zÉf‰„‘bjµš;|ų0‹ģ«+ٱµ_37XÆ·‘€Ļ2RŠ£ )ż2„õ6 %B† ’ū#vī܉ø„8Vb^æ'ż#=RŅS0cę įUyĻĆŗuė„õäŌdÜżé.Ž;&Ō-ś²Ŗ;*„…‡”½£ZV˜G®¦²I[’’Ēx|Qų…P×ųŸšŲAõŒæe°5£¢ā"<|ųEd(RīWöŪd'?kʇ9BqX÷7¾ČšH¶Å¼~O.RČž"Ü9s 777dff ėmŗ6„F4^G{ ^łĶ+Ųµ[˜ö‘ž}t²L”yJ“ź[ŃŃi¬ßß Obįė Yd;-Z÷N¶lŲwƒ;dŁ2lŽ“EPPāósŸ ŪŽśĆ[hmje{‘”Āo¢źėXd;łgó‘.ODzče'É1ĢeŪҳ€F£†nZ»<Ķ”Ņ999ˆŒŠDųļနոC× n€«“+ęĠŖJC×Mś¢.Ī.B… ĀIŅ÷^†ž~ư&ÕõÕšńöa‘eü«¶¹ĒU«Õ¬†ÉŁg!Ļ–ćµ7^Cšä`xH<ąāę‚{Õ÷ Ķ4Œ pb Īžė,ŪĖz|Ƈ¹ēÄ/®RWį¹™ŪFĖÓ/mmmfĖYųæĮ“^šünŻøÅ"ĖĢ=Åf™B҉„׉PNG  IHDREM²—sRGB®ĪégAMA± üaoIDATx^ķŪ LTWš? Ć”bWŚRƒ-uW­›"n[‘J7ŪT„ AcŖY—’ŁM VĶZl²HÉŗÅā -ŗnw ŗ¬+”bEäረ( (0ĆsīĪ9s`-8Ć˜ó#7ÜļÜ3sēŽį|÷Žs‚8Ž3K–ģ7Ēqfˆ'Ž3c<pœć €ćĢOgĘxą83ĘĒ™‚ƒ„…†‡ž’’’‰Š‹ŒŽÆ‘’“”•–—˜™š›œžŸ ”¢£¤„¦§Ø©Ŗ«¬­®ž’’’°±²³“ž’’’¶·ø¹ŗ»ó½¾æĄĮĀĆÄÅĘĒČÉŹĖĢĶĪĻŠŃŅÓŌÕÖ×ŲŁŚŪÜŻŽßž’’’įāćäåęēčéźėģķīļšńņž’’’ōõö÷ųłśūüżž’1“ĻP((--Åąą +į &Ž[ņ,-GēóŽöČnÉ`¬ÆŁłWĪXųęBi••–įIēM_ÖNÖšyŪ‡EZU·«Š"oa‘a,-,įåå×Y®¬dā˜<”——£ŖŖ ,`%œ”Ņ3Ó±uĖVŲŁŁ±­ĢŒL¼ņź+pqqa%†Ł¶sĪdœa‘VĄźÄļŽgŃō»#ē²Ī±H+$8q»āXd˜¶¶6ŌÖÖbżśõ¬d‘`J꫿påŹqĘpčŠ!A}gÅ"]R©TĖå,2œD"akŗ‚‚‚ŲŚōĀÖtóų›šš„£G²Č8ŗŻlMļąøil`pi§Ņ°Üo9śśśX©Ö¤IٹŁ8pą]Ž’ė8-+¼ZHćŠŪ4~Z’@?N„ŸBK»ę¹+óæ™Pö(‘››Kc•J…œó9P(ø|ł2-#ņ ó†÷s,õJ«KiæÄӔ½JØÆŖšĻņļćh܎ ¹č¶ę¶fdfe"åHŹšūˊqšąĮįø¦¶†Öåø_ iß„‡čŲhˆUb„Æ g[tMšš‘ßGšöń†««+ք­AEiЋбqćFdĖ@IE «©uų‡Ńp§Š¶’m;ķčJMMe['NĄĀŅiii¬X¾d9V¬B{{;Ā׆ćVī-tvv²­øQxƒī{ŃŪ‹pī?ēPš}d2¤©Rų¾ļ‹uk×!7/—ÖńzŻ ×Æ_§ėdń˜ćĮŽiņźėļƞƒ{ŠŁ­{ģE5ØĀ»æ`‘łHLLÄćŽĒ,2üÜ|ÄDĒ@ä,BņWÉ^̶Œ6i€µŲ¶6¶°¶¶† .æ„Ø?GĮÖÖŸmž ×~øĘjjFjéa Y ?^’ž üŁĘbč[aÄb1}O+++ŲŲŚĄręčS@^SÓQƒ’ŅŌÕĄó7žŲ·qńqčõbęĢ™ō³ŠD"Ķ{‰¬hĒ ŻØ(Æ@_ļč[­É¦“¼žóżįäąÄJŒÆėI>^õ1$””ÉŹp6ķ,¾=ö-Öżiv'°ZÓ[ $……,š8äāwūÖmDÄD µ±‰{±ś÷«éßłóčMäźx’žż YŁ^žO4[4üéTż*:42’K ½]ƽY 7O7ˆŌ?Ŗ>„ĶĄĘšĮw«—qŽu8Y9ĮŃŽvÆŁAV%ƒ½ęæ1›6m¢É‡"#™ģéģĖŽŽžÖ#w¦Fzõļ–żCS+Ā~‘=‹Ę®§§Gļ~ō ėv÷tc†ė lٲ®.®ˆŠŽ‚ūėīųJšł¶ĻY­©…§¾ćļķķe5t½ģś2īܿⱓĖåz÷£o©¬ŖDPh²²³°3aĆčßīXčMM›póęĶ YīŻ»Ēö2šJżƒvĶŗĻÆ}°/y}>OŲ“€eæ[¦ŁĄŒgki 7Եש۷@€½‡=›Ń&oĆKā—hł€Ķķ P*•“o€¼lȚ®·iև×899ĮÓÓīsŻį8Ø9™¤‘ėœXuŽ‚ŗ ‘śĪĪĪ“žÜ¹s!²"L‹<žč;ßuuu¬†®.Ū.Ģf³hģŗ»»õīg``€ÕŠŹ;Ÿ‡¤Æ’P’_‚»õwįęī†ŸŖ~‚Ąˆ»µ)„§¾ćŁ4„\,UćŸóŅŠŠ w?ś–ź»Õū0 •õ•ØkQ·ÕŲÆv&ŸPVVFāŅ„KY‰Öƒ†čUōb޼y4¾Vr —ņ/įƒ?|€w¾CˆgŲģģl¼ūž»7É!o“ĆĻ׏vŲ‘NDrĀׇc†Ć ģūfmčb+1>Żš)møÕwŖįććƒā’b¼õę[ppp`ļ¬¾Ø«“Eņ7É4Y8Īp¤Æq²wĀÅ’]„ß2?:į†t²deeŃńß.Eך>__ųüvōd‘‰’’’BnjõĶHOO‡ŸŸf͚ÅJ4.|nnXødō¤žē BFF‹“‚ƒƒqśōiiHĻHq£č½ų$ą\<{Æ9`Ē_wč“4„††B*•²HKßńäbZšCBCBYÉĻknnFNN6lŲĄJʦ³„ÉŅd4V6bė_¶bĪsŲ`ļŽ½ˆŒŒ¤Ų:H0„PßX/DDD /ń»ću`[ sµųŖĪ{I="Ø?Ū:ł½Š<uõ/÷~)(JV06ć@ĪćŠ¹|z}ŖĻ<€žž~įė_ õźYÉŲ: „­EˆŠ‰vż}— ¾¤eIII‚ś1…®?mŹ$īŁ^t"I ćm|"Šų&ékt?ǁČ÷śØń‘łĒHa’?÷ ±Ūcõ~–©yĘy$īŠä&ÄØ[n!߫۫nŲx?$a4=hŅū]’"}¤cjńāŬ„3Ōɓ'óĢ>ҧB†.aóęĶ“ļc¤•+WŅIPÓ]tt4ķ{)00>gCkk+żŸ™ńö<é³" $“'€ŽŽŽįŁzœńN(2/a¤śśz±Čp¤3qŊ,Ņ"IįYCaÓ ™÷Ą"­üü|:ÄX¼½½įį1ńŹLž8Ž›®”\Įoˆ-ˆÆŃ)qėzŁut»€ĒRĄ>*¤žb45+ŹėS€ōōt¼žęėŅGŗ(„bī5߃ęošĮS€ņ’–ćQĻ#L<ŚŪZĢżĖ\tš:ńnņ»žĢ·‘£“ŻiX·~=`£‰½WŽ÷LŖ-V ¶lÜ"ņC €øu>ū<ŽŪüžŌK¤€õ©fsuõuƒ  ½½įVŽ>@322°kē®Įć°ŗ¦¦Q/E &€’+%Q† nU®^» «Ł “Ł„M›7!LĘ·‘£c’:†Ó>¶CŽ+G}1’"Žßž¾Č· Ø&« š$G-•””*%¬·ŽżT6ģ8R¬ž4Ö®[‹Õo¬†zŠ›žŗ ©ŪSe=ų™ ą ūėł^‰:H$¶”JdLĀĆĀ$ßNFG§Ä­œœlŪ¶MDvģ 33‹/-ža?8p@Dvģg@VĀĀäż ’4uuu|ŽĆÜÜ\lŻŗUDņB €øå*0³.ļš2ҳKnܽ69': ^c—½z[Ü WŪN“2Śą—;J„ų1J„ų1J„ų1ŸO ą³~†Č™‘¢E~B§†B“¢Ń—’}†yfĄ:€i;EōD~^>ŗu‹H^śśśšĪŪļ ęåŃ⚻I@ā§M–^+…īWˆ¾l2šųŻpk“×ņŲ¬¬,$&&Šč‰²²2¤„„‰8ŸuŖ0,żŲĢ6$oIĘōébķų2 (//Ē‚ D‹kEEEŲ°aƒˆČ³*..Frr²ˆœ•”” »’P’«†N_uīWēĪĆņåĖE䬣­åŲ±k^˜ö‚hŽ?>ŲĒ™ĄHÄņ ›ōŻ¼1eʯˤI“ŠŅŅ‚E‹‰£·+o#1!ÕŚj„G„ó»ĄV$¬ąėŗ;ŗŃdhāUĄÜ9s”P+='ŚJ-b—ÄņDÄ/Gˆ:Š@¾ßXTTT ))Ééog‰+!!ocQXŠšs,}°KY—.]źt,N‡ųųx¾MŸ„?•’c·*„ż&‘qö×’<ōōōšŪzcbbœžī”%..Īe;ļŹ²eĖ\¶; ėwC3»ÜŚd1aĪĢ9¢ÅŁŻ»wėņx¬L›6 m÷Ū`“J’ĻŃ1ü‚%ęęĶ›Xµj_ęŲ7_r5 ŲÕÕÅė~Kæ­¾¾Ž& [nn.ŸČø~ć:o“ĪMlę^3ßĪl6óm:;;yĶÖ;öóO'‹‹ŠÅ’{ī&cF¶·¶“ŚŚk·µZlҭχ§“€d|Œģ+WÆ]åćh4īśŻHz½ŽöłŃĻmŗFģūć2 ĪėĄą@Ģ›7Ź`%RRRųO#«“Vó¶čØh~ė$£R©ų6¼fėū§õÉėÅŅŲ͚= /N³gĪFHHˆh%ÄŁ[o¾å³;,£££±’ÓżŠėōČ<“ɱ6”ĻÆ`sÄŹ•+E‹ü4448Ż™Ęœ>}šuņ{²-›S‰=#**JDņ"}#ćóģŌ…<gĻž…Z­‘gīܹƒ#GŽˆČ3½¦^ü¢ūK/-@ „Lt!~Œ!~Œ!~Œ!~Œ!~Œ!~ ų?Ön6 ¾åÖŃIEND®B`‚Öµuī˜h .8F-¼ŖóʏšyŃóēχßx?”|ҤI½ŌU*Ōį³YhH(ęĪ ©Ōś:}åįéE‘‹Xd;üŌWįįį˜4Ex'óźŒW25#FĄĢ3…v“yóęĮĻĻx<ČŠĮ_ę®üżŹĒē€-I]¤ˆZ…Ä„Dœ8sē~Œ&uŪjžŻĄ`Å',Bl…Oųžžęæ>ĶV†»GRB–­\‰AĀJͳłPą%K–ߣö<źŗ“Ą† ĢNīČOjyņäI᫱¬ÕÜ܌Y³f™żź(¾Ńqóę͘={6+±Ÿŗŗ:Čår‘°mŪ6Œ;–EÖ¹pįN:Å¢¾įOoKS«Ł<ōé‹%ķČRćį³ųÓėYN±žž¬MBˆˆQ!"F €£@ˆˆQ DÄ("b”-ą؜uhZŗåIEND®B`‚ć‹)?ónü–ÜĆĖ(0İ>|æéĀMć‰PNG  IHDRYфśķsRGB®ĪégAMA± üanIDATx^ķŻ TWŗš/4-›ä8j" Ģ yĆį)8ć29jg'ϳśŽŒ'>wOōĈ’ÄLLHPI—™˜£ƒš1.( ¾D$bĖ¢²Ŗl6ŻM׫{)Ę AlB7Ō÷«Ó§ėŽŖ®nšŖÆ«nŻśJ!ˆ@‘%„ōL‘! „ČBdŒ!2Öa#`NNN?G©Ęv”——cٲepww—j!]ÕaČĢĢİaĆąįį!ÕŲ[žl„ō6t@ˆŒ©ŽIć’tćĘ øŗŗĀŃё—Ķ‚«×¬Ęń“Ēį>ĄK/N§ƒŽØĒ¾½ūŒ’Ҭ^µ¹¹¹šī‰ż_ļDZ£ĒPr­)™)Ųø~#T FŗŁUķ?!¤ė,Ś0›ĶpwrĒŲ€±pssƒ³³3|||0ųgƒa4„¹€!ƒ†Ą××jA '''¬Z½ ĻO¾©†„¤ ^殉PNG  IHDR@õ]©¾sRGB®ĪégAMA± üahIDATx^ķŻ}Pēšļ‚¼X_Š”1ĶX{±Ę8!-VA£Ńɤ6m|łĒHÕqźDķą(qB3TŃ1a؎ĶPDy1‚¬ņ’•‚/# •˜±“j…X1pĒyœp¼mŻåĮųr#ww·ßĻĢĶīļ¹Żī¾·ū<»Ļj¤‡@DŖä&–D¤B "c©€HÅD*Ę R1‘Šń:²‰”Ż€ŗ›u¢rL>Ž>˜łÓ™¢¢Ē1Č&™Ē2±čEŠh4?JņŅZ#Ż~Šą~O/‡’­[·ŠŠĒ ›ddd`͚5¢rL‡ʆ DEc‘Š1ČīĪżó%¢­„ %’(Aó7Ķhhh@Śń4I;‚¤CIøõõ-±5&ŁŻ’żó~9eåe0ö•/’W×¾ĀĖ/¾ }‹ożź-ܼ~SlM£‰}dQjj*śśśD5“ŹŹJ¤§§‹ 0u›PpŖżš~h¢…īŹ/”cÖ«³°ņ7+‘r(”a” Ä“M{=_€ÆÆÆØģ£„©ŃDĆĖĖK“8)9ˆž–’’"ֆwōčQ±6 Æ·OzŠõ@2uš¤Žž^éīŻ»Ņ}Ć}Éd2IżżżRGG‡dī6KĆEģńü%''‹5ū)..VžOĪŽ§dWnīnšöņ†ĻXø{øcźŌ©÷ƒqšńńQ†źä_bĻ1žpsćGĻšÆ@¤bģ ‹ä>€õė׋jh………xx˜/*ĒtūömģŁ³GTöQRR‚ššpåČʙ1Č"k@­\%x @¤b "c©€HÅD*Ę R1‡<˜|ŽoQ¹.ww÷ļ5“V×P‡ŅāRxøyˆ–ļÆÅŲ‚Ń;D54ĻŚaĄėׯ£¢¢Ā.W>ö÷÷#44TyŁ£m×®]b͵%$$ˆµ‘¹pį‚ŌŚŚ**ŪX{]¼µ÷ؕµ÷œ={V2¢²Mgg§”-*ė4ź„Ց«Eõ,ž¹ NS'rNä ¤°s~1G“>ĖįĄŠaĄŽöbٲe(Ī-FVn!ądöI±Å€ś’Õ+ķŪ·nĒ]Ż]$&&*ķGRŽ(Ky®ŗū†ūˆOˆŲīƒķŠ·é•÷œ^/~āŪ[pɹœĢzņ³loÕ«’—x¼¾ųu¬[·c†>utøļ7ļo{sēĪEĒõFÄĘĘĀ,™aź4‰­€Ļ’ö9>Üł!āöĘ”£½µ’®EMM īܼ“Ń„&c*k*”éÕ`éŅ„’y8t:ŲŪ¹]łĻDĢ9_“µµ‰Ź~ænÄĮæDOwb’‹€€ńĪŠ¬ź<}ź4t-ĻļĖ#w”ģßæ_T€ŁhFüįxDoŠF^f"7D"#)+Ö®€Æ÷ĄÄéx÷wļ¢Ū܍†; 8qģ6oތŌć©xmÖk(//G¦Sü§`åņ•ųųĻćŠ'‡”}GKtt4“Z­Ø¬WWW‡˜˜Lš4I©ĖŹŹśj(ĘOÆŌ#‘œœlÕL¼/^ıcĒDEO“;oÜøOOOŃb™üŁŽ½{7üüüDĖ@€{HłYˆh±NWW¢¢¢,v¶“· hrV­ZõĢæiŲIQ•ž€Qf©03%SYžŹ?„t\åęę*õ ś†z)ń“D)n_œ¤×ėML‘÷ižtīĀ9eņ‰ó%焤ĆIJ{õ—ÕRiy©²>ZģÕ xėś-é|ÕyQ ;ķƖNĄ¼¼<ÉhyĒąP€WÆ^•ā>Š“tĶ:Ńņ¤įžęŪ øzżjełĪÆßQŅkłņåHJJRĪēå—’ žŲō‡MŲ³&Lx45õ²UĖ1/Bł• _Ž÷~’žŅ.,^°XYwv/i_B©GTäLĢ=fųūūĆĻēŪ#[…„„`[Ō6d}–…“ŸDæŌ/ŽłnN5 °qćF„?@~ó'ZÕiįĀ…bœ‰×/̟?_Tö#?ż(js^™ż öļŪ+_^Q˜ņ]8 HäB“?Öb[Ģ6č zģųÓŒńŽeq%`NNŚŪŪEåŗ‚‚‚”‰‘jjjB~~¾ØlgĶSrx%ąš¬½°±±EEE¢²Ż¢E‹0}śtQ Ƴ«iiiø|é2Ņ[6ęŒ@d`xĪ4#ŠĘ;ža°ØžÄS"7Ō—_Ę R1‘Š1ˆTŒ@¤b "c©Æ ‹¬½ ¶”„¢rßžķŪ|!P4<ĖUž Ä ‹¬ €ŒŒŒG7b¹ŠęęfŌÖÖ*_š”øJš€HÅōÜÜk»'Ö“ģ? ن@vwķĘ5œ.8ģŌl”•”!’L>Ŗ.W)·©Vż« ł·ßMdöEgΜApšŠ×*,,TęgŌŪ׋„} ˜6õ÷źįēę‡f]3_ Ä4’i(=WЉ'bŊ˜0YģåXä>€‚‚Ģž=[“<«ŗŗk×®…··s?Ļ‚@u™»¬šEY¾•{Ė–-¢Z ­Čł4=ž=š €v†Gs"L†™³fBß®Gǃ¼¹äMxŽ~>½Ń"Ą„K—&Z”©óĶ„(ÆĖś˜2eŠUó+:2ŁÄŅ(@Qq4f ¼±@ ˆą `L ĄŲ‰cQSUƒY!Ź4VŽŹšQWĮ ›ØuŠU°HÅx@6©¬¬T.БυåŅHΉGŗż Įżž^ZĖŅ~Æ÷õõ!223fĢPjWĘ R1ž©€HÅD*Ę R1‘Š1ˆTŒ@¤ZĄ’'eU×YÉHIEND®B`‚‰Ž&ÓēųmāˆÓZV“G»@dŃī‘A0øåš0÷'ŗ_^Üi~æÖ­ļ­–.YŠŽīŲzl¬3÷¾¼ų%öžq/b—‡åĖ—³-S3ļʄ[ £zzzpõŹU˜,&œ(?%æ¼ōŹKhlj„l€³[•B…ĢĢLØÕjä°WzƖ-p.q²Ź³T*Św~¾~xdz„ĄUb?Č„ę»ĶŲśŪ­HLHĦŲMHŪ•™•?f^žoPG®‹Äżöū¬š;÷īŽĆĮōƒč2u!’Ołx!ź¶ez&PżU5zūFNķfSuu5JKK”R½ėp:°sĒNœ-łģÕ#Īž9‹×ć_Ē¢E‹Xgfb‹æŁ•Mó€! Cąą æóKßć>, €Š_Ŗ¾­Ā7Uߌ9ė°ŁmČżs.ģ=õ.5¶½· n»žĖüŹqėć°aćÜ3ރĶjCä/"”ĶÓB£f{š<N‡Ū’¹ ™ œ1 æø…/ŃÅ?„ŒzĀ%=æ¾üCčū<_3\Ćõė׳b¬ĻO}ŽØč(¬]½–u¦O’śøąc„††ņ×Å|Cx‡²wé0æ|wū;,”-ÄÅæ_„R©Łš qæŠĆ™3gśs~?ć˜4„Aµ””Łp*))AFFĘS0Ģ #7'ūöķƒžØļģ|r¹—*/”ŃԈķ[·cqąbŌŌÖĄb¶ˆŪ6oŽ,īĒh4¢­± /ĒæĢö6æ¾*ĖĀ–œ{ž W.ĀQ½‚į×OŸ>·’ßz*źźŃllFŅI¬33ÉÉÉųLū™xĘ%ćdš‘ūˆ?\ܓŸ4ń{+ԚB Ōź1 œźÖÖŌbÓęM8Uu q P’AČšH„G‡ĆóĆ«æ~ß7„?Ü 7Ś»ŪńZĢklž'@ņ`Į‚'ĒćGĒ`¢^Ņļ’pīÜ9±=ŹårįŠ‡‡Uœ%~ļfJ·;=Ņżū™Aē ¾ųėhśw“8Śæ"lŪ2Vbb"*++Y5!<&Ml¼‰@Cü¢’‹žė·üo“„h"ŠģOjmiåų³PVĶÜT'ń—]\ʞ īXį1Ījµ²ī[¶lakć›yLšį—w·½‹€Ÿ=3 ž·2|%^\÷"«ę^ŲŅ0ää"bmvææ†ÄŪćÓA@Č’1æÄ¾ ­^‹;­wp ż€x‰8U„x_•Æxf˜¹7śczœ(>!ØOĘcŸ䯇Ł.)NĻ     G !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFž’’’hIJKLMNOPQRSTUVWXYZ[\]^_`abcdefgž’’’ijklmnopq”stuvwxyz{|}~€ųėNOžiĄššń.É\Ķm˜ŅŅŅX5±óēĻ£¢¢‚UŽCÜ.++{j z*ŅÓÓŃÖÖĘŖŁ%Ģ•ČŹŹĀš5kXgz„ō–;-(*.Baa!ė>żļĄ„x)aŗųēÕ< !Fc„H!F@ˆ„Q"a„H!F@ˆ„Q"a„H!F@ˆ„Q"YĄ bk“Ņ™(³IEND®B`‚ģÕ#Īž9‹” Cˆ¹óęJsBlEmĶĶČ*ȂæŸ?w%¢āvV®\‰s Ā7‡cŻŗu(+/Ć÷EßcĀ„ P*”ˆŒŠDŲ¢0œ6Ó&OCƒ±iXšź=~†fĪž‰ø˜8 ‚«‡+Ž$AȜ\,øˆ ±AčļŌæu™„ō7īŁ»ŗk:Ģm>"·Gņ]pä\Čį×øĄq8uś“Z-^žó2źėźńŻ·ßa֌YxŹļ)9r3f̐–ÖuŌHH÷”³„ȝ DĘ:Ü(** Ńh¤ŪQWW‡·ß~...R !¤«: „y CBdŒ!2F€£@ˆŒQ DĘ("c‘1 „ČBdŒ!2F€£@ˆŒQ DĘ("c‘1›ĻPU[…‹Yį÷~hØk@YYž’ O ŖT)1zŌhœM9‹#G@­TćJįžųŹ•+Ø©Ŗ‘–BˆmōÄ 8ٲ1Ś4j«kQQQĮ×ńóēĻCėØÅS¾O!-5 ¾~¾h1¶ øøć9yyyh66#Ą?©)©ź=.Ž.ČūGĘš»hš­½Vz·³łĄ2š <;KOnj1ń?Č`0šé¬^Æ×ĆĪĪŽ—F#ģµöüŁÜbęumāćć±`Į©DHĻb?Tć”V«„@„VA­R£¹¹™ÆĖl}oiiįė8«S(ŠŲIėøF\ĒÅ­•­Ū,ł.Ūq°×Ųóéj;5ĻČĶźķķķł¶b§¶ƒB”ŽķĒd•(66ÆæžŗT"¤g>|S¦Lłē•- 6BdŒy ¶sČvGб t@(&:†·§t·œģ|ųчRI>lń€Eyو‰‰‘Ęˆ%~ŖļK®’‡¤¤$Į`0H%Ū@‡„ČņH¢c£Qv³ ė6¬Cį•BœN9Üü\¼łę›Ų²u RĻ„JsZ†ö"ÖC€XLߨ‡YŅSÓ1ÄmҳӔ`ƒBY³faÅ’®@JzŠ4÷Ć9v‹žk‘T"Ö@€6lĶņ5šōń&Å Õģ?e”ĘŁ]ŪX™MS‰Öē‰Mc}>ڦ1¬Üö:6ĪęeŲ8{ˆÆS“(`²7ńjµ8°Ü(yņšÅ_šzęBÖœO?Ŗś*ø;»ćÕ×^Ŧw7aįĀ…ų¾ų{<’Üóˆż<Kž“DzEĒ>ūō3ģ’Ė~œ9sDŲ’0ń# P˜Å`">ĒĒįźģ ƒ8“š?’żŁ­æWģY%mŸ³­ŽaIcÖ“v~遟·»ś»XößˤRēØŠŹz[ćÓÖ­[„1ėh’}]-ŗ*˜Å!//O8pšÆKĻHJKK…õė× [#¶ µwjy}gŲrėėź…«WĮĮĮRmļ“yófiģᨐōj^#¼ų/¬ŸŸ^šłÆ „Ē6lĄņw–汞ńś‡qrvBų¦p>zXŖ!Ö@€X•³£³4F¬ŚlXDD–/_.•z;feWœu·¦¦&¾ĒŠ„‡‡cåŹ•R©sŌ`eŌ@ŗµBz- „ČBdŒ!2F€£@ˆŒÉ¾Ąµk×x²ŠĮƒK5=ÆØØˆŸóoĻŚżzRHH&Mš$•¬§””˜8q¢TÓ9źŠ‹tŌ øø˜÷m·¦>ų@ū!9õxļ½÷¤1ėŖŖŖ’““„ŅĆQ?BHÆE 7n ł\2¢vD!żb:vFļäćĢW‰_!ćBV­Z…-[¶ąbŽE,^¼āÆö½kׯåõ »xBMŅu·oßFeU%O ZZV £Éˆ†Ę~³ Į, Ŗŗ õõõ(+/ćÓvÅķĀ;wPQU-[°~õzä梦¶5Õ5<ńHmM-īŽ½ ż==n޼‰’ü±ōnņE ?ˆĖ™—įąč€ŅĀR˜ fč®ė°wļ^\8oŲ¬½ĄŪŪżśĆĆĆƆ ƒŠ(š>xzzĀĒ˧ӛ1‡ūhŪG8}ś4ö$īĮõāėH:–„SgNįdņI$ŸMʎ؈ŒŠ„®H‡Üœ\TVWņlEߞüļ,{ßßs³;ų7ģI؃¬‹YŲż—Ż<8oūd2S3ł4äNV€,K@aR˜Zhˆ9ū•yīŁēų%®m¢?‹†_Š.Į'Šg2š‡ß’‰{įėć 7w7 >7oŻÄå‚ĖøYsž£üq*ł–„µ&Ćx”°ģķe4–‡c öō‡ŻūwcŽģyøgŗ­ …^”ēÉ;Ųēfw”±½R{„=ō‚“&q`w‡a‰= J4J ōāĄ¦#O¤”VØaTa§_/.ӾųOS)T|v*iš N3µŽ…ÉA即†’³ÕF”RšĻƒqUĘÖ÷æ[A%N3‰Ó”­v‡öYrö½+•ŹÖ× ˜UfžŸ<Ž ļ¶^ t»ī6r²r|&õµõüų`xóDśŁt”_/Ē+”Æ šē8šķĢżķ\œ8~/Ģ|ń;ć”TX°ht„:äĖCš³Į8|ģ0øĄŌ¦bGä4“4`ŅÄIh65cBŠžžmŖ««qčŠ!Žh‰øø8žÅ))) µ©F@Y€ĘĘFhTā ¬ø’'ė®é`l1ž ¤§„ćÉ'Ÿä÷ō{ŚēĪĆ”ÉSp6ż,z ÄīŻ»łÆżK3^‚Z«†÷poÄ}WWbĄĄXōĘ"‹ƒ@ÄXś?KÅ’ųķ Śč āرē׹·)æQŽššübō/x¦œ¶i,£ŪY–¶!³i¬Ģź-™ÖöÜ~Śæ¾7[Uō&=@¼^ X,še*Åי[߃mōāb („i‚8M J|šøŃ·}’JA¬SŠAœwĒ;°vŻZ^Ļn÷ń‡Ćo”ś{ōĒŁÓg±xÉb$D& ĪT‡©/NÅHƑŒėׯ#00Pliym„Ó9B$Œ€ £ ä-Qp£> |ščÉ#±„~„˜øŅē„Ųößm˜é?§¢NA£ÖˆkźG@ˆ S«0mŅ4$Ē'#lWśōéƒĘ\Ķ4łø{÷.ģķģłYÕövķ‘|&솒\ ™2„_ćeõøč8xOóĘ­¬[(//‡Ó»N9ČąąąŸO|ųŁäj”°·y¬8»8ćųéćŖ9ŖUUUė8箜ćõäōdøwēū±³ŗµ÷æ’>¬¬¬jźś’šžŹ’.©aĻǾ#ū°4d©ÉĶó\ˆĖ—.·śóĘśßóēĻ ÷īP,TąČ#čėÖęę{I›|Œ–Ęķs·QZZŠÓNcƐ“ ßU¾PżØĀÉŌ“xRüiҰō“„xÆē{čßæ?Ž~}ŖR”…J 6;·ļD^AŌjÜøqƒß+é?¦ć@ŲÜI»#>"šķĮo1jķ(DģąuĻ!žČ¼˜‰ĢģL¼?ąż:ūē<́··wM]_F Å'ƒHMŚĶ4$E%aƒß†FwÖÖężoDīŽDaa”Ųb\/4/ż aįa{ŹńTż©S1gʜ&÷%“‡īxXö/ķ?żå#Ø5jōr酽’Ł‹ėw -= ķ{“‡ŪP7¾]GYGd–dņe[k[(¼pģčȓżÕė²ŽŽŽ˜ī;±I±ü P•©pžŲyĢųė _)ƽü{ā–€]{»_ķßAÖA\"Lܾ8,™·¤Yfšė_eęePę*ėŒ!?;»wļʦˆM(Ė,Ć”ŲCXżåjōŌŻ aņˆ„ļąēēĒ‹ēXOōķ­ ™™C>QŽž]{b’¾ż–Ƶ«+߇MZQ+±hŃ"¾OĀŁxOõF—]ųś_±J…R”«Ėq-ó*dčīŌž³ż.n¤óš>ĮBåŚµk5Ÿ¾TTTˆ[Hˆ x\šھZ u'Ą5Ł8qHŗ„Ź*ćL{~Qń1{b‚ҲRĢžŪl„ĄĶõ囙” š ødĮdę¾|'mn‰‰‰P«ÕõĪ”bŸŪóļē#óv&?}ŒŲŲX¬ąS‰Ł󹱃Ų±111p°s÷ž•?Ćł³ēł™r>;uĘü)ó1^1Q‡¢ąźś2,˜£'ŽāŌ™SZ„Ķ7㻣ߔ‡sXülüŸó‘‘žĮ·c?qüDÄŠ­Ł?åb –`͚5¼®ēååÕź³Ą[[[Œ3F¬5]VVÖ­[÷ʙ€WÆ^EšĮ A/§^0c“ł Ąf²ćh(„R‰É“'7h&`\T’æśżÓVÖVbkć±ó@#Gެwč®­Ņ¢“¬­X„~żśAf'×¼;‡U·’¾‰A“Ć?3·„#F ¤¤ä/’Œœ „mCÄ7/?‹k*5Z—a.˜żélX¶³DVvVųÆąĮĄääbÓכŗ2¶6¶ü:õL*ā“ā1aĪ,üūB‰>RsY@ģŚgEĻų:ß/}ń™ĻgčÜ”3_æ9p3ꭙüń=?šDtttĶžÆ>~[ćääÄĆÖPįįįĖåo 6‚ś|ÖēŁ§nNbkÓ±`”b(ö’W©T €ų8œM?‹õĖ×ō1†@JJJ½ßøtķDĄČq#ł÷š;Ų  Mrpp*++ÅŚė±õŻŽķ&ä¦åŠ-‚ą;ĆW8‘tBØŖŖāõ“§O …‚/3U9U‚ŪŻ„ČčH”ŗŗš·żųƒ$(3”Āˆ#„ÜÜ_ @šķ!\ørAHNKvžo§ ЉkįŲ÷Ē„U’^ŗóå س’«ßÖtļŽ]\2 ;~ŗŽ'Ö~›.$„¼¼<±fŻ›ƒød]8óææ!¶mv|³Cx”y!¶4MCś7£Ńh„¼[yĀÜOē Šń !/ėĶĒN7ŖØÓ’źcŅēŲč ł\2Üåī°±±į…%凣>¬IÖ>=śeŗ…§¼ W Üŗ}  ųš—ķ³qėFĢ™7]śt™æ–ŖææĮŒ5ėÖ`؟†!įPäżäu>J č9c.ā§Ū?Įł÷ĪxĒęŻŪ¾n…x…‹=~\\\ĶżéĖ®ż»ZżrRk˜ųĮD?sœ–LQĘ© |<ęcXY6}ųßl”ćŅ×»öķĀüŁŗØćĘc¦b&*ŌĶtée“= MH†½“ėKCÕŽ‡Żōź“‹„>µ·yŻöµļK_Ś cīźnŽ“¼…Be”ŲŅtĘÄ'Ē +·ÆŠTEbKÓ5¦×ĘśĪŗåėĒNŽBč¾P”LU&hµZq­ÄFzģDо4Tķ}ŲMÆN»XźS{›×m_ū¾ōEŖzén‹óK“ŗĪ,¶š†üłšäĖ/#·ÖwÖnY åe%ŸŌ6kÜ,~’ŗųi±øEć¼@L‹×H/,ū×2“›4wĮ\øõlžĖoū‰yŪē!åd "C#qųÄa~©°1(1a^£¼ø>ƒ† BZJŠ ‹Ä5 C@ˆ‰³’=&Lšæ~ŲöÕ6tźÜI\S? BŽ]»ĀGįƧ¤7T›žM@v „“,v)“¹~pėÖ­Fż„[ö›zĶŃ}ŁoNŸ> c)..ęæ|ŻŚ³AŪl°ƒCZ;«ÜAĖ~œcc_µ6»Į¾bklĶń·ŖĶ!¤åŃ9B$Œ€ £ DĀ(‘0 B$Œ€ £ DĀ(‘0 B$Œ€ £ DĀ(‘0 B$Œ€ £ D²€’]jٟhõ×IEND®B`‚ǐ„C@v AŲ-’ ŗ²P;IŽx©Ł©˜>i:ś9öĆģßĢ–ę&}µō2µ””” 11żśõ“jīÓétŲ¶m›T¢vFaö˳qģ»cŒ256_77a15b15d99037de*"%’’’’Hļ256_71ebebd8f4b034c9*’’’’’’’’rW256_4203016071f8786c*’’’’’’’’’’’’Ń256_b5b87915f102636('8’’’’ĢS ×Nģ[ˆņk¶‰PNG  IHDRĆŁĄ9sRGB®ĪégAMA± üaIDATx^ķ›yLTGĒæ» *”ŠZØ ©R4ėÄ cŒD«[cü“Äži”&5VėUŃŒGÅ ą‚šĄr)EE“ʱq9Ō€ˆČ„»ūśfvV`}¬ŠEöéĪg3Łßo˜ć½ßĢofV!ˆ€ĆįŲ$JöĶįpln8†džį€Ć±aøąpl~ ĄłdŲżĒnø¹»1Ķ<_:‰eĖØœœ–ŒŽ–*[ A/`]Ō:¦Én8Ÿ ÉÉÉX¹r%ÓĢ“””„ČČH*Ÿ?‹/¦²µC¤ą.Ǧ(.)F}c= ļāeĖK<ų÷lyä€#[“Z-“ŽĘ8qä ® +3 O럢õu+Kµ=ø Ą‘-łłłxöģā: ¹£ŽHÓU?‚÷׎T–"ę—„†z@S„Į–-[hüµ‚khmmÅŪĪ·9j$”öJC”’ĒGäĄĮpå Ų‰ŠX'ˆL¦`1D®4ø+ƒ1ŽÉĶĶōz=ÓA„R1I^æzĶ$i™$ēĪc’õ0Wk֏»œO'g'&q,»Ł’——‡9sę¼[ž“ō¦¦&*ˆąą`ųśśR¹““EEET¶>>> ] ¬yBĄ G¶˜€Ļkīp86 7Ž c± pżśuŁ]¤pvvF@@ÓŗP«Õhhh`šyf̘{{{¦øqćōzr~c<<<ąķŻóč‹ų¶ķķķL3ææ?FĶ4 ¢¢µµµL³ bZ¶īTUUŃcо0vģXŒ?žiż€KHHH“Z­¬BFF«]OH¼T~ÓPRR"455±R]ÄĒĒKꬊżĢHś?%%…•2@ŽŸ¤ņ včm¼L?Wz;ģĻų˜Ž­9:;:™4Ē€J„vvv² ½Ķ$^*æi m’¢Æå?V¢?ż/…T¾ĮŸū o Rż%śŅ‡:½yłyŲžŪv3Ą{ńĒćq ī’TITW„Øūk,öü¹Ł’d湑ĆHæŽĶ›7#3'[·nŮݻp:āL†K9—h¹ĮąŚÕk-ēoß¾āÅ8zäØÕ˜‚źźjÜ+ŗ‡Cq‡Pt§5Õ5øsēöģŻƒ3‰gw0åå帚ϟ?GĮĶV’3ØŖQūģ’¹kāD¢ūEPT!hj¦Og)&{Ož>ŗL …R“&Ä č ńōŹ"ÉEŽb2Œi¢\W[‡5kֈ póęMTVVB”S ņ‡H¤¦„¢¤øNܰpŃB”kŹį5Ī • þ½ū Ō)1Į†; ‡bˆĖ—-§ĖN:WwמW.Å:×<ŖAōśhč=Ņ3Ņ{ż_dÆ Ŗ¦ ._øˆĶĦźčuŌJM%¢¢¢ ÕiéÆĶČģėźź ???ŒóĒJ<öĒķĒōļ¦Ó:‘©SYY6ü“å0ĻŽßw`včlZvØĆP”—!źĒ(š–•“ŻZZZŠž¦ƚ_ĮŻŻJ;%*Ė+1ĮgŚ_·Ćļ?ŌÖ×ҟ·.[jų¹­„¤żO/O*“ŗæ‹ļcņ·“a'Ų½„ųŃÓA%ĆjGó‘4OŅIš1Ÿi™%iY9qåŹ„††2­‹ĀĀB¬]»–Źā2—Æ^ĘüļēSŻ”cĒŽaęĢ™L낼ީ)©Xµz|} ÷"ŗļ9ō0DŌėŗĶŠŻ÷öLW$MŒ;£:ƒÕ«WÓØ /ąMĒL ˜„Ņū„šųŹ%¢prĀDŸ‰xüä1}Y8-uõučlė¤Ś·1šöžfP!  gC¬ėÅK±dńŖŠž–,1Ȧ0ĀeFŗŒ¤:yČD~ŽJ„Ō÷Dā øqƒćPGĢ“”†ˆˆ¦8{öģ;¬ÖØįļēOe)ŒåI{Č8gegay„Į¦„¦Į~˜=:ßv¢­„ C”C0%` jĀĒĖS™IŪī0Ģ牄‹–Ҳ–BĘ"tĪū/ésŚ÷Ż–·Ę±āCiÄnčtĘYMžäęębŊTn~ՌņŠrN ¤ŗ)‰‰‰7yę­-­ČĪĖʬYšõóķ¹éH €%œ>}šIņĮܦБƦFA§Õ1­'ā¬*¹ xņäI&Y©MĄīżßÖŃĘ$i¤6å€\ź!7ŗ÷K]]“¤'&õĪ­[·„”¤įų_ĒYŒ X| ‹¹sē2M«Ÿ›6mbZd™d¼jā“Ձ‹‹ ‹1°mŪ6Ģ›7iƒ9¶[æ~=Ó ģܹ³×+¦¦¼xńāŻŒB ¼¼¼˜f=ČJLL Ó8Fˆ+ėéip>q½£££™Ö;d嗓“ƒa Øn±°ę¹ø9¤vņISūŚ\©ņÖn+Y ›īöö§N¦åūÓ›ŽN^l™žŒŌ³Ń,6ēӅ›]džį€Ć±aøąplą?ĘørkĒ}IEND®B`‚=”1Ƈ§“'O~µN<Č盧pžBďß†ąóØĻńĒ„”ę~0¶§ąąą •īcēņYgš ~ŲѦ7ė“Wg²@zĪśäēēó~ i%dāŽDAÜH…£?*=zTŲ³{-$ü5O‹åĻó LĖz½^Ų·oŸTźØé3ęĶĒ»¦M™†iÓ¦!äw!üą•ŁÆšé _³¬{+éŻ("cŌŠĖtÖpéŅ%~üĻ.Tjuš?¾Tź>_~ł%Žzė-©tė tšąAĢ™3GŖé[ŽŃŲz§_k›>}z‡¢Ø#±ŗ®€¬¬,\½zU*u777LžJ#ż"\/DÜūq4RĖżc.Ś;Ūi¤›6ˆ9C£iż}żČŹŹ‚‘±īķæ’”JHĻIi¤­ā« TßŖ¦‘n–Ä'ĘÓh p ‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“ž’’’•–—ž’’’™š›œ½žŸ ”¢£¤„¦§Ø©Ŗ«¬­®Æ°±²³“µ¶·ø¹ŗ»¼ž’’’¾æĄĮĀĆÄÅĘĒČÉŹĖAĶĪĻŠŃŅÓŌÕÖ×ŲŁŚŪÜŻŽßąįāćäåęēčéźėģķīļšńņóōõ=÷ųłśūüżž’`±ŹĖˉB” ‘žhoo'•••4Ņv÷ī]ŅÜÜL#ŻTTTŽŽ^i £%żsāÄ ZŅMKŗ›©=ŚŚŚHuu5ōGNN™šš¢‘¶““4ZŅX,¦„„Į† c¾iś¢"©±Ą0?b#£#ČÉĪĮ×ņÆAŒ“GūĖ–ćæ=Ž›’ø‰“Ó°ż—Ūƒ¼‚<ńeQ”Ož>Į®]»ų8žd<”JœJ9ÅĒ9ŅLLL ."į¢p£Øø"‘1į1Č/~±÷T½&ä’)æ{Lk–Ē•ĖWų}=Ó§čƒōÓŁĒ•†Ø®¦]|yxtįQį8rģ:;¦ėōIvV¶Ę÷½ŖnV!>>o"ģpLMMé5­022‚įįa^ccctkµžĮ~øyø!+3 •ooodffĀÕĶ”””H$pZ焾Į>ģܹ)gR0n5ŽŹźJ„ å×µ^cŽ€p>ż<D€į‘a$%%!įL†ŸÓ=.ĢčččŒĒĽø¶xŽÓ'Oa3i{;{Z3»¹Śr¦/»ģĻeˆ‹ŽCęÅL””•  Ø!ĒC æ#Gdd$Ö[¬§k®,ÕųvĘcāźj¶÷|^[k’#OLJÄĒ%ćĖÆ¾„_ Ź‹ĖÄ·Ó½{÷čŚ+g¦cyö§k©9ovFw?f7[;}’ÕÕхŲS±żļ(rrr°zĆjŗµ6­Y€²Ņ2(ś4šŸęęf$''cõjõŽø¤šØć*®W`lb ‘į‘§ˆ‘z&ņÉńł_>GÆ¢^ Ä;ށŸŸ¼~į…¶Ī6ló܇Ÿ8 ōÆ„xĆå ˜ ĶqķŚ5ō}ׇ 6`h`čłO’ÅÉtÆŗéčč€T*…››­ŃŌŁŁ‰`óęĶ“øßr  x3€Ö̬²²MMM …“F“L&Cnn.T_,™BcS#Jž^‚ążĮųģŹgpū¹¶¼¾Ī.ĪØ•ÕĀńUG888Š-VĪžżūįććC#µŖŖ*\½z•Fŗń÷÷‡ÆÆ/¦) ģŲ±ƒæ8<ӯӍ¼ā–~(„[én!³ŹA%),,¤ŃģtąŚ"LF¾ųŪäŅÕK$!&¤ŸO§K )-(%CŹ!­,]fzzzhinóH:“Dä·åä¢ō"9™r’~ZHɍŖDrJBTI—؆Œt핱Y€ŚšZ"kŃhvóh¹ßBābāHō ZCˆŖwDKjĖvĄy“3öķŻĒ;bccaldŒØˆ(~ŁÖŸm…»»;^6éŁé°ŚBušĖ8×oDHpL…¦¤K ž~8’^¢H||`kkĖĒÜPāE²X¢oø ,%®-ÄÉblŚ“ "ųh0Ž9J—^æņ‚•`ö«Ź՝ś;““4cłv8xų Ā…aļÆ÷B `ė¶­xėķ·¦Ē¹śõŲ&&' o”Ćs‹'­Y<—×\šAŚ|ļ[ņ; ::UĆč,ė,€““Ó’čœ5kÖ&€¹¹9ß}ēŲŲŲĄFØSŪkŽ©WŁ­ā·µ“°äc®ėĖÅ\2X%œ^öż÷~QLŒMś^( Kmż:ø¾ī ³—Ģąāā;;;ŗ°_kæ ’VšĻnķ”ĀbpĀp]`”•NÆ:Įn•Œł¶āĪWWWž;Ņ'Üē=üŽaž8–’‰‰ |ßōEDB.ē]†ŖGE—Ø-kų±233ƒ‰©~d+Åō%ķ;ό&.±ĻuĻ`±¬…ÖüS©}ņ­Q[’GÆ_掚šXZN_­õ…jģˆ={ö`÷īŻ“FSCCņņņ°vķZZ3<@jjŖVĻęī&·o}ĵKAAŌ:4ē Ŗ¹466"?_sJ÷įƇČČȀ££#­Ńµµµ(--µĒvīÜ9žź¼r¹%%%4Z<ö/Įʀ±!Ć0–ʀ±Ą0Œ%†1`,0ŒĮžž„[Į”ēIEND®B`‚ųž¬`ųšį“aĆ%9¤4³fĶāˆ+d¬`Ņ(øØ‰{2dÆFŁų»įźäŹ÷$ŲĘĻŪÄ5•]6¬ÕjŃŌŌƒĮWWWÜÓ߃Ń`ä‰\™S OųY·Ś~Z>æ„äØ €Ų„Z‰ÅKcĒ ~JÓŁŁ™_*l§¶ć‡7m3 lćgśiūĮÅÅj•š?ģķķłqæėc®“ńĖķ›°bÅ ~kc÷#Ø««£CBzRAAÕ33µńņņ‚£££TźŪ("cŌ@ˆŒQ DĘ("c‘1 „ČBd ųݹb÷šĢIEND®B`‚FzŲČšWDFF*)ŠLĒÅc™Ó+) e„죓ĘO ŃR-[Ū‰PNG  IHDR15#wŚsRGB®ĪégAMA± üa ŗIDATx^ķŻ PWš?7(7ČŖqEOåM#Ł2Ÿeb’žż054„%ņ©ŖØļ0FĶāīÅĮļg?čéčŃłŌ×Öcļž½4j¶lķ2XšYŅH>å/˹;æ±Ļ…2sv‰PNG  IHDR!6õuAsRGB®ĪégAMA± üacIDATx^ķŻPWšo0ėQœöģt®µXī“§½iĒŽÓs:r½Ś›^[Nz:€ž‚œU¬±ČLeŹe‘:^[S¶Š•Ŗ™ö§ „ōhNJ2¦#(Ö:‡FBrHłOŽķn^‹XėŸL̾Ox“żżv’Żå—·»AB8`F”"č3Ć0"Ä Ćˆ+ #b¬0Œˆ±Ą0"Ę Ćˆ+ #b¬0Œˆ±Ą0"Ō‘€…ŠBœ:}ŠFā1łńÉ(ŪZF£Ā+/½‚Čū"i&°ÜN7}~2™ŒfnLž!Ēeķe…™D†ƒuitėœN'ę$ĢAäŲŃŁG¼gŸyÅ4 ¾Krr2—ÄÄD:usn·›äęęŅ(š6oŽLnn޼yt*üÜĪ~¹šĶf#………4‹-¢Sžóy‰Ża§‘;`p]Č-ÉÅŹ·VҌ+ Ęlv>Žū1äyrd,ȀdPBēų„d0hiiA[[›ėõzø=n“ŸožyZ^Æ/^bžÉd‚Ēć”Qų3šŒņ ш 9Ü”ØżŸ–w_óÉfČWŹ;)ŹmJÄM£s†…dX·fv>«’ µ'j±«l\.ęüeŌ§ÕĀ2ö@±of¾)ļź}Õčļļ§Qxóø=Ø(¬ Qš9]NŲmvX,žŗ…¼Ūķ 5wž ė€ÖX¬˜Ķfa~øSķVĮl½{ļ•ßöŻ=ŻXöĘ2œ>{‡ēg=©TJ—)$ €Ī©ĆĢ™3!]ŽG‡Ęv§S'OE]}ŗM݈rD –L:|õśaéĆt*üÕ|^ƒY 0F:†f‚‡?čÖæ»’¹9E9Āž).(ę5ż§ š’j•‘…-;·`łŠå(*+B^A:/u Ė„-īwī¹?>‡Īswē}Ś6lڲ Ū•Ū‘æ6ņer<8žA:÷śB²Øv©°:s5²³³įš¢ĻŅé)$‘¬]³µ’®…)ʄHY$®t^AZZšŠ”{•čį”Ž?1h ŠōčŅtĮd0A£ÕĄŲe„®GF“‘Ėuj`Ņ™čZ#õėśū«XŻ™^c/.t\Ą¹ÖshkmĆÉ֓ĀtKk Ō­jœi=ócnĄ6@×ĘßŖä›"_)M¹×ŒČß-1Ķy ,N ‹{ ė2×aŹ#SPœ]Œ'ƒÜ#”š½ĢĆ ‡qøžkG®jĒøö×i»f™ś£õō;üŌÄŲ‰8ōÕ!łOoŌæžgóÆį‡×S{ū?Ż¬µYˆ’m<ņłˆūĶO»ū×sÓq;·ļDMm K­V£««‹F>Ę>#ŹŽ-CQqŗõŻŲ·t}:ä­ÉĆāæ-F]m~r;>ف*e–¤.Į‘#G„uK?*Åāß/ʄi„8T=õ»§šĀü@¬Ü¦€Ū }x£½ˆ  .Cs1^®oĶu€"Ę£¤¤„®ķ³§z^›’ʍG3ž)--Å÷ßcŅ#“0ń—”³é0!zd܃pžŪģFÄų!Wŗ£-ß“ł8Nģ.ߍō·Ņ‘ŗ$K6āŪćß"žåxdäg {Y6­ƒˆ’C<6¬ŁÅæX5*j* ‘Œ¼(LsēĪEĮ;Ą.ą!žl’ļ`ņĶŹµ‡øĘ×ćūøĘćė·’ž¾l€B”šåÆŅq±§¾>…”æ§ŠŒž”€õļ¬÷ÜažR½ü£uk”¬TbUā*¼ų×=.Ś7ć:ŅÓÓQUUE#_‚åēĘ”•—‘„„²0i!¹ōŻ%ĀŅkī% ,$ÄÉ}¹œ$95™: $iQ]‹mŖmÄd2Ń(tb@c}#9öõ1ł/ć.Ÿ¹LŖT®§FŠņ‹ˆĮ` ÆžłU’!Ļ Ź÷•¤ńD#Q·© ×»!›*6CƁTn®¤k‡ŽŃĄ}Z“³ß„‘’n6Ąåv‘†¦’”œDΟ;O<3ŅŅ„K锁“įˆeĄB#’°@Ć^ )(. vēČĮ7žøÕ@f«™T~PIr²s„Ķk][Ų8€{Xna.ī’Åż4bBwv¦ČS`läXš}1Ń1Xńś ¤­LĆ۫߆źS•p‡ęē°p „óg궂µ¦żzŹw”ćÉÉObyŹrœųęøÓ:w+ ¦¤2)ž~ęilżp+.č/ 3'Søe{µ ž5`JJŹ_žiµZ=z”F7ʏlœ1c†ŠFC{{;šššE376{ölÄÅŻŚ-¦{Mss³°=n—ŻnǬY³0}śtš <~ •J„¢‘ :Ž7Gbj"͹š‚üćƒāv»…£½BķõĖt×CmŻ*öŸFÄŲ5†1VFÄX`c€aDŒ†1VF“€’šn¬”?IEND®B`‚Oįō†ėTń~ ]Eow­$–ķ=¼™XZ!`®ĘäaœuS@-‰Ś0Õt±qćFXiżŗO–}KÉGP$ĄŽ}{addDKš,]³ĊŠH9źą¶ĻFL‡‘ŠÕ¶nŻJē”ĖŻŻĪµ-==]ųšįCɏĒćŃ9IQQQĀüü|Éo×®]tN’££#“ł222h$I‘φĻē šmŪ¶Ī)““cĮF…)5¼,} A‰111ššš@ee%żr544ąaņCõ.÷Óļ“ZžŖ*«—Ÿ‡¤¤$īs...¦æa”­G@C}Ī\8÷ŸÜQTXww\ævÉ÷“ŃŲŠˆÄ_VŁÆĀńćĒx1‡=£Ø¤÷Sī öóö£¼¢W®]σ‡Fa#]j÷IŒL„®‘.:ư 9994źS}SÄDĘŠØó²_d#%%ϳžÓÅ … Ļ“Ē%wO/O\¾xO?AEeųwł±ö«ķįććƒĖ—/Ctˆ†Ü¼\¤g¦ š@P*?œž;µuµt©Lwź‘š å¬YaÅē+pĪļÖ­]‡Ä{‰ÜĘ×·o_L{{Ś{?üš>]ņ)ņsņ±tńRųœńŪÜ4ŒōpŌū(ŠŠŠ°zåj؉Ż-15Ć-‡ÓØs*•pŚåē]ĪHĪH¦„гčgŌĢTuž¦¦&“µµ¹Ÿõäłh‹ö+ģqīÜ9ŲÆ²GrZ2²²²`ff†f|4Åy·3ę2O3ŸbŊšżÅ[¶lŃ052…÷’¼‘x7kVƁ¦Fēׇy=…©&—••Éœ¤«Ø:ź:P×VGDLeBS]“ūf „F½l?µEȕŌ7փÉĒĢI31ł½ÉĘ£FĀ¢9‹`¢o‚ØŲ(ŗDłõµ~-§ņņrśģf–c,“ŪÆi“õ’WTTŠg4ékÖ®®®ųńĒ1~äxZŚZ[Ė#å-‘“q_cµü_²–'żŁD‡FĆĻĻį‘į“D¶—/_¶Z–ō{¤#zhči <:œ;“+”@½Qy…yˆŠ‹ByQ9VŚ­DHHjkkq'ž¦½; “&N2¶gŪ/lŃO«¢c£å>Ģ©ÆÆoµ^Ŗ8ÉŚŽå”p3ą£GĄēó1hPėę¾ššp‚Ž:Ā>;’ó|rźFuuu“aó*((č}ÜŅ:ņžäųģWgÉēW>Ōq©ƒR“Réɘ'{Ö šDŧ‹é‹³_“‹}”ż;¦+ś+ä1ƒ ōŠ$éXėė{¶‘÷ūKÉĶĶ„C‡ńØo***hżśõ<ŗ^sK3iā4TYQÉ3·®½½ęĪĖ£¾?~<Ÿ»±})ūčÄOšØoŌj5Ÿ»9łü”Ļကz;ķmjloäKˆFÅēz»ćZC «×ĮŽŽü&`yōrčkõ°·³‡ƒƒŁ$ĻŪH/×Ń®øPså¢Ć¢qļ=÷¢³£&Ż9Ū›ąāģ‚čH©eŠ <„}F޹ &żĆš™i“§”ģ»2t^“Ī»’}8ė6­CEI2fā‰ˆ'0Ä®ė|ž)w\š„°yašó÷Ƙ1cąźē _o_8Ų;@Ŗ|,'OaaalżĆ©‡‘W”Ērį‡ć  °W e ÖĘ®eł“÷ÓąąW'W¶“øxw]¼Ż‚ĘįĢ…3hŖn‚ĻDØlTØÖWĆeˆ“ž““‚ 0Čq»ąŗ u 4j;5šŚš kŌ””©y§ņąčęŻ%TJfĻžŻsÜņ#„nŸ|ö ܕī˜>k:Ld‚ŹVŊZ7ł³å‚R¬*†R”Äö„ķŲūŅ^V”lmmįąīĄ ’Ÿ_×ļJž.\Č·¶,åŠ{źŃi7pŁķę4 %å%hmļźFö§FC#–ž~)ŽżĻ»ˆß§7= ©µÉ—ŽÜgėM,YøߕĒ£ÓŠŠ€M›6ńčzRs¾().A”³™…¤7“ŠŁŚ‰Ó§OĆŁŁ™­'ßEMm&Ŗ Ų²q 6o،œĻr°sēN<÷Üs°»f‡÷ÓßgĻ€wümŅ2Óą-½d§ §0“Uŗx¤ °«bVĮVa …­üö¤’=6÷ŲĄĆՃ­#5Į`j7±yYyU9 *›+Ł]8Ų'˜ 8*”tVĀŪÓŚz-233ŁEśc5e5Ų°q§†B”€¢]6Ē6Ö*čÖhlÄšAĆ”Ō+„+@*8C†"ōńPdŹ@[{Œ­FÖJ9ž<»ūĖ~éGq»wļęŃ­“Ēr~ųa]/§<#ŚGĄ^zŻ©{‚iÓ¦ńØoäsč§Ų:ŚĀŻŃ¶·Ńą–Ļ÷Ÿ:.Cƒ”3B±Y³n®n<Ū¼+`6n6 MÓRjb*IĶ)/Ž\L'óOҜYsX_÷ǚĶ4ĪgU–võ Ė.–‘&^ź'VWRČōj®mfł¤”$ÖgJ;œĘĘZZ[(fe ét:¶<%%…VD­`żĢ©ASÉh4²|VVłųłV«eq}c=?ޤ‚Åŗ‹:6pY™|}}©šĖBš8y"}xģCš5sÕźh‹f ±õ»É}ų5 ÖŠńüć<ÓewŅnZµjˆ¢M_~ö%-9K+bVIk0hłŹå¤T*ŁĻ?iŹ$jiiį[ü²r  ō«RJܟȣ¾č1€²Ke“}Ļvv^õÕĶĘōWõllhΜ9tD{„gÆg1cį…ć½ģ÷ą„öĀčŃ£1wé\ž:.n.¬ł,ēäiJŠH:r>ĶAąŒ@–“Gõ—?¹Ć݇#vS,||Y¾šl!ę†Ī…§‡'ė#ĖMłŪv`åź•lł‰‚xłõ—”tTĀŻĶ 03d&b£ba_-Żu¤–§“Ź©« _źZī9Ü*• ī¬eā÷€ښŚ<#®n®°»d»¤Nåœbć\ÕW«Łó’[Ā ŁøY @øs d @źņо죣’>Ź3·n [µõµ¤ł‹†¾-’–gś¦/Odg~LQ‹¢hēžTVVƳŌ„‘;‡/f­s"ßõc¢bą5Ņ‹g–<6õFŅ˜Øžˆ˜E1xk’[|ɍ‰ X łéĒ(õ(™§ cś-œ»™‰PNG  IHDR&+šEłsRGB®ĪégAMA± üa QIDATx^ķÜ{PSWš/"R©(/ĮŠe¶*3 8ÕŠ#*ŹRu256_3cb3a123e0fbb184*’’’’’’’’öæ 256_3195728e1f6e0ca3*’’’’’’’’’’’’Ę256_d4514303abbe2aea*’’’’’’’’’’’’HĖ256_53b83498bcdd3934*’’’’p!     ; !"#$%&'()*+,-./0123456789:ž’’’<ž’’’>?@ž’’’BClEFG×IJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijkž’’’mnoqrstuvwxyz{|}~€j;jw|T««²¢ėeWjGE¬viG ĘՊ‚+0 Ø+>²"jD*ą‹ŗ‚hx‚<ĀŻœ›ĆR č I6ēĆ0œß¹N&ń&æœó»÷3N Ƙ¤ō/Ć0&ˆ%†1a,0Œ c €aLK cĀX`Ę.2‚( ”••A×·‹“£llmh¤Ń¦jƒämmm“ĒxŁŪŁĆaøŒ0‚ćńćĒP©T:żŠbDō:ŌŹjqł_—µž{cūŻ·o}UʉAnÜøøøøŠavī܉iTUUń7{ölŚc¼¶mŪ†ˆˆ6` ‚²U łs9ßninACCßīJ"‘@œ-ę§ŅgR§$åOĖi‹!ĢCÕh›azōäÉXYYaŲ°a“G±X ___i466ņ7fĢŚdžŹÄ•œ+(+/C½“oھ‰+W® ’—|äßɇŠÜ-ŗ iµNƝ’š‚ü磨Ø'MÄÅģ‹Čgc¼Ūx¤f¤¢Eւōsé0W’XZY"!!fJ3„‡†ĆsŠ'N&Ÿ„‡»®^»ŠŠņ ütę'˜2Ē[#Ž¢ĻH˜ .ĄĻĻFʇƒ 0W`²Ļd4Õ5”µµ„’RTVT¢¼¶3¦Ī@öålœ’å<üżżįīįŽu«×”±¹ć&ŽĆU±śCüØ­ŖVœ»tÕÕ`5cß‹ÄäD>^^^“Ēx„„„!22’FŻś€%¦“ž©Ģ×ÕÕŃHøĮƒó—‹¼åŌCc7KKK 2„FݱĄ•žÓ;†žX €aL˜ŽFņz9źźu2ź†ŚŪŪÓØCCcd52 CŠ_ŽŽŽ°°° =Ź+ĖĮµī€ŹĪĪ®Ūp¼+6č[/©ÕÓ§Ou¾„Łf˜ †X÷<õJo :*ž^ž4ź_鏧Q‡˜Ä`Ņ„I4ęŁ³gpé¬õµl ĄźOWÓČšÜ,ĄśĄõ4ŅŽ%€¾õ²pūömĮy”3ķ&ė\¶‡l§Ń+ @D"mõæŻ»wÓVg½yŽäZųµk×hŌYhh(m¦ØØ(ŚźYO÷0½ó²ū ¹{÷īŃHøŚŅAǵ(Zh Įj cäur>|Ÿožœöh¼¶š¼é9.\ČÆŸEJR -Z„°Š0ˆbEü-•A B^n¢÷Gćč±£8~E%EŲ±“>ŠžżpģŚź;d©küįx1Ģ‹„üœ‚ę¦f½U›zJwābcc±ų‹agmGh¼¶ mĄŻŻ+V¬€ÕVXōÉ"~ŃʎаdåĖ—cÉŅ%üżŪ õ P)Th­kE…¤Š&}żRķį=]ĖĀŽ^:–p aįaH:ž„²Š2ż5ā‹bz”a“óē…ĀāBõŽŖUÅ™~µē+ųxś xK0æĄŖ«æłū7Øoا‘nJKKł5ŲķČŅĶ]į»ųõÖ£]GヹąėČÆńÅę/š}Ü÷šü½'DŃ"|·’;DEGĮÖ֖/Œ<ÆzŽ[wo!<¼{OØ 6š YŗŹĶĶEFF€“3iš›é÷Ā;=z„°°08;w/ڐM*Św‡Q*”Čż5Yē³0Łc2&Lš€Ģf"`U¼?Ģ›7ļ„wߑ·ƒä”c7–ö0ƂŒžČhŽŽ“§3©TŠ   øŗŗŅ ŗ¦—¾Œ—}L{ŗ#Ė¢§NJ£īä29ĘøĮĘ?oäÆ\µŪ¾}{ēĻIśŠµĄ¦NÜĮƒłE$›ƒ6s5u5\“(šćš8īxāq¾ųōų?9u¦āŌS.žXœ’ļߋœöœß9’[p<0 ć’ÜhĖ0Œ b €a\K ćĀX3'īŽ½K„©y)¼p öE’Ÿ~ü +CWRä<,X€C‡Q4’°ĄĢ‰ōōt8`yRO&)) ńńńIRRRpüųqŠœĒLöūC`Męa`p]½]Ać›Fōö÷Ņ#cŹŹŹ Õjaģ4R ćž=Ź ć0‰·fĶЬÓh4X»v-E’ŠŠ DFFŠå”{)ØUc ‹ ŃÓӃ?ī’n„Ć“ü'0404<u®Z¬+(,@G{4Uø¹»!55MMMų,ō3x*<Å÷t”™ģ÷‡ĄšĢ¬»’>śūū)’˜L&œ;wŽ"ė.]ŗōīdļĉx;ōŖ zzŠž¦ś&=Ö± LFBCCŃhhĒ %šõöEeu%¢££ŃX߈ˆˆü™ń'>öū‹³;†ŽŁq®_æŠ,µ4·ąĢŁ3šöń¦š¹Ē3ėäŚ½ćėJKK±qćF±,ĒZ€ī„ž<ĀŽčØÖUĆ×ÓŽyĆŌa§!Ÿ¢ŗ¢›6oĀąą ÜÜÜŠjlEāĶDü|ķg$+“±yūfŌjk±mÓ6Ņ»;޵>€yŃ? $†™M< Ņ˜ńu#ü?k”J%•Ę$''‹[¾/n§kxx˜¢hīÉ}£¬=6WŲ3ėä®lB»{ūöķY—™™‰“'OR$IHHĄĮƒ)ryyyˆ‹‹£ČŅ|ø` €™ur¶Į`;ė¦# –·ē555Tr.¾¾¾¦ČK̒ҼhŪ:łš9±y ćĀX`fWą·ŪæĮo‘EŽ700€Ć‡S$©yUƒŖŠ*Ьʦ9B‘¤®¾š§Š>Œ®®.qŒ[˜7>Ŗ³«*• ž §žØ"“­…żrww§@õ— żŻ–cńް*b"?·³gM€é™ģszńāt:EÖ Ćv­5€­©47ä†M222Ø45¹×ēęę~Ša"Avv¶8\5Žėׯ9½^O‘u P$™«!¦;wīPiĢ|Žr“}N3łüfņ\ó€™khh H2kM€āŠĮ’1ą’q›‘™!$čŖuØ{]'Öż[÷/=ŪqšØdC£JĪOp0ŁüwgŌŚŚŠ‘įŠlĆ_\’8iiiP«ÕT+™µš²ź%VÆ^ü¼|TUU”£­Ś-Ō’ØQ^^ŽŲŲXTj*1ĀŁ·3S)ż»”J¶Iøž€“ßÓpSyW¹JµĪ­¾¾%e%øńė čjtųįŚŠ}Z,?Ī} M¹½½Z„ŪvĀd6!ņ‹‰óķgźāŋغu+EaEž­ß±+©­­EXXEcJJJpłņeŠ€ĢG™ŲżĶnŠ,ɝ£Ź+ł ļ¾X¬[·Žjd–U ĄVćūtzø}Zö”Ó餲±Ķ(ns²rø¤¤$®N_'ʶ’kļ¼ßššįC*M$÷ś÷ūŅÓŅ9­VĖååMh—;Źtś„æs2SõšwŸPø¬¬,N_Æē:»;9>ŁŃ£ö‘ė`ģ3ž»ć›Ķœ¶JKŃDrĒōØ·ę·œņŽ’ĖTe¾;¾F§Tšµ4"e²ØõQﲚ “ źė˜ÆÅ^ī•!Ž’E—={öPÉ6ūc÷#<<Ń_EĻ««Ųt§ŃŹY¾|¹8³.&&!ĖC°Ųw±ų«;Ģü·jå*„NŃĢx(< ė6 9%YķāĻyzTb×0ą•+W°oß>ŠOøÕ={ö,EaŽųŅ„K'“määēēOX’*ĢÕ^“h‘ÅŚ\+..›Rćõ‡ƒ–-[F5“ÖĻ;v .¤ąÖ­[ˆŠŠ¢Čq„õī“ĶuglĆ_Õ±bŠЬ“;'&óŖöŚMķųrć—Tcgčķų«+Ž$œä>>>I„N³ŁL‘uö¾Ž‘„$4žšµż1Óõžė…}öĶŃ …Eßc?aŌF˜ó2rĒōL°µ ćĀXW-Ćø0–ʅ±Ą0. ų†[ŒDN±IEND®B`‚8VcœÉĶqW^0VŠÆu-?Įŗ\‰¤3Ū¹˜JåŠH…<°ATpzõ*9Ü+ÓßNĀŚ‹{™`khĢHÕ«ŗ©Å‘"|;½%™L¹\³Ėk#+¶Čķ»]‘gɝZŗ"Kb D£dß|=żwö X[[ӈ1dĖ0ņ„¢+rÉł|UzK Ć>V`ĘƘ0–ʄ±Ą0& ų/!–”ŅŲ)+°IEND®B`‚m¹ŪØöVóčē!wE§Ķž†ģO²Ł xdL$š7ī‰ –Ȱ³³Ćŗm됰.«’“š/čMA°pćĘC³EĆ£ŽĢņļdee!88˜gK!’Ÿł‘#GŽÖߨ­­Edd$śßŌ©SńĀ /šØoBBBnś]€Ū%?=ŹČČąQ’3»PWWǾ”!X¦ĄĄ@ŒqėßT–ŁA~>b @¬˜(‚`ÅD+& € X1QĮj’4#Ń4¶¾*IEND®B`‚­ź(žÕgø¾¼ŅģęÓõK(eŗa#‹•pŹĮs›ŗ€}8§iZ]å”™„Ō õ, ϳŸćż÷ß§%­‘ĖøqćhŌ,-- ööö°°° %ņłę›o0{öl5»uėWU#ĒŃ:}t0vtóśJ#UśČČH 8–4‹ˆˆĄh$ŸŪ·os¾>-iŠĆ‡ÓH”ÄŽaÖĆ`lhŒp~8ęĶ›‡ģģl 6 ĮĮĮŠÕօ”©aq^Vž‰±¹±yļļ?øŠņ LŸ>1q10`†n’sŪ°aęĢ™C#ÕEÕX”DRPX@L&° Ø}ÕÕÕź˜ā’bāÜäō7§ qĖ \„”•”©c|™'¦KĢ%¤¾”žFē‰i@ĪŹ‘šś"ļįÉ„ŹK¤³£“dee‘JK%± ŚHEM…ś>*’$‘ś+“’¾§Š§§[;[Iƾ MĪ­Nœ, q1qdļg{‰|tI{oøzõ*)..¦Ń0v€y"pvŽ”’§œFĒīÉÓ  ¦¼†ČG¼4šœńŽPr¾„ÄEĒ‘]É»HWOķ=ųÄ5ęÖƒ’k8_õxųćšó¾®åmĻ?ż<’ž„µÖ"#% & ®¾Ž.‰%³2^Z'J)‰PNG  IHDR(ś$‰sRGB®ĪégAMA± üa]IDATx^ķŻ}PēšļAÅ#BAčŲ …©Ćų‡E;%m‚ādĖ™”ś2­¶JPG[©WŚł£g‡$8įÅĄd¦‚2rL¤FĄ*ŠDˆ2ņvp¼Ÿ'ĀwŪŻå±äʁÜ Ēż>;;÷üžŪ[¼cļĒ>/»J8!ɉ=B%B%B%Buj•5µ5,²Œ³³3^’ŁėXŗl)«1õą›hljd‘żq]āŠY“8P &N<…»v²Č2U•UųA‚‚‚X)¹\Žøø8ٟŒō Č’,‡D"a5‹€yęĉ¬d¹²²2®””E“>|˜•ģSrr2g4Y“8P!Œ™w»³„U„,šPQZĘfūķ3°”ȼŗuū–Š Å­Ā[HJJ¶ßnƒ<^ŽÜœ\deeįīż»lKb ”XOO:;;MVNĒžīīīIū|¶ ±­&8öĒļGæ®_ģ$\óĆ5ˆ;­Q ļUŽŲüóĶlĖ…ĮÜū֑į¶…}”ąĄbccQ^^n²¶µµ±g'_Ꙫ©©™“Ļgkoo/Ūj‚ŖV™— ž~žŠ @ę+ƒ¦Cƒą•Į}< gĪ™m¹0TTTLz_9s jQ±-ģĢx_ qD{öģa„ ęF2Ó3Yiz³PkԜ~DĻ©ŪĘ5®æ§ŸÓ źøź{ÕÜŠšŪržM5 pćĘ ®µµ•Eö…ĪČs½æķ}V²>,qY’ļ?śČ|ąįå©›kBÖ`©«łIEÄ:(ēr[ęĘJd±”@ˆ£©Ą,&&©©©,wåŹ²Č2|ūGށL&c5¦Īž=+vŚ«ŃŃQ¤„„±hĀĶ›7€U«V±ūA Ą™KÄröœØ @ˆ£@ˆ³j`ph:ķÜf’ŁšÆÆ/+™A_o‹,ēīīŽåĖ—³Č”¦[Ī0-- ó‘Mył*5¬c&M€¾¾ŁĻä}¾2óĒķ\Y5œžä4‚_fŃĀSTT„3gĪĄÉiņ‰Oɍq6—§‡'«±L]]8•ÕœČ÷"±ó׳»Ę~.JĖJqōoG§Ę£`3I;vļĄ;æx‡E–)*)BŹ?RÄ®X¬E”P°ŅĀÄģœĮ``‘©ėׯsķķķ,²Œ0;lŗėčcccYéÅŗpį788Č¢ÉĢĶ$–›ÉLĄ½{÷²’å„ćvllŒEÖE}„8€®ī.čõzM°yŠjµāø²°VWW‹uŗAŻx|łH}m½Xp’Ž}ttt §æG¬Ŗ«ÆŸżž·Ę–{}øp<[jV7cĢ0Ę¢q-ķ-¬D-žWޤnbķ_śĢs™8ō»CčźźbµlžīT܁——ÖÆ_eĆĆĆHük"Ö­[‡ŖŖ*”Ü.AJZ ’yŒAĻéńQŹGø”w Š“ ń:ńœühŌ444ˆūų"÷ ōw÷³½Ū–ŗU;·ļ°Čŗ4>Ąå//ćć#CŪÆE¾2µ5µųŗākœüĖIōō"O™MƆ½‚,*|s^y^)ć¶ LŹ*śwāåńxć§o`ēAó}P6OF#ųö5 Ąõqč€,PoooD½…ś»õšĖwųʼn_„2\Ē/@)-*7ČAā&T*ɛo扊ś ¶wŪR^Ubs”õÆG®¹Ļž4čéCŻĆ:„‡‡ćüłóŠ=Ńįą"įh6„o@ιö*²Øš‡yXDjJ­?3RÕ¬Bœ<.Ī.PœV čå )G‚lž8#‡ČČHxły!čGAzJń“’©ųœqЈ×>:ctxĘ#¤^RHœ$x5ąU4Øš¤÷ žųķŁ½$ō:=<]g×So)m‡ÖģˆĮ\µ¶µŠ_ų—–愵įk”ü§‰I‰Øü¦źF5¤īRŌÕ։wČńt³Ż{®Ä#ógŒx¤Ä¢¹āyœ漈S'N!bcœœ§?~Ķ~–žšUĶ,š¹²²2\»vE插S^ŒųųxDmBeU%4­ttwąĆ?}ˆ‡āņµĖāYĄ†° hP5`믶ĀČ/”?ÅW’ś ±ŒEhh(ŗŗt, Ė–.c?aę„yÜ­­­fæŌĶĶĶP(šóóc5@fz&¶¼»>ßõa5ę aDDĀĀĀX)”ķ•‘‘Į">C·«š÷Œiǰż÷Ūq)ēÜeīhooG`@ 6żr²Ņ³ÄĻmĖŪ[šŚO^cÆ“Lnn®ŲĢrqqa5¦„÷¢ŗÅõ<™Éē(\!œ[^A6­Ū?VcŽtĒķ’óū¾Zīµ`ūžķy%„ÕN3T)$kYlƀ ¹ģ“lMĶ^‡ɋ3ip˜ć’?MęOŸ›qK‡…ć1ūól.!1ėģīĘTC•6oŲ3w'wDļŽf!Vä ˆ90ŽēeeĀŁHōŽh|ūņĻå#õóTqäĶJ„,R^+¼s o…½…āĀb³3 ­;ųōi±-¼Påååįųńćę§—”€oˆ£³Q\\<åTąčččył/±®^½Š}ūöĮĶīč3ßvķŚ%Ž„u6”J%Ž;6§©Ą£N§I}VMĻn3½…„LtŒ|ßVFSÓģ'f7ĮX¹r%‹L × ć²óaõźÕ6É –Ž-į›­©ŽŪ¹²j „ŲśÓ@ˆ£@ˆ£@ˆ£@ˆĆž öŠ×ŽAIIEND®B`‚ŖWÆ^$i7I;¦˜iČ87ø÷B’cč; /$ü;Ü~qĻxŅ(”5šg:_& >£C‡ŃØHPDjjŖP“±ÓH’¢Ķ€¢o”J:Ū%m­‡PōMN#Ł”Õ XUQEēŚÖŪ›Eļo•hj¤a§°fĄ&ņlė²ōŖf@55µ>tV©DėĮ›čōśvģ£ŽHōžź‰¦ī?™Ć¼V§ŌÕÕ1jŌ(ZŅlÕŖU°³³£‘ņ½¶ZDŖ§¤ŠŻ§OĒrO]]öģŁC£f¤ś}öģYhiiŃłżAōmF£f›6mźp2ŖŖŖā)dž­_æ¾Ć‡'äs÷īŻ000 %MČՆ҇=lƒ;wź"Ķ«4’_·$²Į(øŲ.Ev*éĖWęMŌ tú廄ų¦‰PNG  IHDR/ŠBTsRGB®ĪégAMA± üa³IDATx^ķÜūOSgš/¶–›$„p±Q3c”^£a,Œ‰śƒ&ÓÅ,S’€E£Sć¢ń’LĮ˜›—^‚Nq±ŠJ¢"Ø(h¹„PJTīōN×sx&`K”Č“ļĒžē„¶=ļ9}Īū>=,V`Ę-M£Æ Ćø!Vʍ±Ą0nŒ†qc¬0Œc€aÜŲ„üš^Į=t÷tS6u<==iÄ9»vķ¢ĢVzZ:Ł”Mœ¾¾>¤¦¦ĀßߟF†suĪżfų!å»ŹlÜ-@Ooe“«õŸVģłye®\¾įt!eĪ EāŹDŹååęYÆzJ&‰Éh²åĖ ‘HhÄÖŁßĻ"(8ˆ2ēF¬L\‰ˆČqW\•——GŃŌŹĶĶ„hdUUU•JE™óF;¶““4Š&VMM„±±‘2[®Īłhļ{*Ļé7(”MŃųdddP4Ü„K—(š<ķķķ–āābŹģ;wīEĪkkk³¼|ł’²±¹yė¦åŲoĒ(́‚ƒ„…†‡ˆ‰Š‹Œž’’’Ž‘’┕–—˜™š›œžŸ ”¢£¤„¦§Ø©Ŗ«¬­®Æ°±²³“µ¶·ø¹ŗ»¼½¾æĄĮįĆÄÅĘĒČÉŹĖĢĶĪĻŠŃŅÓŌÕÖ×ŲŁŚŪÜŻŽßąž’’’ž’’’ćäåęēčéźė ķīļšńņóōõö÷ųłśūüżž’      1!2"#$%&'()*+,-./03ID456789:;<=>?@ABCEUFGHJ]KLMNOPQRSTVlWXYZ[\^‰_`abcdefghkjž’’’m¬įopqrstŠż’’’wxyz{|}~€ ó+yU‚ĢģL¬X±s£ęŅč  /F“;wģ„Įh€µāą}Å{ܼq™ü÷ ‘™™‰²ņ2>Ÿj÷īŽC?eKoŠ#’Æ|tuvńĖ犷(|TU“Šč‘_ė •Õ•P*•üߏw•ü…ÕŁŁ ©TŠ Y9Äo9ŒŚŚZ(8pąźõ(zRÄ?ĻŃcGa6›łų’€Ū657”®®Ž?®Ļ^ąźÕ«0ŒČĻĻG¹¬'NĄõk×qśĢiČårČėåŲ’Ė~TØFiI) ąü…óØx]AĻźµRg%Ļ(›J•™fB(bĒ÷;h»ńi“ŝ”[·nĮd2ŃČŲq“7Tģ²X<~šQ’(~’„ŽÖ—Ń |oõźÕüėĢ ˜50ąīe]ŖRf_ss36oŽĢĒf£Ŗ6¦M{ŻćęĆŃkhµZŠ€ \€°_ˆG‚Gž-Ŗ­[ąč¢ā"|lżˆŻ?ķ¦GŽĶ;w@ŁpŸĻ¹³d2™Ććā.ō”dļdDKPŻn=Ÿ^Bh{“Hž6҇R“kŚł‚æjÕ*hZ5XŸ² ķŌbN̾0DEDaž7ó-‰¶;’Ÿæ—ÖÖVŠĘ§““¾¾¾” R«ÕƒõuõLĄ¬7£ĻŲ‡®Ž.$%%AśX µJ ƒÉ€¤Ä$~¾SÖ¦@Ł¢DGKę-š‡ćĒ#4(=ˆ\M.ÄįbzfąĮƒP(”Łā^ū?³ĆfćIÉ,_N#£ćŠ.WdķŃźµбż‡ķššpÜšųT6nÜH™s®]»FŃĄ `¦ßL˜f˜Ø©­įĻÆ¦[ƒŽĪDJ"ł ]Ō*ā W°d52ōvõ¢·æŗ^b$1Xøh!Äbˆ|Ev/ŹĻßKNNE@­¼s%¶ĖWGāāāģßåĖ—)²Ž%ÕJt÷uóMHė¾°. «ź«ŠÓӃؘ(˜=Ģčlļ„Ü(‡Ÿ·^—½†ŁśGgŠń…Ÿ»ĮÅÅĒįŌ©SšņōBąĢĮfšš5k@™­““4Š˜“ĪŻx×®]‹ŲXŪĻPŃó"(*HNNõĆĻ£^€K¦²a4Ōxš€åoŹ-ÖÕe£ķŲ5Ӟ?§ČyĪ4ĒÓäü’š€Žęa$_R°¹±Ł¢nSS6ŗŃš€z­ŽrńŅEKĮķ‹u»K£öĻ©Ū5¹;‘3[W,MXJŃä ”čė4Ņ*čkĮm‚ƒ)sČK„m[·aqübdåd”ģķČż¶ ł=€Ū·oC§ÓQ6uø%Ž£å9‡ėpū%///q·gÜ»w/e¶Īœ9ƒŠŠPŹ&· ݰaƈ=Wē\$ńĻ?®O£×ė)›\MMMŲ·oe²²²ąććC™óÄb1ßośœuĄūdā~NĻ-’££GŽöū’ĘM”¼(A|BŗŽ„…%&LšĄ#e‡’”±²‘GGKK 'LD‹256_24bce8348b2dd3cc*’’’’’’’’’’’’“Ū 256_e333db68c318f3ea*’’’’’’’’’’’’Ā˜256_37d47c8443930b28*’’’’’’’’’’’’ģÜ256_9f8a104110d437a8*’’’’’’’’’’’’˜ ž<Ó}PŠ0s<°ĢwzõźÅ3'pM RN§šHِQC°oē>uÕ«!?#ē‘2«‘VŲ’ł~uœ¼«y¬ązĶ÷ā™nD,DsLŸ>]Ø©©įQĒrppą£'1‚ŗ–=iŲ°a|Ō± …Ē£ī…ī¢ĮØ¢ĮØ¢ĮØ%÷qų›ĆØ*ÆāÕ«ÆÆĒ—{æD}C=Ļt/%å%X¹y%Ō ¢$’ē|\ϻޗL^āÕ+«(CĮĶčéź”Ø¤YYYČ»™Ē×6’L…łørł rrrXźlżLśĮŁÜ;÷īäõA€(Y²x <xņØs$ŸMĘĖÖ/#ćXįæš[į‡ė…×Qx»oĻ~G“":6ųVė-Ļ·p#÷jźjxF=P ”@g°ĢMĶy¦s䞘‹ńåK–#*2 īīīš]ģ‹lY6ä‡äšrõ‚ßū~9f$*Ė*łVKK[ ś}ōQq»‚gŌ5©={öąžż¶uŁmŻŗr¹<óXž­|¼?ē}Čä2ži+++ńHYdd$.]ŗÄ£ĒÄOŌw—¾‹OB>—§FٌB= „£…¹‹ę"!.oü˜†»ĻtGxt8†Xį[·ßąĮƒĢ#e›6mBnn.”566"śßŃšp÷€ÅĖ<Ū6ā%Mtt4œœœx¦m<==!‘Hx¤t 6nÜ›6-FFF|«'‰Ÿü×kÆóØżōõõ[|Oqź–”W•CŠ`5ČŖłć Į?Ā’[ł·0Ņd$R.§°ƒ·€z³z ź?ˆoł|ÄŖ„ŸO\zö|śįŠ$4įNćvŸāyXZZ¶ųžO[Ž;†źźj¾µ ±v ņB=z4µ®µN@i˜TńØ}ž§0ót¦šmü·l|5’*Ū‡½½½Šü_(­(–/[ĪÖÉ3äĀvév6ž#ž·°čV‘°ĮŚēy:}}}…’’©%¾«}”HS ¢¬s®um_³Åō…ÓŁŲj€ŅŅŅpīÜ9ōīŻ¦Ę¦Ųŗm+[7éÕIšłŠ‡;›x–¶! «66–G@DD®\æĀ#(ķ[\~ŪČāęęĘrÉņdž!¤{©ž„kW­Å–ø-°›d‡äÉ-NŹŅ% M‘†ß”••±8'/‡M›dõŖ®żōą Æ­®EZz-·*ŠÓ°'R¦²u—~¾ÄŗŖÄ©°ÄÅ÷#_ĢsŸĒÖķ‰ŚƒĻc?gł˜­1Ųp?®ę_EZfŹĖŃĆ÷U•V”I· ©‰öåĘ6ĖĆżūśchjlĀ”ÉS¼>{"÷ čƒ Ü,¾É¶!¤;Øūµ_}óŽpy¶Óm»1NŽNŠŃÖįÆPÖ%ĄČĄ±ŅX…”¼²ĘFĘ,?cņ ČNÉp·į. nĄ¤æ śõĮٜ³°·µGjz*J)eÆ×ÖÖf-ābmjā’bŌVŌbūķˆŁĆņęęX€’Ū%04Pn’Ÿń~čĀ• m=g2Ī ø¬ų‰ż[™X±ż—T”`õŹÕ°aĆ!†;l,Ŗk;aŚ&BŚądŅI¬ @~z>dßĖąīģ}]}¾¶e]R $0l†„ŽKq6õ,Œz5 7ÆØ†æ6¹7rń“ā'ō5č m-mbĀpėŠŌŒTöś#GŽ`芔lqņtĀī»QÓX6“ĢC&bŅøIč-éĶ&Y|øĶ›ĪoņWYײ`1ŠļĢĒgūOMM}ōZĒŁŽˆŪÓ¾¦˜śöTv*µ7 C Å+ƒ^į{!¤kŌTÖĄū]o|ńĆ\ˆÖō`Å6hW#PH`äi-µņo‰›ŲŪŪ#**Šg”mßµ£†ŽĀŪ1HˆO€™µd‡dģšüTņ)čÜ×AäĪHģŠŪS=SLp™‰ž ÷ą6Ė S’6›Ć6cß¾}H:™„ߟ@DXjļÖbö“Ł8rüō{=Ø|bńhŅjbcģȱpttdłŖœ*|€ŅptqdūætĀåÆ.xĻė=¬šY¤¤$üxęG$$$@ŗYŹ&”¬»[‡„ƐŸ“ĄõŠŃmłŌź066fCҵpęŠĄ%06|fū{ĪĪĪ8uź8±t“ցbwŠ͟°lœ©Č„„K—²ø Ø@_.ų­÷cqJJŠ8žļŌŽÖF¬Š2‹„yóę±\}C½ą³ÄGˆŁĆāõ’\/ųčĻĘUæT Ż ē3„˜1‚\.gyŃłœóĀ¢e‹„Ó §…ŲÆcY®®¦N Š/ ®®®,×\t„€Ul²Ģ;5wƅ^B¼4^Ø©SĶWl‹ŚŪD4ŪķŅŪĀŽų”צǾ9ƳOzżõ׳č±.¹ōēAlī9‘ĶXH?”²O=QóžČ/ŹĒ‚ڈģ>Æi^llØoĖ_-!ūÆ &&&,§«£‹čĻ¢±ū?»qüŪćX»r-lķm1|ųp889ĄnšlGŪ*½§Č²æ%ś÷CāåD,zgĖI $"‚ļßĮŌōĮe„xó$|s8e‰HJLbϼoڶ ć^‡qöćpžrŪ[v Q3S3,žæ‡’!%; f-@aa!{&§5Ŗy ¬ŒĶU’“Kņl¶¶¶O“‚ÖČOŹqōČQ4ļ©ó0`ä–oé KĪ!Ŗćäā„ŠM”°f ×Y®%>ż›žØ¢†t$:p{Ė Šl™ xąŻālGTQcŗzŗFoüüyö1•ŻX³f BBBx†“ĒĢ™3u)ŅQÄCż÷ķĄ*)boæT*åi/333ųųtĶ×`Ķ¢’@y1Š=B4B4B4B4€ƒy9Šäkf‰PNG  IHDR ż©¦äsRGB®ĪégAMA± üa*IDATx^ķÜmLSWš?Cy‰Ck|AĒČTŖ2ebä%ø9ć̌_¦Ģ}ŠČL–)&Kœ_ę3‡‰q†“²čx)ę»"ņb¦$ˆ0DJ©ŲŅI)Č]ļį(–A)P“¬Ļ/!<ĻinSąöé=ē\'Į„‡ō’Nq@Tq`4 6sļŽ=šldüVųĮ’užõ)+-CõķjžŁ/”WĄ‡}ggg>2qP 6“››‹ŠŠPLš4‰X/>>QQQ<ė“ššŠˆˆžŁ/±č…„„ĄĶĶL4 āQ FVFŌ5®—]‡xįZ|­Ś-ž*’  HĻL‡NÆCaQ!÷>ęGKؐ CŪ©ÅéÓ§axdĄ·G¾…×+^ؾ^Šź œJ9]»)‰)ŠØ5ČĖĖćGKØ@¬²mŪ6ųū›7éŖŖŖĀ‰'žö:::ąįįĮāᄇ‡cåŹ•<ėÓŌŌ„ŲŲX·?lG^~ī×ßĒ,ļY0ź@My fĢüßņńĘņ7ŠŖj…t‰+0sęLvģx{%%%˜R6¾Ųw1<ēxbŠĒH¦I0ž|~BõˆU’’’ɳĮÕ××#++‹g#³jÕ*,_¾œg} ŹĖĖyfæÄ·Ptt“ÅõŁŁŁXæ~½ŻõØ«XSČŠģµŠ€F€F€F€fÓ&ą?’ ńn#Ļ&Sł“śH1Éyšī­^Æg«ŃFcĪ+s ™*a±N§Css3‹ķž3ą»Š—'żØ 86–š€5u5xlłŽ7,˜·€g£cӐ›—‹E‹ ł†²7UÕUX¶lžącGœ/Æ]»–ÅWÆ^eŪdŸøU} æ`žĻ<Ģõš‹nC7‚ƒƒł£/ÖłóēašĘń¬Ÿų»ū%dtÄAq“ŅĄO`‘ųĮø’~žEW‹°ŌoéēåāmŌ†Śn­T(±ļ‹}¾&å#}LSSģŚÕכٶ 8ąžpiæ¤aĖę-ˆū.A+ƒ ø¢€÷|o8;9摾$īÜU߅ÄCŠĮƒÖ0Ķ“ąóŖß¾G¾>‚=ūöąLŹlß¹=Æ­ˆ'µø³LüĢĄĘMžłšó÷Ć왳YnÉɓ'±sēN¼·]ŚĻih~،Y/Ļ‚›»6¼»īSži̼@b÷ę“ēēčŃ£ˆ‰‰į Ļ–cŻŗup™ģĀGg鞉­šV¤ž”Š÷Öæ‡…¾ Ÿž€š€#l–””šČ²’[ŒŸg›€F£Q(*.ā™e֜W„E„Ā÷ńß mmm,7]5°ļOŠB  ā!¶'ŽUHœŪJ`H "wDāŠņ dēe¬Łž,›NŹŹŹŲm”›ēŲ£öövv 5}śt>bN¼ĶÓķŪ·GõóL›6 7ndń„K— RŁöæćEÜŅ{ąĄž‘ēįąĮƒJĶēźÖhmmÅŽ½{y6<½VŚ»µš_Ök7›BČÄBSBBBš/»`@ĆÜv¬\IEND®B`‚¦×•~öĀ£ @$Ķzv•"Ķ„ŚJ°\[«ĀŒ"øĻ›*>WÉ'pčyB4š°¶&d3—†IEND®B`‚… Ęģ:ĘŁĪ;T^ ’D’öæ’ҹ«:ā-bOź_ŁwÖ|É'5=ė`j"9zRpP0*«*»¤CQE„¤„ą[‡o¹“`Ҽ<½`Ńæc})æ¦Ąikė¾¾ūī;ōļߟFņ)xY€{$»`»tńjjkøV“Žˆ‹‡Ū^Ł£ )šŗ„K°'NpŻj)[YY™ŠßߟF ѕ]‚Eß°4RŽŠŠPaII $)ŚM–³³3“tšąA:'?OOO:×ģüłóĀŚŚZÉÆ½ĻīčŒysUWUsחäå唓“”–2b•ÕŹG© ą·§æ!'7§OŸĘöoĒćŒĒō7̟UuM5""#P\VŒ¬Y\ФgēS§N!)5)'źN¹BqQ1īŽ»‹§Ožrē$āāń,ē׃tLl ņ‹Śn»V9gįģO£Žƒ$ʰ;a„¢Ć‚:ZŌcz$ģļ²Ē;Ų™’š‘ ĒķŽÜˆ¼™Ļ3ŃG·ć¹~Ż’ī%a‡ćlÜ“i™i8łóI|ķš5¹øņ\įčä˜Iz“„‹eŗĄ­Š[8zō(B®‡ŠőQ›Ž¹ƒÕ0+„‡†#80˜-čüÅó004€~}³»Iwńł’Ļq'é~/ų~WüpõÖՊĮƒ?ń>ī  A035CB\ןCz”ńO Q×p’os—ķŠ"'0ĒÆ;īvŸL鑐™ž ŪŚĀy»óŲ`’`øģvž‘Ž2Uƒ°N.NpŚķ„wƼƒQ#GĮŃŃW.\!ĒžÉÖVÖšæč›!6puvµV'g™.3nģ8|šĮ˜8a"-QŁŁė“ėørdL‚‰ļM„¦¶&JŠK0Ęf 2R2t]]\įÄā\(bqĖ‰PNG  IHDRä֑ńsRGB®ĪégAMA± üanIDATx^ķŚ{LTWš/Rׅ•¢Å€qeÕö»Ż ŹJ]×WmҦ›5­›h¬‚&ņZ¶ĶF)hc\ĘĄ +Ek,ĀÓ%<‹‚ŠpZtaLygŹČ`”)Œ0¼f`˜įģ½Ē£Ķ,¦”92™ū;sē2sﹿ9ēwÆ€ć8‡“Œ=sē€xą8ĘĒ90ž8΁ńĄqŒ'Žs`ü2   ž’’’ 6 !"#$%&'()*+,-./012345ž’’’7‚9:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]€_`abcdefghijklmnopqrstuvwxyz{|}~ž’’’ ČļČŃ£éa‘õ¼¼¼°{÷nMUTX愑Eöµ}ēvlX·E–Ŗ«ŖQ[WĖ¢łŁ“aŽ’ėū,śyłųĢĒX㹆EÖÓōh ‹•±Čžl–Ŗ««QWW‡+V°–„”µµńńńX¾|9k™^LL NŸ>Ķ"ė%''#44”E–ÄC”ššŠćĒ³ū™œœDVVŽ;ĘZ,‰Æ>|NNN¬Åz2™lŚ}g6›qāÄ ųśś²ūæ·§§'żn³‘H$8{ö,‹¬'W-<£ĮˆqÓ8ÜÜÜ7ˆ Ą*++‰N§cŃŅQRRBŒF#‹fĶ–ę'11‘-M%tFrżśuŁ—p’““4M•™™I?ßóJ„lɒÉd"ééé,²Æ‰‰ "$7Ķ,**Š-Ķ½Ž«xå5r"‰’ņņrÖJÆ,aŻ0L&-œ®ž.¶$übNš1¤bgoĀł„»µwY“xÜÆæ¤+IxŃķE‡³ÖĒ,h“ˆüG$ʉĆćOĪBŸ³²³•žmæ ×pžüy„……”µ„•½ˆ–FÓu„—„21*Ė+”hV@"•@Ū«…ō_R¶ęāU”SēœYd{Ź6%²od#óߙøyó& ņ PV^†Ā¼B¢ņėJ¶ęŅ26>†īžnÄ&ÄŅ>Ō«é…~LOūŁąš rņr#‰ĮgiŸ”ōf)üOś£ÆÆŅ8)ōz=®¤\AźõTōōÓ÷Ų’8 źł®‡&āÅ@Ó©Aģ§±AčßCįó{öŹn@Æõ^ØQŌ`blĪĪĪšööĘś_ÆĒ»~±’XBĄ8rä^ūŻkģ€««+ĀĆĆńöž·”~ØĘ÷½ßCy_‰’ö!"ĪEąųöŸ [Cü¾ŗtĻ5/žŲqsSsį³Åė^Y‡®ŗŠŠŠ€QŻ(Ü\Ü T+QüŸb¶öŅrYvņÆåXķ¼UÕUČ+ȃB®@SSnÜø5«× ül8\~å‚6Užå Ōjø’ĀZ`ėo·¢³«_T|I2ɶj;®n®vłĶfD?‚„äÜk¾‡° 0ģŁ³gƾ8mšNõ4·4³hnT*.^¼ˆ•+WŅø_ӏƞūœ„æy ¼_ńFpąćįG}}=šą·ĆžģķķxóOoŅ×Dq‰qų(ų#”V”ĀĆӃfņIó$Μ>ƒœōœ :I·k⯫Z­¦ l6>¤£–'’“j9ܚMdd$M3÷ӓbŃøqQ’(¬u[‹Æn¤N®c³÷f¬żĶZøüŅĖ–-þ=ūčśĻC,†ĄĻĻµXR(HIIyŚĮ“Z-}öšš ĻsqčŠ!ģŪ7õ³Š]ÓŻŻG„±ĮhĄÕų«xŻļuh»µPµ« jSŃŃeŹÕ†BqO·Žy —b.aó¦ĶŲ²m ***ąćėMƆ&Hu›Ū’øoüį ŗŻé˜L&œ:uź™HFƒ .°ČĶĖÅ{ߣū.Ä" 82±5“Ń„­¾[±cĒ‹¾;88H‹õū÷ļÜ &[ų’"ąąų ²2¾)(( ™“`r-å)-/%Ä,¼§¬’ō öŽöb0Čšš0}ÜŹæE¢žEn~›Ø؉Él"ĀŠŸ™›|Yõ%ūö1ß"`~Y>яźYōlÖÅż$ iqēŃ£GdhpˆčFtDHD蔓€f āö­)ź zś°Ę\‹€Ā/6ÉĪĶ& Ÿ&>m‰–E“Œ“ ŅŃŃAŠnŃĻQVXFd—ed €ŌŽÆ%Ż?tU“Š|[’-i’®Ü­ŗKĢ&3)É-a[Ž|Š€ā’o¬kdŃÜ,TP˜†e ‘\’ÖęÖ§Ēh``Ą¢øh®|S’ ~mécŌ0ŹZzü*Ąāæ ö=[[JWn—Ž&ń²xŅŁŁ9%Ųģ>€ŖŖ*:\z2X*Ä)Ąęt€X·˜Æ¤¤$„„„°Č’xˆ„“Ю׋ŸNndddĢx@qq1-²=±ŠČ¢‰µŽģģģ§S{§¹¹¹Ļ¼@¼wcŪ¶m,²^cc#āāāX“pÄ}™™• Ƙ/o|łéĄf @©T"??ĪsŸŸ‹‘‘:Ē{V @¼™Eģ4óµjÕ*±hŖˆˆŗĪOa×®]Ų¹s'‹ģGL>ēĪ£u{O‹½{÷Ņ9ōR"L!L©ńŅź—hĢoę8Ęoā8ĘĒ90ž8΁ńĄq ųÕķōÓptź IEND®B`‚¼y3×l ĪÜq“ŖŽlÅq«¹ @…­‹øÓų‘“ “%Ųł“' r 0÷ùŠy„ƒŲ[±ś¾?ūZi©iįEĮ XZZbęĢ™t©]‡|‘˜żÕŒFSßPļ“Žø~ć:n^»IK§©«©ŁPŌŠć—×vŖ€ >!«ēŁ›7or½ńŠ›fRŅS'eUe܈@śØl¬DuE5Ž}ū]<żżifMiµ®.īŻ»}}¬ł×aąõĄį+į¤YĪĀå€ĖP×UĒ÷ßĖ}2ĶĘĶĶ S§N„%LXX˜ÄĄ Ļž€ É !:*ļ8p‰PNG  IHDR%­d7WsRGB®ĪégAMA± üa *IDATx^ķŻėO“Yš/ rSAiE "fVw˜]¼Œ“Œ3¾qĘ«/L$¾Š‰Ī`²Éųf²ĘlF‰—qwL6YgŒ¬€ICÕf•KäRn„@ŃR “PʽåÖgŸēp6ĮŅ"Ö9Ÿ¦įł§åyŚšœžó;ēŽ†aV¤Uō'Ć0+k0¢‘™ž‰¾ž>‰K³¦?ßž™FV0¢‘žžŽääd‰‹˜Ļķm°.³¬4k›éÖ įó«­µ ­śVčZu“0›Ģ˜žž¦Pü[1y¬Nļ| ¬¾Ä£Ū ó^544 !!F@¹Ŗii„I0Ęß ¢“¤EEEŲ¶m._½ “Ń„§Ŗ§ąläłrp“śzū ųV‹ٹŁŻ å%Bֆ@§ÕAÆ×Ćn³£½£2 šæ…ØÆÆĒ§{?„GžėõsūP°.ćU/;PŖ*„ŃlUUUø~ż:€Ņ²RŌkź!“ʐšĒŌ4ÖĄĒꃚĶᰚ¬°Y‚ؘ(ōZ{ŗ6f‹£ć£ąoMMX¾ŅH)bcbŃÜҌ ”088’užĄ8°{Ļn XP­®Ę™3gč‘ēŗ’>|||hä¾ą `$ż9‰FāĆ*Ę«r9H:>’ńz?ūaīCX¬DnŽ„QoÄWś eI±ć;š¬ādŪe°ŁmIdčźéBKk ¢6D‘ęæd«„$ļöķŁ‡šČpŌ5Õa»l;rór! —":&›c7cßŅ2ųü‹Ļé‘ēZlĄÕė”`oį?IéÖ\®ö½o‹=71æ&K2Ģ ĘŗŒW¹jJ+ Ųl6‰‹F£ĮåĖ—iä>±² €ńŖu<żMÄžzY€aV°%mäęäbdt„Fā! ß>|ėׯ§%NĆĆĆČĶĶ]ŌšœcĒŽ!88˜–8 CMyyy‹ś½ļ’p>IĒ’DKœŸŸæč÷āųńć %óc-§ńńq(²ppZā>žöĶ”oJKIØ–Ź­[·č–øF®¾¾žF³µ··s­­­4ņŒšÜ¶¶6ĶĘ÷¹ĪĪN‰‡p¾/^¼ Ńl\WW<#<·»»›Fo&ö¬ųRsõzM&WUUE#ĻōōōpÕÕÕ4rÉlāģv;f°.Ć|ąF†Fy?©’J%-ŽW½³ @õL…¶ö64iš099‰2Uģćv¤ŽI%ūKJKPVVF&qä=ĢĆŠŠ)ƒŗŚ:ŗÅ0ŽÓŃŻž¾~½=įŗSä( Ļ’ć䩓8zō(ŻćōĪ*­V m£†2ļŗ¢ŖĶuĶč4t¢ųi14Ķōš{Iįć烱±1śĢ÷«¤¤Ņh)–ް8åŹµ+ČČĢĄŻŒ»ųéļ?įę?n’²ņšrüš×Čbf劖D“ĢŪrL;P¬*Fź?S±’~2ÅyÕŖł/õ9I@įbĶÉÉĮ“ù’Ź]Ā"‹‹/’ķ“§įČŃ#Hł[ Nœ<¢Ā"ųś"`U>žżĒØRWįĄŠ©uˆKˆĆéH6KČs—߯EZZ¢££i‰Soo/IĘĒĒ“XH9räoŲ«ų¾4²³³IKœ„cž:u QQQ$¾÷Ė=ōXz°)b,śś*k*±#~Ź+ŹqīÜ9ĪMĢ-5NG’“7n¤%NF£§OŸ†TźyŲŌŌ„'Ož,˜”Ŗ¬¬ÄĶ›7iōį»{÷.Ö¬YC£Ł„VļŽ½{±k×.Z¤g¤#łŌĀIR“É„;wī@&“ѧēϟ#6.ēæ=  ēߔZ­&“„'TKåÕ$ೊgäg‰Ŗ„ÓiuœĆįąŌjNY¤$åyŁyܘ}ŒS*¹—ś—܍k7ø_ł•ģ[jž$ z§*WŃČ5O’€ƒCƒÜ78¾ÅĆiŌ.G‘Ć]ŗr‰“Ėå‹N-†»I@+(( Ūī`IĄły’“Z¹‚\÷Žó…’€ƒßą””ÜäŌ$)«­­åų<²żl`žQ«ÕJ·\{›Q€‰‰ r÷6OFģ³3Ę®° `~žTĆĆĆäƒŅīŽtwusWÆ]åŌ5yüė˜Ē[­ŗĮĻĻÜÅĢßϟn1ްvķŚEĶĮpE"•ąūæ|Ū  ņ łœß椁RRR°eˉ‡0æüąĮƒˆ‰‰”%Nf³YYYäĶ÷Ōčč(’’’ ‘ĢĶ]żi¾ ĄĄ@Z"###8qā6mŚDKœ =z“Øsś³BĪ#,,Œ–ĢMr&‹Ż»woĮ÷l>v»äŠāāāhÉĀ„%ŅBnėÕJ€­`¼ŠUāĀ*Ę«\]}}}d”b¹¾P$qW"fcüĀÕ!ģ›o²ŠŲÉårœ={–F³‰½`I@FTÖ­[·ģīžžĖ7YŹ*F“„©¬V«•$ÆI|<.@’ĢtY‹ÅB±™™™Pרń@ž€¬°›˜˜ SĻ…Äd浟¬¶&Ųü˜ņ#j’8ƒCƒlę%}-8ćU®¾^ūõ}J„rę+æł›ļj_( ŠP׀S¦¦§p;õ6FFÉŽké%KŃ;^t o ķ­ķŠč40u™H…ŃÓßY¬ F«°ÅÅÅŲ³w[3>āÉkÖ`¼jzjš|a1’ž⧅жhé£fLLM Ģ7 †Lf™+/Ū*CxH8)K>ž ū„żī#ÄFÅbēĪßŽśźz2¬k1[Č'½pĢÄOÉ4ōN]'""#pī»sX½z5=ŅŹÅ’€ŒW  arl˜āaæ _žī²fįüłó|0£IŪc—‘¬įxŁņ‰‰‰Š¶iŒųńdįĢ—_| ƒŽ€­q[”ļÖCעþOö”ŪŅXY,*+*É•<ĪyŒi’ilßNž‡Ąg»?[²I7ĀXž›.#a€0?B¬XĄˆ†Ų3ęo²\Ļ[Ąŗ ³‚±#P©T4Z>„Š .ŠhyaƬ`¬ Ą0+«fÅžJžG}ŽI—IEND®B`‚Ó’HķØĮŠ4Bī’Ł6[¤v‘Ļ’æ31,Ģ}É$“Üš?°4OśY=CII  a5Ԋ–J"ƒNäēē·ŗˆ$66–»½ō¦)іt1č"’S’±nĶ:;r żōĆōÉÓań–®]»†Œ“ ̚: AaAŠÖŌ†Ż ;īK@”øŽ¤É˜QQųņ«/anbŽ“Üv’‡ '«ēdņ÷HĻbI I0µ0256_3a04f2fd034c68b8**’’’’8Ī 256_2f840d061f1c8b18*’’’’’’’’’’’’^m256_6711f4ad5df6f3ac*(3’’’’ˆ] 256_f166377bbc662836*7’’’’’’’’®~¶ ŖŻš<3|(®‰PNG  IHDR€#$sRGB®ĪégAMA± üa `IDATx^ķœ PGĒ’č±ĄŠu!w‘H)'¹ŠU4&Xń,S„1–„ĮŠ^ #*>x%pń4œ¢‚Į£¼S¢sT ' ŗ`Œ¼ä¹(‚Žģ.śfz{Ea–ڐ";æ­®łž=3½Ż3Ż_OĻ·µ„zÉ$¶ŠC  Ē@@@€€€#8=F§Q€ĪĪNōōō0%0LŒM0Åt Sš‘+äčRt1„b1ÄSÄL©čUö¢££ēųXĢՅKščźī‚\&gJ;ŒajjŹŌpš[›AśĒ·±“&M‚™™Sƒtõpķģc;øvN}~;Ē‚N€ūnw,ūĖ2¦FCʵ ;~Œ)Ķģ Ž‡łšĻ”vdI²že8S*’R’ŠŃŚAĻx’•°š0¦ž%$"³­g3„WÓ®āDō ¦†³nÓ:lZ·‰©ń!-5 Ń'£™$ģXl’hĖ”v¤§„#*:Š)Į;]įććĆ,ŃāīīάēĢ,ķńōōdÖ ‰‰‰¤½½©ńĆĖĖ‹YĆ a–öxxx0K3žžžĢ?Ž=ʬg e–öhŗ—ŚņsĆϤ»§›)B„wz@?Īž? æ=~x\’˜åžĀ/9ƒķ;·£“¼ł÷ņįį遖ĘųśūĀÓŪŁųö»o{&–čČ!\¼|«×¬ĘöķŪq&ī øŁī»{%%%ˆ‹€·—7‚Ń|5=½=prr7ĖĄ'Ą×2ÆĮÕÕŽŽŽ8{ī,öŚĒEŽš÷óĒįĆtx0·ļ݆äG b’Kæ“?ž|üyųļń§6ŸŹ«Ėń¦Ó›“=UČČČ`ßśė‘œšŒŖŚ*¦tĖ”ŠCĢRq9ń2½¾C‰9eŸ’©‰IäńHf©øpį˜m_`p \¶ø ¤ø„åźI–Ņ )Sŗ'ćFö`į ±Õu+ĖUń‹;€©Ü§žQ=ŚŪ`¬4Fdt$B„ā«ˆÆśŸT(ä  xŌšŻŻŻų`ÕpssCPPÖÆ_ŽŽ^Z–R©¤^,'7‡®i—:-…¢‹;—1@ąč興ˆĢyeD="PżŃʏp`ϼķō6¾ł ģŠrM Mš°č!2³31Żj:öļßO’pƇШͧ˜D¤učėėcßśėQ_XŪWʶ–Ō„¼Kw7wģöŚĶySn­z" ŸzŠKé—‹¤Ä$ųŗūbŪ®mč•÷"ę_1øzå*&L¼‡ČYvøīĄN0P (,^ī^H»•†oĪ}ƒK‰—ąė鋝ī;ѣщ·–½…ššp$'%³tĖ’%K’]#€ļ¬ŽÜēęĶ›ąÖ‡ˆ‹‹£ē?y‘HNI¦ƒ^ l^^ø5ņóóѬlFLL =wčŒmckƒ”ŒśDP×Z‡Y¦³č€ŽŽ¦Ē_æ~¾yēm>Éår˜š›āµłÆ”VZĖJŃ ¼#Ņt-ŸNüżxš¦ĒM™É˜z1|Tfhy40„¬Ō,xžĶ›’ŗö¶‡©Č&&&čØķ / Š 6ĆbŗŹjŹą²ŃK—bņäɬ„‘yQæāÆńXįū¦2ՉŸˆžęJĀģ’Ē~ltވYsfĮ|Š9DF"(źX“`2%™ō~›ˆMŠÖŃ[s[œŽ= _?_VĀčŠT…bpŅRĆ÷]¾’ÄHķT§†Ę|~šsDŠBHPV:Æ6šÕüŽmŸ”įqņīä15zŚŚŚ˜„‚p10ƒ©µ) Š šśÆ#>>3ĶgĀl²śŒT³é{Ėßæ͛°7xÆźŒĖęųāŋįēēI¶„z'±kĒ.Üųß :k™ŠUaž&ŪŚŚb͚5ųžæßĆhĄĖ—/‡µµõ“0˜ŗ#Ų¼jß}¾8wŅ*)^žż2š+V¬€•• ˉD"ZO?é§Ūw–¾//¼’īūTė‚ęęfźp^D]]³T˜[™£÷±źÉh$†•_TT„Õ«W3„Bi¬DEe’.&įc׏Q÷Ø–f–°“¶Äƒ`gc{{{”ä—Ąn¶uBsēĪegMuQS]]ͬAųž4mŚ4¦žOkkė ÆįP 4Q¢¬¼ §£Oc˶-˜n6ĶFĶxÉś%”–bĪģ9X°pŠŠ‹Š­čĘ×’žn›Żč2ˆōMuŖŖŅ¼lSįŽa(#µóię9ĢCeM%~HųĖŽ]†©æŸŹö »8:CS ¶¶–Čd2ĀyRSSCóŖŖ«H~A>į<įEøGjš_Y]I·Ü EøĒLjóēópž“&nĄœœ"­‘’ņņr"‘Hhā:5ÉĶĶ„ūź֓Y µłtæģ>-C]OåżJĀ9ŅŅŌBä29éģģ|r|YE­«Z·“µnŠóZŪ[I{“īŽ 5 u6Š“·\ŃFz•½äĪ;¤¼²œp˜’āĀbz]~*ś‰pŸ^‹ĘĘFz¼¬SFø%µG‹¶Q€k™×h]FBŪ(ߖܼ\ŚVnIGīŽ»KŠ‹Ši{īÜ}ŅVĪѾØī2…Œ•02ŚD HŚÕ4¦žĻX¢ŅJ) ō $)©)D٧$ŁŁŁD*•²½œgd[0Ža@Žš“OźŽ9Ń«ą;iw×`8ēyLä0`oj‰‰äģhs°ŸɏrpĻArźō©gĄ„ņ據1cM,W?ą×ŒFĘFLż612ė·Ķ‹~ÅØøQ¾Äq >;š ū é» 5ŚŒCCCøøŗĄŅĀ’å@·?ęcØü #Ńcgg‡µk×2„™ōōtpės¦“c޼yXµjS****ĄŌųįąą€•+W2õ,·nŻBff&SŚaccggg¦†Ć‡šųšU¤,ź&ŚŹk‰PNG  IHDRŽa2sRGB®ĪégAMA± üa’IDATx^ķÜ{LTWš/čŖa·q·>ž1Ż4Fk»nÜMcCž’’’ƒ„…†‡Š‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ”¢£¤„¦§Ø©Ŗ«¬­ž’’’ư±²³“µ¶·ø¹ŗ»¼½¾æĄĮĀĆÄÅĘĒČÉŹĖĢĶĪĻž’’’ŃŅž’’’ŌÕÖŲŚŪÜŻŽßąįāćäåęēčéźėģķīļšńņóōõö÷ųłśūüżž’ĀbŗM³&yX“ąŠTu”qķjÕnT| *2€PV]ć#Ń[ģš*Š.†ē(™į1Ģ0æ½ēp\–ĒPs>““¹æß̜;{sī¹ .¤€$INÉU\K’ä„d$'& €$91Y$ɉÉ INLIrb#zP•¤Bƒ”ADĪķ­łoįżŽ‘}‹IĒ“ŠjnĒņZź…ÅX,"ūžźž"ćt¬V«ČŒ}sfĪAąĒ"ź?£Ńˆ“Ō4“w“‹Œć¼>ću,"ĒѰjÕ*¤¦¦ŠČ¹āģŁ³"²Æ¹¹ÉÉɈŒŒNJŽŽĘįƇEdßķŪ·įéé‰yóę‰ĢŲ·råJdffŠØ’Š‹‹Q^^ooo‘q¶dddˆČńFü`Ā„ ²)m \]]{ķĆm †óyŒD,ö:\ļÅP™ŪĶørę ĀĆĆEęUr@’Ę!«ÅŠīü€ØČ(Lc:?tģĶØ*¬’~¹ėKd\ģņlüūF”k˱Āüüüx;’x'SNĀ×חĒĒO‡ÅjĮŽ;ųc:;;±%j Ļ?*ƾŲ} zļw4›ūĘ\”–•Šhx±mæŗ¦aaaČ-ČEL\ |>šĮ”ÉSÄ=z7Ŗ Ū±'»L†ūĻŻQZ\ ÆßzĮŌn‚¶NĖ_kēϟ‡©Ķ$Ń5{^¢-Au M¹åńÉUŠ 3h>üӇø~ė:Č8~óÄfŸŸÜ‚¹sęŠĢČQ’S/¾ś»¾Ś…ŖŹ*|żϧ«ÓQ_]uYĒgĢCV‡@•®Āįƒ‡Q×X‡™ fĀĒLJ7Ļ©žˆ;‡Äc‰øxõ""ÖE@}^m’ŲĘ7ræżpłŹeŽļhöö¢·qć›"^{öģĮ©”Sˆ9ƒµŸ¬Å“©ÓÄ-}›(®_ĮŖurR2Ÿ@Nløž2R.¬Źæ6ū5<.ĄōEÓ1Émfżj’’’Ľ€Cq‡”1ƲąŌ4ÖĄµÕn67ŲL6dŻŹ‚¶\ ]ƒ ,€ū4wų~ä‹s7Ī”E¹°uø°”Ę(SYY‰żū÷‹Č>ömčįį!¢.Ö6+LJQd‡y?ėŹ –F£é×ó(++CDD„ˆ^0T°{ĒnœL> c« -äłÖ¦V””–Ąg…–.\ _{ hyTq*ä’;UUŲŗu+ÜįĪĻpxøząé³§ˆŲZ]-"C#q)ćjĖk±üĻĖłģø£±mÆ?ƽ»ŗŗ:^øz3qRÆ»Xæ±}±ÆēĶē] BBšĪļߣP†T½RŽ%†½‹µuQ†ˆ“įÓ ¤«×‘ŸæI?C?j~$ļ?z“J„āķėė_SĢŃJLLäń¦šMT§Æ£€ ŗżĶm*.+ę}]¼r‘N$Š÷W¾W:&J<”HŹĖoüüüz}ŗ7½^O±±±āQ/|ö9ՙźD4x›6mźu½ŻŪĶ›7éŃ£GāQ]ĢmfZ¾ž”į;…­ £ĀĀBśöŅ·ōš?)**ŠRRSČh4Ņ­ģ[”ŸŸO•Õ•”¢J”}ū÷ń>Ÿkhl ß_ڳ“jžÕŠömŪI9ž„µ]K7žuƒ=÷t,’Ƴ?½YYY¢—>¤¬ģžł źu¬•iĖh憍$žļ3} KƲ[~ Ż ÓÖŽĘ rlHÖRF d2™H©Ī¼)‘,–’ÅVK׆Ćī’|™aoė‹]3¬åŪ“/F¬ōGSSSÆ@9v¦Ė.‹hš6oŽ,–ś–““Ó£š ”q9ƒL©2UŌ`h ŠOC)fw egeÓ՜«¼HÜ-øKUŗ*Ņ<ŌPaq!%Ē&ó µmŃŪhēßv’®JG™ ™¤JSіč-@Ļž=£ļr¾£šŖ±FĒb`0?~Ü£°"x0ń éz‘öžō„ÓÖIÕÅÕü‹3żtś+ūĄĖĘLpVC-lC`· ÕP ĄpHS§‘„Ż"¢įåČĄ>6ŚŖ’Wž³X,tGs‡”C#>:cčeö €ü;€qĀÕÅīīī"?VÆņqōH`ŸG÷¹šį4qāD¼ū»wqģÄ1P=!$8šūšólŻÉ IćČŌ)Sįõ‘ŽĘ…&Oƒ5›×Ą`“ŹtD 0ž|,Yb’œ ; pķŚ5ŁĒ~ °lŁ2~†c8ø¹¹õū·ńńńü÷ćE^^? 2PEEEˆŠŠĀ¬Y³DĘqrssq’ž} \é“Rœ>{%%%HKKŁä?•$' oŅĆÓ£g±–@’œ˜œ$'& €$91Y$ɉÉ INLIrZĄāĻ‘4eIEND®B`‚@@'lń׀ s:ĜNolķxĆæ¼JNNΘG2sęLlŲ°)Ż ü%˜€€#,ōĮč1‚Šc  ·’©»ʘ{×IEND®B`‚ąŲ±cāņåĖ,/łkĄ¬Œ,į?Ź_ųśū–@ahĖ?ZŃ0§CĢéŹ8źõ|²?QÅPĖö!=Z/Y²„FĶ?~̵“Dž¶¹yŪėyäČ.”µ ggg‰ž£ł|Œ1ū·ĢElåŹ•X¼x1$I®ņR8šx[m¬dšĒµkמ±£ EWÕÆøvL¢¦¦†ė†›ÜšHšjkkėDĖÓŗtķf’m6 śpyAęÉß"ĻķH“Id4š… ŅĘÅÅEāfy0|ųp˜˜˜Š’&dD§E‹µŁ6ŻŃg˽īļ4TŁšIS“¬f@rhÓr‡%5///¬ß°ž–ČF’¹iFšōņäAIl-r;²8}éAŌLœŃ~-lóęĶŲµk$‘}MOÆćcF(\&5q²˚Ä;ŗ˜ščAVŽ“{’‰<‡ļĢ¢ēk‘;™–,\óAęlPä§xžü^‘öfņzéõSåIQäó“^–ų³Q„čµŽłÅ¤×KŽ>|šņöBž…|degĮŻŻźGjxūyCyS‰E ¾Æų2© …%…8 p»Ę²"ēTĮŠ€Ģ%WKŠšSƒńSa H#Ÿ c“Ż”A”&"‹˜[ŚZ0M0m`3Cš(½VŠŒŒ ~ĀŠg@jf*„œQ;£ >+FūĆv|õŖ«ŖŃŌŲ„UWAR Į¶Ømø&¹†Õ?ā½Č÷žš777\•˰öķµxē÷ļ įXzzz°)|u<²•Ėš]ŃwšõōES[“=ZĢ’Õ|¼łö›(.*Fk[+Ö®[‹æY@ŸÕŲīŽ½‹ĻşcŽÜyżĘF^/²ž“<Š©éD́›®žbDūŒƒ#»Č;¶ķ@š«Į^dl‹9øfĶŗp±š"Ģö—„¶¶į›Ā±$dÉĄżŠū»’>V¬XA—zt=øZzK—-Ōé3ąéē OųĻņ‡‡‡ŗõŻx}ÉėxŠöē²Ļń·õöōƜYsąä3ųƆ%Æ-Įܹs1ļ×ópėÖ-ø ŻÉu śœśŠßߏą`HˤX½j5\]\ōŪ Čkäčhź@XXœęļwvvņĻ7l}ŲĄėEÖń’’[m]-–¾¶Ō¶ †d€a‘HD{Ć%&&ŅŽ€¶¦6Ś]~~>§Óéh4d“ǰ7*•Š+//§‘i™™™œ1ńŠČ6±c±é3§ÓcļX`ĘDNŸuttXŌ“Z-½õpʍŽÉåķ­‘C€©€™'F»JO&“A£ŃŠČ|üqõS—744 ®®ŽFömõźÕšõõ„ŃHb±Ū·o·éKĢSå2][a €0Œc €aŲø(•J|qī xūxӑɣiŅąpüaųūūӑ!įļ†#ti(ĢCī/)9‰FCŅÅéčl¶Ż¢P²†æ"n,ģ`|upśŌi“?j§‘yȅMŪwlGPP±IćI.—s4š\R©”Óh44.))‰öĢ—@{Ćæ8“g›Ģ=÷>UĪŃۊ±®xž×»®®ŽS(4²;`˜)NŪ­EĪ©œŹ>EG†¼šĄ’}żļÆł>™q•"JĮžżū‘ūÆ\ÄĒĒćäɓHūG:u ųj1Ęäϧ‰Ó ÓY6åÓ wŠÖŌF£ńS)Æä/Ce˜±iŃßJ¾„‘õČż],øˆŒĢ ¬XżĻ#§Cæų=Ø«8ļėįęw}///Dü!†~bcc!p «« w’{źj5źŖG£¬]Ś.žv!ļ|^šõ¬ÓŻÕØŻQHLLħIŸ"÷Ÿ¹ˆ=;” ±?®BWh›µčź¶žsÆØRąųńćüœ„č½Ńš ’3œÉ"ąĶņ›ż £‘eīŻ»‡]»vń3r÷ŸüżÄŠēc2ł#įo 8śē£ˆüc$½ŗn®nŲ½g7 !Ɣ#dqZš[°/z?!äy•••A"‘ĄŪ{dA’|cbbų>yĮĻž9‹ččh>;}ū°pįB )))Įłóēi~vYv^6‚ēC©P"šå@¼õĘ[š›>9æ—’’®¬¼ +W¬¤c­ŹŖJ„‡ŒZ”J„ČĪĪ¦Ńł-9<<ńŹāWčČpõõõČÉÉĮģŁ³éČHÕŹj„ž.[ŽŻBGˆD"ģŻ»—FIćéé" )‚Œ=Č}•ūWōŸ"Θø#±GøŽ¾^īćø9ƒĮĄ;zŒ«ØŖą²²²øøø8.īP'>+ę“Z-½—ēcn<‡ä„dĪÜ"`AAg|“8Qŗˆ‹‰įŅNMn‘ŠÜb“ńX‘ö˜ń`ܧ=ÓL½/— .s-­-4ɜ"ąĆ·\fZ&——Ÿ7¬™ššJ{C&ä,€^Æēz{{¹¾¾>>&_8‚Œ$ldl°o-KĪ”—r÷4÷hdš¹ €¼čd}É:uu±«īŪ¦§ß’0Ī䜔‘i–œP«ŌÜń£Ē9™\Ę&M%€ 9 ų]ŠiÓ¦ńńąõįdœ ń`#cƒż‰śF(id²ĖG֗¬Yē‰^Ę>‘ŸRß¹u'¬7ēå9ˆ’k<_“:‘t‚Ž÷B>™Ę­Œ[ĄIoäyŒĘøU6y›g5c¤·ÉŌņ¶ŅČŗ2¶ÉŌūõ¬fé›’ł1—¢?Āū[ß§£CĘżJĄööv\ŗt‰F“/22’’Mø§‘ā‹„«€ 6Šh™ŻF ޶Šģ…lŁ2¼ ÄL>ņ£¦d¦„„ĀĆß9 Ńl6 Ć80vpŹ0Œ%†q`,0Œc €aK 氀’x–Dk) IEND®B`‚fwJÅY§‰‰PNG  IHDRŽÜšsRGB®ĪégAMA± üaIDATx^ķœmPSWĒ’y‚7…T^Åf™å„Óqœ:[Ź‚ØŪvFķtķÖń£_żŠ©3;v?ŲoītÕAœ•„ƒSE?¬”@•b+¾”„ ˆ $$¹{ĪɁI%$€œ_øsŸē¹ēīĶ9ē¹ē<÷œČ$ĮŠD8AH9üåa¬]·–kž1›ĶŲ½{7bbbø°Ūķųśč×HHLą–åĒĄĄ<…BĮ-‹‹p‚ržüylß¾kžyšąbccĒ-€ĶfƒŃhÄęĶ›¹eł”×ėQXXød€œļ‚×óͰŽ[aµXńøļ1&üˆś¼»tézzzšÄō„[W.¢ ) Õ Õ¶ņt%VÆ^ U„ £ęQDDD ¹±E%Ehł”…ä 'G÷£nlČ܀®_»˜œˆ±‘1(Ā0¶»&Ÿļū2™Œ’—ą²ŌzĀ‚ĘƇŻOąÉ~¦‹Ų<œ³0 ™ Ó²ó@j©ŻiĒ‹įĢXǬh»Ł†īūŻččĆØei°Kv¼±ź –‡:R0uä.9†ĶĆHLHDø*Ik“šmõ·X—¼¹æĖEBBčb Ōh“(TÜŠ{#ߏL’!3#3dŽh1+—Æ@©…6‚lįdS“Ęģŵk×øäM”Ś0~.ÉC£Ņš#Ą½›÷ŠŁÕ‰Ņ„ČČĪ@هeHLIDöĘl¤¤„@·F‡œ¼dfe"mcąjĪÖ 5- ’n@łĖ©D||<Ļ1th£ł=ńū¢÷xćĘ āx‚PB{A08uź—<ŌÖÖriv:::$“ÉÄ57ćććRcc#ז'MMM’Ćįąš‡ŗŗ:.…1ŹŹJģŁ³‡knŽ9‚¬¬,®łghheeeŠj=½śšŲ±cXæ~=·,?ŗ»»qąĄ1€ . ““”k”C8AŠšå¾Y, bĮ F8`#€@°‚ (0dBė­\ ©)©ģUŽ7÷;ŠÕŻÅµŁŃh4ČĻĻēš›Åø—Q*”xoė{3Ž F˜_˜¹6;¹›rļ™83>>ަ¦&ø\ōesššwķ"0wüÅō=,/,\›—ĖNP0_ćÕÅŁ³g¹äį’¹_iėŒ7F£Q²Łl\ó@—^Muu5—ÜtvvJżżż\ ĶĶĶŅÄÄ×<ųz (šæ:HłūĀ6>½Ž‰!Ą'Š™a”žY&XXŖü,V Ī]8‡ožž ·øY0P[WĖöś=Nœ83Õgšó͟qėĪ-|õ·ÆpüÄń9wÓĮ:jEŪm\›ķķķxŌżU’¬ĀŻ{w¹uyćt9Ńp„ķwŚ1bAWWśśūųQĮRĒ%¹ŠšŸ®ĶZīWÆ^E}m=JŽ/ĮŚ”éK±}ƜN'—fēāŋSóŗæ;÷ŹĖŹ”oÖĆōŌ„˜Ø“ßo'™III(//GÕ©*|“÷#–~¾ŌŌŌ°¼¼©ÆÆĒ¶mŪ¦äā?Cęg^%ksĶ÷}ŠńrEUĀåįŠ%ź°&z ²›ĶŽ:-–ĪI cóŽ'¹|ł2ö~²—k³sņ'Q²­„œīĪ ·§o'½ Nós3ź.Öa°gQ±QPF)ƒ]»v±“ŠŅŅ‚( ÉS”d‹tč“[ØČĆąŖłļęCI>r™.¹ 2§ŒUf§ĢI’Dä$É$fwJN&ÓōSv±“Ļ4;ł°ō$ µÓ¼ÄDķ“ü™]Aģōėąvŗ8Čę“ĮņŒŒ«éćnŽ-€fIē芟3i§{š½·ī©nä²Ʋ»/םÅĖnøn@AAē掎ö|ö—Ļ˜Éšƒ›r7¹ėˆ¾ųņ lٲŭ¼GĢ#xf~†ŅJ”wOØz9ÖąÓ|ßų=ĘĘĒøęŸÖÖV:tˆÉµēkY!ÓĄĮEʄčķźE’`?ŚnµįMŻ›,H‘ž–ĪŅĻ—£GĪ˜IFŸfū÷ļgņuĆu¤oL‡&Ś3oÜ2Nb@o¼ļcxhgžuź(5"#"ńńŸ>fö`C€ĶeƒJEÅ$¤rܾyūž¼5¬Ī_;YŌ‡’z[ßߏ5 ’q?ŽÉ{‡9ŗ0ēłŠsüņ褬OĮ[ŗ·˜ƒ.ś}O=Ø ‹vĀįä’e¤ż; Hķ%N»Źp·c˜’]Dv9lŗģrŗŲFÓøÓešŽ®ąsN–Aj,“I~z®ĆN¼ł¾”*LÜ8lČå¤Ł«äL¦NJ¦ĘŖČU@–·üR#dĢ&ӆN[ѤL?Õiš¹Čä¼1ūŌjµ; µ“k”Żö=Ÿø©śF= ßõ撰ādv”ķ˜ŗ«ĖŹžžtTaA!”JåĢ`#uóe©é=ō)t :®˜;[;¼ńśšöõęJ߆pĖ<9žt…E…Üź±Ę¢@UW7W®˜–3§Ī #+\1=żān\æ5kÖōYCč\½z•—Œ£ŖŖ Ū߯Ž-[·pÅ“dgecdĄH,\ø+½cÜøqø~ż:·ĢOOOh4n256_8f66ff6d29d1d491*’’’’ŁĄ 256_a51bcff70b036ce8*,’’’’’’’’•256_2b9643ab2fab1e75*-’’’’’’’’0¾256_92423a5049de5fc(’’’’’’’’’’’’cT ž’’’)      !"#$%&'(ž’’’*+,-./Ū123456789:;<=>?@ABCDEFGHIJKLMNž’’’PQRSTUVWXYZ[\]^_`ab°defghijklmnopqrstuvwxyz{|}~€õŽ={ö`Ń¢Exī¹ēøbZęĪ‹Æ¾ś ŽŽŽ\1=żārrr V«±bÅ ®X¾¾¾(//ē–qTVV"::ū÷ļēŠiIIIL&Ćāŋ¹Ņ;„0_Šo‹€VVV¬±YZīĖłœ@`,b@ ä¤d¤ąĶļpėA„dT×Uڵ•öŽvTTW ­­+›––¶KŠ_Ø TŲµI“y>“«"Ą ¢¢¦qć oŌsep”Õj³'m-ęįź“uˆ‹G£¾‘+O‡|U>"žŌ„T„¼‚ų„x~¤+Ņ466"<<œ[’cŅäIČ+Čć •J…’’¬^æõ õü0kÖ,Üŗy »¢v”±™ß€*ą­mo!éd[\l$H€ļx_xyxqeą°īŻušööFDd³s.å`ģø±L;}ś4ÓrÆęāXÜ1Œ ƒ°ß‡””©M-Mxmõk¬^ā׉0 °s°cõ:J%Ō-jÜmøĖ•¾ēć#cŪŗmX¶wnĜę°x‚‡1 @ѝ"ŌÕÕq«“Ū•·QTV„£’<ЦĘ&Ś PßVĆ 3°śiÉiČžO6č¦F¶eåepópƒ‡ƒ ĶöÉŖdŒ’‚‡ššš˜6˜Č;•‡åK—ską°vÅZųņGYYlÆŲ¢¤øq1qČż!ł¹łHMO…NÆCĪń|žł9ņ.åaŅÄI(½UŠØ½Q˜?r>ūlܾ8ųųūf²ŽJŗ_ | S.r„o0Ü7ąŪsß"tE(JƖāÄ©˜2u  ^ćį H`-ėź±ä29\‡»bśÄéų:ķkö Ó ŒvrL.ĒŖU«pößgqžņyȬd¤ ĮPĒ”Š7éq£äZļ·"ė\ĀžĘꑃā;Åht%#öpŌŽ«…*[…ėv0{øöż5Ģ ™ §”N°WŲ³”2ķŁ[mZńIō'°µ¶Es]3ź uČHÉ@Ų¶0öŁ%Ė—ĄĶՍ•Ķį(®*ę–é9™~k׬…śŖļżł=ģŁ·®Ī½L’óŸŻŅŽŽŽŽӇ9>jgÄšĘŅNŚžIpwu‡¬Y†e”˰ž/ėńźŅWįģä 8’”– ;Ž’č}¬ZĻ¢>cN2cī żö(ü`ćjƒįnĆįīęŽņ¼rę< c՞*YłY0Ü6ĄåY#Ą+Ŗ*ĘŪ‡š$ßf_č=ōWČ”„€ę–†EēŻżńįCIß¾ģ<)é'Ņń]Įwä²:’ĖÓNnAFTFŅ’ I $éIĆHŅ“ŌS”CxĒ9ūŲ“=Qj½ka§±ƒÕ+hīiąģē̜9ķł·+·³)ą…k¾"•Õ•ĢIt“w ńN#²ļ05“M.X² Óp'¹–dzŗ$ÓĖN‘“|ä’•€:SĶāzB*A#3.¾ą—¼²ōČéƒFŪ}ųI?Ćī-%٦³|Šó )ōĢO™?aꄙÜ2ž˜ÄĄž>éiŸI?“-Š» em…)i)ų2žKčjtx~ęóę6Œ4 ų“ÉĪĪ–¹Õ• ”Ā—‡K’~ęNåÉßߟ[’”šy‚ä7ĀOŗüżeé\ę9)22’é:NھI"Tjohgھæī“"·GJd¾Éģ¤I=žž¾ÄĖĖ‹—ŒG£ŃHÜźJśéRÄʇÉÉÉŅ7ß|Ć­Ž3vģX^źžņźréŌ©SŅ•ü+R›”M"½­t1ļ"ÓrssY{ś{’Ŗ@ÅŹZVŗ”¾ĮŹ%e%¬^^nžtńŚE¦õJ„’—zOtt“tłņenu„¾”^ڵ{—T]SĶć–ōz=·NUM•’Q¼“`ž)!9«2mŚ4^z¹@‡³ĒŅ!Ą7€…ĪNœ9Ś-†:Q÷Ūɲe˜1o¬­X}[[[¦;99įõÕÆĆĖ× EŠ"¦El‹ĄŁœ³š ōc¶§¶nŻŹ¾›ęŁ3fCÆ3’­³9枃1“Ē 3½ū=ßž‚NéčPyĀä É;#"§N™Ź4Ņ0YgGgŒ?Ž•]œ\0Ś4+ūył±zS¦MĮŌ_Meš¹p>÷<‚ž 2¾W6÷aīxóoāųńćČų"o’īmhīhXÜÄ#įŽą©ņØĄ`¦/GOJ_Ģ¾<)½ü?gNŸ‘6­Ü$}pčI]¬fšYĮć3į|ģžūn ĀŽ-;ła$?Ņį‚Aˆż3öX¼‡“C®‘ĆŅ®jvE8`BwTčŚŲŽŻ;šÆ®>Hæ½ ““”””\±hH+j{čū&L˜®˜–śśz8pĄč÷Š…×Ń£;ķĢ•ĀĀB` ō}GށBńäńŻqóęMTTT ¾‚äēē#,,¬3’ĻĀ oōĘ>.ōó} Ż7ö}}NO kė‡ĒĢwł9ø©Æ0öœŒE¼P °`Ä€@`Į X0ĀŒp#€@`Į X0Ā š_@ćMæ\ĄŒIEND®B`‚o¾ń&ģykf6« dÅ2ĢS¶xū/oc8ؐ€ŸŸÄĢ» .Ą©S§0xüų1ŒŽŽĀ®]»p$šH$HIIĮ,pŠ€¬8‡h»ę*dő—É”OŪ5Õ5:‡ŻakŖoŌ>Öā£Äāw‹Ģf³i|}ś“”%‡‰PNG  IHDR$f8äņsRGB®ĪégAMA± üa'IDATx^ķÜ_PSWš/žŠĄņGE„Š ³BÓµŠÕZŗ»ÓVåiĖźĆŹĢnu:ū°;¾õa»ćÓvpŗ­ī8;„Sa±ü׊ A-„v`–HųDž‰IīŽs8ѐŲøł}2wr'so’›{~÷œsļ—$!Ä#y‹gBˆ¢@ˆ£@ˆ£@ˆ£@ˆ£@ˆ£Ó€Ä%ō#z”••! 0@”8f2š°’~¬Y!Ję¹sēąļļ/JÜ×ŌŌv汫bV‰’g%ā:F£7n%Ž©ÕjDGG#**J”ĢÕŃŃ«ÕŠÄÄDQā¾óżŻuń`”Č3EŪ”Eéē„…¶]˟ėnŌ”IŻÄĀŗŚŚŚ01>ŚŚZT×T£CŪƒŃ€Įč‡ōbM„”.±«÷^/¾ż÷·ņŽā%ļ-¢ķ1ģŠa‘'y²ƒCƒČ|1sĮ]€ļ›¾GčŹP›ėģėļCÖĖYŗ-źōõóń³¬_·Q±Qō Ĥi=÷{Š­ė†źy"""ŠÓÕ„¬ÓVŒŒŽ@oŠ#ļy äės%–|.\ŗ€øøø§¾Ūn‹[T[°zõj¹Ą}P v]»v Ŗt”žŹ™JʰDĄvl¶£‹ē]¦­Ó€Łl†R)/cK+W¬œ°±ĪĪŽN(ü@EE_’™ņ30š‘öó4^¹ƒƒƒ”R`ēö(?[Ī+½——¼-Žx0ż€Ģ™'Ģ0Mššęoßäėr5–F†GœœüŌ÷`Ū ’vź:±mŪ6¹Ą}P v±°}ūv‡•łÉA°onƒ-/nįóóYč ąŌä_&>1† ^±‚‚‚ T(Įv搕!¼¢±e ˜&L BKK ^ųÅ x0ł€'œ„ąhpdd­­­n—X~"ÄåUžÅšó÷ć92< 됐Ą“GhX(ĀĀĆąć惈ČDEG!,$ ±«cŠĢĢLž$–Ŗņ?Ė(āĮØ @ģr¶ 0>>ŽS§N‰Čy¹¹¹ “=(g0pśōi¹æ}ūö!,,LDs¹k€±ĖŁ@ģ£1BˆŪ”@ˆ[².Ąōō4æųĮłłł‰¹Yls°sŲ ÅšČģÜó“ĢSfHN »6jīėė+"ŪØ ąĪtŲ E 5ß~ē¬%K'ŽŸĄšµkDä~Ųyź÷’ņ¾ˆfŻæåˆ['J»wļ²³³±jÕÓw‚Ī;ŒWõŖˆÜ‹¦UƒüĆł"²€k8J¬ņš×ń|†(qĢ0f@jj*6§o%‹ĄĄR(**sīi¾Ļ'WfI­V‹Č9ĶĶĶRooƈę:v옘s?'Ožsó«®®–äSDd±†‡‡„śśz=mrrR:ž¼ˆœÓßß/566ŠČ9† ƒtā£"’¤eß‡%™¾į>ž,o ōōōąĪwPWWĒ/ū”7ŅL×ĮjĮĶ›7140ėżīĪwčźģāĖ-7óC3ŒćF¹Īšč0īģćß_ݤę1! »¢Ń•,ņ£ņĖJ”œ)Ąģ’+,Ļ  ÜÉ(ūWŸ­¹RƒŹŹJ„†„āFŻ <—ųźźė‹ŚÆkQ«g??‹”ŌTŽØÄõšėüZļu_~¹ÕŌÖĢ\ļĘ |Zų).^¹ˆĀ ńYńgØśŖ HJLBėZQu½ —Æ^Ęå_ «« ¾ŗ –&ž¤KŪÅļ^tĶ] ŽGʆ¼õ‡·ęģĻvĒŲQ™£ŖŖ ‡āóģ- žV€ü#ł(=]Š×v憫__å-€·¾’ž!ŽłÓ;xļĻļ!*< 1Q1ČśuŖ®Tń*²“ŅāRžļ1 łĒ{Ų&[·nŃ,¹Y…¤„„ń˜½oĪž>?v­9»h%22R”Ģ’›uČĖĖćóŻķŻ(»\† k7 &&~ ?*Bt\4^ŚõŹĻ•ćąļņ„ݰÆg½>ļ?ęüTŲ»wƈl»uėT* …(!‹166†öövžģmaĻZ­{öģįń°~źF5vżrmąæĻ¦M›DÉ\’UĀŊ‹HS„į•—_·×Ģń¾øø˜×%Ęn ĄĖŪ ŽŽŽ‹šĒnĪģäo<0:€ŽĮ^č{õ –ßP@£ŃąŻüw”ڬº¤uØ8_Įoįdć“ĀO06>«ÄnÆr[Ÿ›MSś)ł†t„ß}ę`] M Pȏ‘ĮhŚ4X»~-¦å»žŻh0"9>·o£Iӄ† ””KVłdė3?>±ė裣[ÆŃäüÄ®d‰ŌÖk?NÓėõˆ_/¢łĶ·ß±ÉĒ×éééh»ŪĘoT²‰µ–Ā’Ė  Ü “ŗ;»Ed›+åք4eZžA7gÉņxr°YŻ,Y¦-"²ĶŁA@“Ń$ž³PŗTyI²X,sö}»-DFDbMüņĪLII2€N¹yŗŌ“Txūø¦z²nsīļs‘’˜‚’ń1“wµāc?EII oś»+6žpäČĶbg"JKKłm¤Ībż»œœ„‡‡‹’YGuŪ?µ|ųš!8 "ņæÄ~ ¹µˆŲŲXQā˜ÜjĄŽ;””$JœSs½;wķäót3!Œŗ„x0J„x0J„x0J„x0J„x,ąæ¼fłü¶Fš‰IEND®B`‚F,€¢ā"-’C¾¬)ŖBŽū<)•GĻČŹŹŅāćće­eYp…ŽÕ©t6­ZkwæWµ«uõuų¬eĄ7 ń§¼¼<Œ¦ø [K«³™ĪŸ?Ń$®°=Ā,0åää`ä‰/ J„3’£=p""" *2 3²”č0 ń»ŁłŻøqĆēνĮ`€'N`šōéSø~ż:lŲ°GĻōæł¾rėÖ-Ųæ?Žųāwó9ęæŅ-w )!AŒ !AlQ¦§ÓNCŅĪ$Ģ––ŗW ™ßgBhčTķJż*vķžū4Š.müpę ĆOŁ—³±3˜łG’`?¤’=b¢cpdRŚ×i°óO;1{±ż|sś­į@GG”””@dd$Žųרq>Kł āććqÄM¦x›ˊ…š|¦P+Č ļN‰PNG  IHDRŽa2sRGB®ĪégAMA± üaPIDATx^ķœoP”ĒĒæx'bZ_D;ɌÓyc:M5­ķą„Ń©ķdĘįb”vbj“±P$*IKcJP=@nčP‚oj2Č)9(pąŃŌĢŲ 8 źżæć¶» !ō€r·ŸgæægŸ{žŪ½żŻīó{īĄ/YĘ·Ą@ šc„üį?F8Ą@ šc4 XŖ.ŵÖk āߦ»«9ĖAÄ÷"øezŅN¤ĮtĻ„€€nń†ŹŹĖøš™’ž!ō’ŅūMMFנÕϯp5{ņróŠi蜗ž3 š‹ē~ņ·xę „RI, W¾Ļ… ˆŃhäjfŽ9B<WŽeĒŽ¼ōķœ={–X­V®ü:Šx黑žžNÜn7WŽEÆ×“śśz®¼‹X> ćhŌ5℘—ąp8øõ!Ā>ˆĆī€ös-öĒīĒõė×ńĀ^œĮdŻøÜ.œWóσūp©ę’tĻ€x2?ČÄėæ…<ĘkLdŃ€sŲ‰;½wøBå”8~ü8***¤¼*|z =8WpƞaéƒG׏ČRfᣲ ĢU¢B]ųCńP©TŲŗu«tœé n§[zM«Ć ӀI*/%¬6+źZźšüϟē–ÅćüłóŲ½{7jjjšVŽ/z§NŸBrbņ”ß,‚^Üö"TŁ*®ęB“Łj†ŗDøƒqŃTXXˆĶæÜ<ķĄeŃ±Ó“ JēķN¤§§KŒe‡Ē§ŸzO®{=½=pÓŌŻ×õk×cٲeX¾‰G„c-v‹“eōŪś‘°?Az„c €ļXBÜ6ŽĘś5ė¹Z\šk›—MĻžųY$Ę&āėk_ćļĢĖo_aeŲJ axx˜[¼‹ÕnEĪ98väV­^u‘‘["¼<˜×˜™)ƀšĖ“č[øņ:%%% į`Č2„¤”$(³”’Öןį”9±aĆI³óŪäēćō™ÓØ×Ō£äć¤OAFFŅž’†M ._¾ S· eź2N=ŒņsåˆüM$"""Š×ևŅ–"žÕų‘×\ *++Ń¢m‘¼š=rĖ–v›²0ŁČĄy@+†Ÿ•†«ŗ«Sóæ›Ń~³Æģx…[ęĘʍ±ķWŪ ÷Čq‡ÜĮZšśi  )‚¦š¾O“ƒ&Ķ5 >żųS¬X±‚ ōōõĄŲe„¦Yƒg~š >©ü'2N@Ū¤EōÆ£y-ß`ß¾}#a[šŁč`]Ā2‹Œ²qČõ(“^CmŖ««ČvN$;+Ž:0å¾ŁŠŚŚŠģģl¬Y³fä¼ģŗŲW7ąŗ 0;ĢČÉĢĮڧֲźS’ŸŸ={ö@.—s ‡9€ÉPo%…4¼Ļœ9óHŠl1“ØØ(RTTDØs •—*ÉŃ£G%ĶņMĆM²k÷.©n‡¾ƒ¬ūį:©\TRD223Hn^.y÷Oļ‡ÓAŗĢ]äķæ¾-ķĻ+Ī#żżżRłĖ’|IŠ‹‹„ņBĀĀ€½½½#ķ9ģ–¶Ó夤¤GĀ€ƒƒ¤0³«¹ĆĀ€ģžatŽ™2ė£ÉaĄ»¦»$fg Iżs*©¹RCÆ*HUiiljä5|:cœ²]¾-ĻL}/•Šå+WߝŃ0ąŲłXwnŗT$)”C)ä‹Ö/$ŪdņņņˆĶfćź!S:€łbŖēŲŚĶę±L×ķ5mT»Ż>V—½ŁŃņhńoŲétJ[—Ó5fg[—Ė%•’’õ9ź6IFV鿦—[ę†7ž`6ÖwģY™µóäėõ˜˜ S9Ö>U’Ø"µMµÜ27fūY’Ü‚\ņFü¤īJq;^Ļt`Ńļ°)ohhčX œØé“I&“Õ]!™šŽ?nü“98xdķ4fgŪ„ųd[ M÷ÄįOpĖāĮ–lé&õ-³vßī‚Gaķł³Hlžéfn™_drŽÜū&Ņž˜†Æ¾ł ;ģDõ„jXlļMfŃ€`f–Ė—C.›“n,ĀĀĀxiįĒkŠ× :© !Ųū‡½Šit|ļD„|”ŠšPDż" ŖÓ*ÄÄÅŒĶŽĒ³ ?*((@CCƒßüФ££jµ«WÆę–éINNĘąą WŽåÖ­[R”d6(•J466śķ“Z-nÜøĮÕģa©öööyY 11›6māļ!žT šcÄ@ šc„üį?F8Ą@ šc„üąæ;ŒÖĮÆSIEND®B`‚Īń4¦DŚ3†;‰PNG  IHDR ż©¦äsRGB®ĪégAMA± üaŽIDATx^ķŻ[LTGš?(jŠDM­>T£>H+iŠ1&|0mIšT£)rWløbSŒb‘PŁE \TTVXj1¤VE4Õ€ˆŌ T@#xį¶»ÓsĘAveµė*œļG&;ß̜=ø—ļœ9sˆ6LBˆ"يGBˆQ DĮ(¢`”Q0J„(%BŒ! F €£@ˆ‚YżNĄŸl "Rūłö8¤:$¢±Õߨ‡:A [[Ėę鮁.-ĄōO¦‹ÓŹĖŹqBs666¢E,]€½æģ‘y®V]EzF:ll-’Z­\¾””"² 9X“ŸŸŸØ)———Ø™ēŅ„K¬””AD–£ÕjŁ“'ODōf¹¹¹¬§§GDŹ$ję+))a"²¬ąą`Q{{zž=ü÷”ˆF¢)!XwW7vķß//Ń2%B& ݊’(FB\üšĒÜĻꊞ‘>Аw,OŌų””””ˆˆˆą„­½ IÉIčėļćżGŽįĶwšy“*ƒ±I±CŪåää “ååå”»»aaa¼?#;ƒļg¼ŗ}ļ6jjDōį’ē¼ØcĪž9Ė?£Ö ®ļ“ŽAxx8¦N u²N_;‰ŽŃ>xŠéuøP~ADĄóžēppp@ZZ/³fĪ‚öø§OęYM+Ķ_q ćļw’Ž%…%ˆŪĒ%ŽHLLD@`Ź’.ēĻ'?ٹ2“?hNJ+ų6h}ŲŹūǽ^Ņ¢R8į,Z>ŒōōtÄģ‰A݃:ģ ۃ epTsŅļO>Ģ^t¼`/z_0OOOŽÖ?ŠĻ<< #žP>Ģ=Ó.‰PNG  IHDR%­d7WsRGB®ĪégAMA± üa ęIDATx^ķŪ PWš’² H‚ 7¢ĮRWŻ“J£.!*kV1ŗƒYµjU0ĻUÆ2+"š ‚1Ę“¢ &x%D.AŽÅą 0\"‚8Üo§›'2aPa™÷ėzeßkŗfęėīבĆ0JI…žĖ0Œb€a”+ £ÄX`%Ę Ć(1VF‰±Ą0JŒ†Qb¬0Œc€a”˜B§ēåęaŁŅe *l6rO ˆÄü…óiF>[<üS2T%KxGó$$'ŠHŚĪļDā‚ƒ„…†‡«‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ”¢£¤„¦§Ø©Ŗž’’’¬­®Æž’’’±²Ō“µ¶·ø¹ŗ»¼½¾æĄĮĀĆÄÅĘĒČÉŹĖĢĶĪĻŠŃŅÓž’’’ÕÖ×ŲŁŚž’’’ÜŽßąįāćäåęēčéźėģķīļšńņóōõö÷ųłśūüżž’©Ø ŌifpSkSCZv¤ž ÄуG”!Š ™¾%h ćAĶō1®(Jzz: ¢Óńńń$<<œFņsss#eee4ź{ęęęt­«mŪ¶‘ÜÜ\ ~FFFt­«#Gސ»wļŅØļ;–“µµŃØļ±[†Qb¬0ĢÖÜҌ‚¢Ł}Ǿ=F³Æ°Ą0CT]mvmŪ…€°@G’x֞ļlP€śśz¬_æžFŅĪ9‡×o€H–—ĢĢĢ`jjŹ7Ž_°,ĘXtäø¶yóf¾ļ·öķŪ'µ]Š·A“§]ll,BĪ„ µ­iIiX¶f›ł¾Ąļį¹Ó“_J¢¢qąŌ)Nšł`œævžFŅ„"!.ŽŗH£Į'/'7ÆŻ¤ŃĄłł»Ÿ1}ętLžćdų{łcŽóh“A]>~ˆźźj½R_Wjõjœ»v¤­½X[[#žb<Š‹‹ WWlń܂Gį‹_ 44”ļ;tčæ}gMĶMxōųbbbųmø‹›ß·æq„ˆrDHĪIFcc#¬'Z£UŌŠØŸ¢PXRˆÄD|½ėk~Ū”BX*ÄÕÓWįåīE3«“² ‰ HĻHĒ™£gąd儚ŗÜIŗƒųųx…B¼,?ž ©±ż=äśR³Sé^o”É(DGGćiõSšé?ā1’Ņ“ąīįŽų»ńø’q+>ZŚ#č] ź ¦ŖFפed”…“@ē™’2“ųœŁT3\M¼ŹÆ;Īt„ĒghkkćcUÕ×?źā±ØØØH=j¹pįüƒżńüÅs<*}„“Ü4˜ ̐’m 8†€D_ˆ†ĒVØŖõĻć4EÉŒĻ„Ūr7Ø©É~śSõ³jųlšį‹wdT$*Ė*Ń<ŖĮ'ƒq/ó~-ųaaaج­Ä²;°4²Äķ{·±’Ÿū!‰°iĆ&ˆˆčŽKWG†c !LŅL’ȐĻO=q9ö2¼×yĆē°¬U­io÷u0eLפÕēÕĆĢŚ Ÿ¬’'ĀOš¹Ø3Q®?ĘĘĘ=z4Ģ­Ķ”>L’Rėæ«ĻoÓ®ŠŒŠźZ%õ&éńW‰÷a4ÅÜ6ąų÷Ēł>cKc8ø8 *& Ól§õßsZEh^4 Ō¼D0šs4ŅSŅ1Ęv –’u9\¹`܌qP×PĒjĻÕštóćžå’E½Qņž>ĄĮŁ×lÄŹķ+±dÉųųłąĄEÅßŗ¼4ĶtĪžē,śVKK Bö‡Ą};¼¶zaĒ?v`ņōÉo<é½Ō£ņ^$,BVvVĒµÆ¾ö?Z\^,y…’ɲó|•]ēvA—č¶5@Eu ó ±Ņu%ßø3ö¦u›šUčW0Š5@åÓJččp£ ²µ“¶ öy-ŚÕÖ×¢*³ ź­źųęų7ЦøKq(üo!ŖjŖų¢2{Ęl”ä–Ą`¤ż©‘šš ---ɇ»ĶéNS[rJsąÜą d‘Gss3®\¹B#itM¶’ģĢųĆ žźć y{{”——ĆĖŪ M M‹Å°2“ā'č SŃÄ/Äšż—/Ż0ÅŪM”źŒ»ģīµdggcÖ¬Y4’MEOF’E^ܱe`źÅõŲ³g„…BÄĘÅbŹÄ)Ż^5w§GWÜå1·cīĖŚ—ŪļkÉ8łüż –.XŠĖ—/ómŽ’yˆ»‡UŸ­BQZ捄±%?6šņĆŪy P&Żó€ė*W~bö_fwĻ÷/Ī^¦Õ|ąOŽ<ī÷&ė÷Ł›öŗß=wådbh‚†¦š‘¬ćrķMWKāb ųń–Ó§”9I…÷ 1cÖ ž=xßī}č™ė”,· ęFęo5šš ©ӧ „­…ÅZL÷Ö7d½®½ń3,Qž¤­FÜYL>²ŽĖ5īVōš”ƈˆˆ@ų…pģŻŗ—æ"č~:‚¼i&ą³ŚgD__Ÿ˜™™ńmźļ§GWGņBü‚nAH~V> Ų@žT?!¦Ę¦ŪfęfvĢ ’ÜG’[·nńėŻŁ½{7111éųłĒÉYŒųļõ'•t+BźžÕļ¼ÉóŖē¤TTJ¶lŁB{Ę@ĶŒ»G¾<ń%‘\ŃLļ¼ĶL@a‰Ģł`±²“"nīn$%+…ŌŌŌ§Nü{³Ņ{%ńóó#99Är¬%¹xó"I¹ŸBLMM‰‰© ‘\aÖÖVŗ··÷63¹ĻąžÕ{ˆØXD3½Óә€ $2,’L°™@ĀƉøAL{ŚeddĄĄ@½¢Šæü§˜˜ˆuėÖŃL’ā^jzf:2Ņ2h¦¶¶6œ9Aówš43x%$$ ¤¤...4#wwwž‰ˆ””!ĶH«“,¾»}ń±ćǰ›eG³=gaaĮŌ˲}ūvžų66643øqcJÜą¢,ü-€­­-ĶH+*.Ā×~Äj×ÕüUJo7łłł=cān…ļ9Œ*Ķ*,œøö‹ģłćfffāöķŪ]«źAĄž §«Ē?2ģÜø«ŖŹŠÅ[#$Ėē?‡ŃĄŽo 5śŗśp_ģ.ח_šĆ5±ĆoÖŗ­ELj Ö~ŗÕU]„æ¤T€«¢ę°··—jvvvü}/#mä»#aimI#FƵ†Co¤ˆ`c256_5fb06c1cb962dd5c*’’’’’’’’’’’’ˆ¤256_c7f3f2660e1fed85*’’’’’’’’’’’’³256_3945eeac5447da46*’’’’’’’’’’’’Ż 256_c9275893a1292c14*51’’’’3ŒµĢ6b G彉PNG  IHDREM²—sRGB®ĪégAMA± üa6IDATx^ķœ[PSWĒ’ X«4Š€Č]¼0XzƵµĆˆSĒĖųņuō±>ōŻēv:c‡ŽS”qZ Œƒ \ƒ0Ümł1n!å"—čG$œļģ !‰‘I"’ż;“Łkķsö9‡Ć9kƵo~‚8ŽOĀ gÅ1>>„R ???–³ņŚļܱį›ĆYŠPßż“žiž'tS(vķŽÅ“÷7œGGGbbbÄrc4ŃÜ܌°ąįƇHKKcšē©¬¬Ä±cǘö~šg)‡Ć±bhhˆzŖntÆuŠh5ŠétC_o4 :U0 čķėÅųÄ8FFGčńÓÓÓP÷ØŁ™–7Üp86˜fMhhhĄļw~‡Ń`„¬Bӌ ’ü÷¢½³uuu•ɐ—Ÿ‡Ve+šäMh{چņ²r”—@łDÉζ¼į!gEżK6¶&l„2©/^¼HC€īŽnÄĒÄÓ|kHÄÄD–čõzœ?&q+.,F||<‡!łD‚ŁŁY  #"<6nĄŚ×Ņv†„ų¬ĄĄąńņåK„…„Ńó×®]CTTÓ2©›Äw’łŽi„ēC§““”I‚ŠŽŽ.LMMQynnަ¶ˆ“ —Ė™f¦ŗŗšIŽ”¢¢‚I‹ńÖ½p€³"(++ĆńćĒ©¬R©ŠÕՅիWSŻ¢a€D"AJJ Ėņóó±iÓ&¦yŃH!33“i ńVƒ$7œµX xĖšF@LJįg?’ņ3vnßÉ4ǜį±ü1ŠŠ‹š¼ć9žÕž‹ĘśFäŽÉEĮŸجØDcc#FFFš¼ó9+ÅyŸšĄĒ™˜˜ żŁÄYYYL³ĻÕ«W‘œœĢ4óŲūS§NaP;ˆźGՈ ‹ÄšŠ0śūń©ōS¦ ˜ę ’Ÿ»wļĘÓ¶§ _’‹ūśõk 66–å˜!Ćz÷ķŪĒ“Ÿ'Ož@*•2 š÷÷§ć YŽ{ąĄĒ©­­Å‘#G˜ćĉP«ŌˆŪĒrr’žżŻW–xuxtw h]F‡G±&h ’“Ø!Ųæo?4ƒ:N£d#H“ē_pW! ··»v½ßI4ŽęqŻc:|ˆiīƒ‡»8śųŠŌōTZ“ł ŅŅÓ°yĖfśń¶DlAFz¤{¤Kśų}™™Ł&¹īų8¶qÆCBB˜fŸõė×cļŽ½LŖ««N½u'&“‰†aaa,Ē7šTÆ7>Ž­ą,O}šiŽį8Ę;U%‡ĆY–pĄįų,Ą’˜lĘN)O£2IEND®B`‚ų ßü]^©’?Vų ßü]U—Gø–Hd“m__¬’ūz,˜æž'üi§4„»`eĮ=E±c‹¤”$8NvÄ{ćߣ=ưĄ0JĄcęĶķ:Xįƒ€—.]‚««+Ķ0o’’’ĀߏōÅ 7ųŖÆ’śIRņš;w.?~L#iÜ ąœ9s`eeE3ƒŪĢ™3QQQA#iÜ 7†4iŅ$šé[ü|™žö–B 7¹ćäɓ4bzŹŁŁ&L ‘|"##q’ž}õ= x{{ÓH÷‡UÜӟ’ܗ+Z²$''ćśõė4źܱ‡d`F±ŲĆ(1VF‰±Ą0JŒ†Qb¬0Œc€a”š?\6Œ żŠH(IEND®B`‚’ؚ/ż4’üOš¢Š?±4_śi’ų ŸįGö&‹’@?’“ü~ņ`·źoń}ĖĻż[4{ōäļ·¦M›6}ML•ŠŠŠQĖ€}½}L Ń»‘—?~ltŸÆ—ģģģQĖ€W®^a1±1,2*’U\¬`»wģf±‰±¢wb 4śz¼©]|ÖżŒeČѻٺu«Ń}öéūX~Q>Ū³‹Żk¹'Ffj ś ą}0v€tĄ¤S}^äŌ`].Ņé ļ4T7H_n1f¼­Ü.µĶ°ńĆū¬É÷HS$–˜»Ådu ›‰PNG  IHDR'ଖ\sRGB®ĪégAMA± üa±IDATx^ķŻ L”÷šÆ¼36†@x+­L+ó%V%jŗÄ&mZ±3̤ŗtŌŲAEø›R a`Qģg4įL/ž`bĮb+  ©JP –+²aŅ€aĢćżæ{Ž_Bo pģx9ī÷1Ę’÷’<÷@ūńü÷ÜĆ”ʘI2£c&ˆ c&Œ c&Œ c&Œ›€l”Ņ’Rß(¦¤?{ÄŠ£4¶£=ŠöŽvJĘåYĒ3œ:} –4cĤĄŲO) 100@I2™ŒF/–˜˜H#擗—'z{{)7^0fĀø°9ćaŻC<ķxJiDėÓV1CćĄę„†ļø?MM(ŗR„šź@õD…øØ8i©J{2CāĄęa&!‹Ą•‚+ššņ€ā²®®®Ø©­AŌž(,X°€öd†ÄƘ sēĪ”­­Ņh<ĄÅ‹annN3ś Įڵk)­®® …‚P\RŒÕĖV£ąZV’z5^zł%”^)…×R/ųłłĮÕŕöœ}łłłØÆÆ×łś,õYŠ-Ū¶P2"R`¦%%%…FcėU€‚¼Ml*ÆÜ.¹-Ś;ŚÅ7e߈Ź•¢ū?ŻByU)*«*E”²öšĘząŲ±c42.¼`“°!€FÓcż›ėįģčŒ æŻ€€U°ū™‚ß F€Ž ~öb†Ę€MЧ›'Ų|Ā€1ĘM@”šš ¹\Ni“ņņrRҟ——öģŁCil'OžÄ“'O(—žždffĀĀbäR`)ļŻ»—’ńą`‚&*LĘZx Ą˜ ćĄ˜ ćĄ˜ ćĄ˜ ›Ö&ą½oļa`p€ŅÜāéé wwwJŗZš[ŠŅŚBIÓy챘›™ćµ5ÆMśzynŽDMĄźŚjōv÷Rҟż/ķńźāW)Ī“é°ÉIÉŲńĒ43·H×”Ō?Ŗ‘[‹×^×V®Š P„DŽ㠒7Œe¾Ė“Ē1”   lÜø‘’®źźjœ?ž’ęsŽ”æ„ąPĢ!šŸ>Ēī{އ·‚ŽBЦ Ø»ŌŲ“yņ/äćƈŃ­ī†ÓĻ ¼”„Æ»/Ž~÷mz”®Ė—/C„Ré\›>žŠŠ Rb†pēĪųūūS­¶¶gΜ”4¬ün9ÜŻąėėK3/¶}ūv¬Y³†Ņ‹IOēŠo+|$¾>ŗĒĶĖĖCpp0,--iFC*ÓᛀCƒC"jw”ø{÷®8uę”ųNõ8’xDTUU‰ģæg‹Ę6 ™\&ä1r‘“—#š~hI IōhĆÓ« 8 DĀ‘ Ó§ Ø)Œ"N'Jn–ˆÆo-Ė‹OS>WÆ_………ā“ĆŸˆÆn~%Õ?¢GŒ¦oĶ¼±š€E…E¢½½Ņų&Ū”¾ŸJKKE|R¼P5ØhvXnn®čėė£4lꚀš$“ĆŁŁ!æ ļ+¾ˆ•ĒĀÅÅĮ›ƒįķå­]ļĖÉņN<\=šńīéĮ³Ģšó÷C놿;­…¹bÄ`‰ļü&²8¢’†Ę,÷[Ž}{ö!p] –¼²„Įę…> ¹£Yū|0$éūI:ū”EĖPVQ†“Ģ4tvuŅÖŃf® łćīęø,rŃĪYYZió"—EšOÄ NŽNp“w„Ģ-Ķįąä Żo.ŲņęøyøQ2,‡…šöö†µµ5ģ~a;{;DģŒĄā_-†““l¬męĒo”a#4Kņ];vQ0<©ßž~8vži'2?ĖDnN.4gå“uÄĢ9©‰if6s_®©Ž“™ų?^hæ ‰ X°׊ÆŃģˆi½0<<\{Š?­X±aaa”tegg£±±‘’žV®\‰mŪ¶QŅuśōiƒß£³³YYY°²»ÓĖfŸtƒ[[[Jś“®ņŒ§45ŅełŅ᧦õ½Œ±¹—Œ™0.Œ™0.Œ™0.Œ™,ąæc¶E܏IEND®B`‚Xż ¹kśę(¶ü5ė4ž&žŠž >ż,žĮ<­Ķf-·[DĖŪūæ÷Čæƒœøå"æ?ņ#ķ'KŽPpŖ€Ign"z7cŻŠŪŪĖB~ aY©Yģéó§¢õSŸ½āĄ¤I“`ggĒ‹?@ABCDEFGHIJKLMNOPQž’’’STUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxž’’’z{|}~€?÷Īaīļžļ½’;LBˆ"YŹ ! D €£@ˆ‚Q DĮ(¢`”Q0J„(%BŒ! F €£@ˆ‚Q DĮ(¢`”Q0J„(%BŒ! Öf~(59¹ł¹ 0j9vxtࣰ²²’#껞qZUUUr¤iØlUčėŪNNNrÄ|wīÜAJr Fƒi–––čŁ£'ŗxt‘#ͧĶ$€Q#G!š™@ØT*9BšŪ®ķ»p*ž\\\䈳^ yš4pÓøÉ‘¦qśŌi¼ž6ņø1ßį’ĘŽ½{1ą‘r¤iäåęĮY팄įKåH3ā  -šóóc………r“„Įƒ³‚‚¹Ö0³fĶb©©©r­é„‡‡³ųųx¹Ö0111lėÖ­r­éüüóĻlٲer­yŃ9BŒ!ķŒ”Ģ€L]¦\«%Bډ C.$`ƇŠē‰>r“n”i Žē}lY»ŻśuƒU~ż®Ō“‹PX\ˆąłĮčŁ³§©„¼‚ÜŪ¹¢żdĀÉm½{÷ʉ3'°yßfųśłÖhćåÖ­[4hŠīaž+ó1śo£”/׋eÅ}‡!OA^^NŸ9ż»y'Lœ€¤+I3nLų¼°yøS|G\RŠˆŽ0Å·ĒlĖåęĢ™ƒM{6ÕøŌ9jŌ(”••!ęPLåńņjč«bŪ£Ų“±Xµx•\k½āŽĒ!ž›x¹Ö2n?ˆžżūĆ®›¢¢£0~ŅxX[[Ė­uk ĄEķƒŽ€ %%E”Ī:ć£õ‰ ×ė!/<õŌS¦¶žūV,^‰qžĢy¤\NŲ½öü»łČĢĢ„ŚQŹņJ8ßr«ŖŽ(Æf]Erj2ŖŅŖŠć”>|øi>^öĒģ‡o/_üņ Ø'''cĮ« ą×ŪO\Gßšī”žRjzž²Šeˆųw²ó³qåź¼üŹōeāµ²X®jÆi€GG›ęćå“5ŸĄŁÉY<·=1f±cß,Y½DŽ“^žŽžųźģWČÉĻ‘#Ķ£²Ŗ’/`hĄPģ?“;ĻķÄāÅpļänÖ8v‘ų^ÕXi„ lmmEłGÄ?u) 9¹9()+ƒ-īµ½Œį?v*;Q/Ļ-‡………©½›G7Q/¼[k½5<Ż=‘p>wKļBU؂›ŠKŚ@˲j,—¾|Ž{ė’”œ„ŒÄ ¼0ńTV`MÜDƍ6=_{S‹Ų­±°WŁ‹„sl÷1¼øčEÜ.¼ w;lĖmĮ|“z­HR÷ęㄾY¾­‰<‰i榉÷ŲŚłt÷}¦=n\æŃlƒŌŅ.§įćM#ś½h,m96īŁˆĮƒaeiž­v‘ųØ²ŹŹJ¹ö+W'Wdh3 ×ꑐ€ŠŠPQ,\ 60Wµ«xžŽ¶ŗ{OyE¹ųĖ7Ź»Īw1dģĉGIQ‰Ųč45¢]„UįĢ™3¦åņ²nŻ:ŃĘis“XżĮj¼“č%tzØ222ŠÓ½§Üś+ßA¾HMJ{ 遐gCw4Ŗ¬«é{eū‹-bcck¼¤ŅŽš$››š‹æXZ“Ægæ'ūįĖų/Å^¹)]L½ˆå+—cĻĘ=P[©ńįš1vņXŲXŪČĻ0ŸY»ˆe8ņõ‘&£µIM­Ž@jSn[Žr•“ŃŽ”*ü䧅ćFö ‘īxށęĪ+āŅžųŸkpõĘUxyzĮŻÅŅ”#M„IS$mąŅFĒĻŖ–ß.G>=D0VE7ŽAķ –ÓĮ³¼¼¼LĖåīz:uņTj8Ö’g=¾Oų^|Ö¼Gįņ  XćµÜŻŻåG͇J5f(šµk×°råJ¹ö{:½Śé8@4ĀĖ/æÜØ”Ą—k̹£34©X0ł‹×Ū¶mĆŃ£GåZķ Š °bł Œ9ZģPžb8P=•””ˆ‘`-Q š‡#«ŠŖŲœgē°ĖI—åcŗ›>e:ĖĖĖc'3˜ōe[“öšģõ^g‰i‰¢~)ķóöńf•ŅÄ%„%1ićbRĻ‚±ÄÄD¶čŻE,ōżP¶łóĶ̰?ĖĪĪfĒNcóęĶóüÖŚUkYŠä ńZ÷šĒ]:w‘kÕųk÷Š FČt:«’¦ļN}Ē¢>Šbģ,>÷Ż{w³ČČHy®–ĮG^æ~½Ö’O}ĖŌ©Sė hĢ7²°·Ć˜.['G†<|ųp­ėPß²k×®züś‹ÆYXD“vrÄ<|$ą›o¾Yė:Ü_¢Ž‹bĆ cßžō­<ēsqq‘Õͬ>–ƒƒ\]][¤Ōµ×)r,B”ŗY7³žž. ßĆ?ņä#pR;!Ż3EEE¦¶+iWpåŪ+čā^}ó…O7©Ó`!UŽŻ½Å^·ø“Xœ¹ē‚¦įȎ#˜4bœģŖ÷*Ž]½k,——̬L\śīŽĒGč;”ČŹ¬^§Ģ›™ā-r}$¦Ļ˜nzž¤1“½$·‹oW÷®óŒśŽč‹ükł(Ź.Bņµdt°;ņóóMóńĀoŖiźU~‹ßPŪ’§¾åĻŽė­Ü¬ ŹPįܹs>¦V«Õµ®C}‹£££¼¤ŗ„§”æoq>Ø”ģģģj]‡ūĖ’š%Ųńń„‡bŚ„iČŗ‘e:\m(«‰üøUŪøq#¤½m­7ٕہ3œN8üQßG}1oö<8Ś;Ā-ß gSΚŚ/%"śh<ąń€˜ŸŸ‡tØĶĻčs9·sPe¬ĀŲŃcÅŁ’‡~ް±“Į3O<ƒ’Ņų?ī‚ā¤§¦›–ĖKzF:Œ®F0 †³?żśšé·Ņį7ĄžżżŃŁ£3vīŲ)āį«Ā8&P¬§”Ā€ĒļŃNšŗ÷ė.?”Č+ČĆÅóMĖć…Æ7æ¤iog/Ö»©mٲE\Ŗä_ֆЉ‰A@@4šźó(µ)w+G܉8<=ņéoT'Nœ€··7ŗvķ*GĢĒÆ“čõzųłłÉ‘ßćŻņĆ{cö“ŁpqmŲMR¹¹¹z™āšźĻšĆΐæ‡@ćØĮ¶O·įĀ… °w±‡G'±ÓŗGź-béŅzÜ\TŻhżčf –×\7¬ZĶP„±¤‰PNG  IHDR˜0ķ³¢sRGB®ĪégAMA± üaÅIDATx^ķšįuƒ …±ć4ż§«¤#čMĒHFhWŃ5ėX.ŌR“hó“˜ūåp$Š€ļ\O0ė4Š!ģ‘(0" FD”Ąˆ(…#¢P`D ŒˆBQ(0" FD”Ąˆ(É ¬x*T–ew`ƒTHīk ųŽ?IÉœ"‰(…#¢P`d2Ķ{£²§Ģž‡A~‚¬eƒęÜØźP)uÖł¶‰ź=‰¢z®T±+T¹+UżQŪ³æ³Ya“a¤ūéō~²%¾ƒkøĒQ<¬·ajŠ#8xM§~[ąōz2Ļ„vŹx¬ņ„“W"Ń7%Ŕ.‡ŹāÜńķh’]ØŪŗ+÷eWJ{ę;~=µž­iŗ%چŠģ‚ēõ‰ķĆzVšÉć•Ķw¹Ķ]0F“"ūA®gJ?ndŪ°C¾Ļ»\å&?Dl6=EŅ~]Ē)ĢĶ mõč)r‹\㬽޳ŗśj“æ°Ygo¼ ékņzŠ41GŸüü³-Isōć/«$HõZ™¾kĻ·dv3.Žl:˜fpū)ø÷”²8ļÜč9|śå”rKŃļė­ŅTbļYĻJ3™bŒPYcčųĀåżø ~’% Š‰w nŻ6’?ˆĘˆķĆzVšÉć¢lČó8įz£„±ÆÜI_æ] übū°ž•fū`ĪĖų©/Øą[£åœ0]=}†źFņ+Ś‘āx°ĖK6ŽŲ>lV`[f `š””Ūn‘ ZXJ{j³lSdÅģ nv'ČŅ6Ą×Ų:ĆrŽŽÕ̹Ų>Ѓ‘_° <CXX7‹…#Ń`£Ūx­Öžˆ€Sd‚üō·×Ę Ą$%pŠ$¢$éĮˆY„²¹’Mr#iĮ)mžžž łż9Ł_Sn¢q8”KĻS'((F£‘Fc³Łlp¹FŸ œ”]͚„\ę?ole`²³ £a’€a4Œ]` c €a4Œ%†Ń0–F³€Ÿ«zZķāv1õIEND®B`‚’ŪC’ˆBQ(0" FD”Ąˆ(…#¢P`D„>Ž““œŗ—_IEND®B`‚’Ą&•HSŌæ¢Ų†5䈳šćf ©÷Å>ūü3öéŽO™¾B/GĶ׊›ņrņŲīĻv³™³f²·^{‹is“rKҤiašBLŸ;]Ž“Nünü˜ń˜†źiĢ Ņ8|0–V«—¤jöģŁ8ž|£®$Ō‡N§Ć¾}ū0lŲ09b¾żū÷#,,¬Ī+~„aŹ”)X½zµi>m&”””Ō:ܗ4/~mżžĖMęāw6ņ[W›æŽß˜†ŃhDii©\kZüŅoKüŽe›I„æ DĮ(¢`”Q0J„(%BŒ! F €£@ˆ‚Q DĮ(¢`”Q0J„(%BŒ! F €£@ˆ‚Q D±€’Fų;&uAIEND®B`‚?ū.Š( Š+Ē—÷Z_µżRĘA՞™s<T6×H™”ąšyƒ@TW.ž֙Ä/r3’¦&°16!V©T022bąĒų˜_†_–Ża›Å†ŁāąÖ“ĆWŚlļƒ{ڔꀻwļWXq”"v‚ĘpAĢV3ĄŁ³g»phń{ÕÕÕ#ėbÖAmu-ČKåĀn¶²R ;vģYlHś?)tuuĮźˆÕkłK@7mŚ÷īŻń&1\+–YØŚßj!lõģ»ųóUž’rP(pęŪ3ö²›e.uŸyµTUWAIY |÷ķwŠŌŲÄšė_Ż”†›Å75?füø¾­µķ‰X$©«Æ³ęż't:ųõßæBėĆå=}–x’Ėä"~·•PVT¦łčƏą½wßKÄį÷Š ‹„­©/†ääd!ę¶ü ·V 8Rާ@īs”_ÓėÅė!asBWü¶ųŲrEłė_œüņóņįȑ#pņÄI˜ąnŁ—²!,üÅ_`…BF£Ń£Ą_ züųq!–ęIįĄ§„xŗŹŹJį˜ńŖU«pÄæ'’žž.Äü{—ɞĊc’ąsµ1v&⓿}ņ|Å-~ƇŸ³OŸÆó—ø¦¦¦böbĶĶĶĄķņCLĢT”··Ž= b±œN(+. Żh³:Ž=Ż=šĮū“ˆ6ˆ¶šĒĶ‘ŠbEųę?nc&8š×p5ē*„® …ß’¶%lĆWõF£ņņrˆ‹‹ĆOĀʀLžŗ<88[¶lĮ‘)™™‰·Žŗ;!Œ ƒÄ3?†°}ūvĢ<544@Śé4Ųŗe«{ō`ųš²ÜēÜ?ŸĶŹÉbKo–²ķķ=Ü/c+”lvN6ĖĒ lÖł,§D"N÷T*”,÷åbKŠJųłyŸ“PźĀ—šÕ\=€YėrĶžóé0†żéŸ?9k”5I¶DĖķ”ą#‹Ė—@óĆfŒfš«ą`ģĻ’śŁY)ÆT_ŗxÉyń—‹lĘŁ ¶åvKgO{”ŗŖś‰Åb±ńĻ­­Ŗes$9,·ågsssMź^µUx‘yš«@|3½PŖ(eMć&ĢœBø[tTō˜.HRR$ž ļģ}Gé<€¬¬, Įliń.?ßw’}ÜFŽńĖ;vĢ£ா¾ŚŚŚ0ó¾ŽŁ¤+W®ųܕ?|ų°pĶ3üyēR©³åqčŠ!X³f fd!ųžTMM fŽ%&&¾}ū0ó] @H[qSBˆļØÄØÄØÄØ“~#ŠYāŻĪĄ IEND®B`‚1åKnč·ōu¹7Ö@Ż(Ž©ó “4[…ķĮ‰PNG  IHDRĆŁĄ9sRGB®ĪégAMA± üaSIDATx^ķŪ{PTך/°Ą.ņ°QŠŠu¦ŹÄĶčTf¢Ę ˜†ĀųOI i*BQ‚ŒQ#v„b—$*3‘ŅN¢0ā`y£ą @Į ŗøˆ ay(ė² ÜŽ{9Y^ŗvŁøēs’øē÷»»ĖzϽæs÷ž« ĆEQFɔ¬)Š2B“P”£€¢Œ-eÄh (#F E1Z(ʈŃēŽ@Ū“6\J»„±±1’ŃŒ™©üżżį“‰dŌ••””ؤ&&&຃[Ļ7™xgń;$3įZö5ŌŌ֐Hs D p ś‰&$’=żƒż$ŅæÉūŽžöŁB¢·“N @Yir®åĄŚŚšd&čć@×äoČzdH'“HŻ7°~żz8::’ŒfZ[[ŃŲ؈;vŒŗČČHœ9s†D†”¾¾*• nnn$3!((ēϟ'‘ę5„oöīŻ ±XL¢ł¤¤$©ćŠUß@ŸÖĒp‹¤ēžqvvv$3Oø +łłłL[[‰ [@@iM•——Ē“··“HsR©”ÉĶĶ%ŃTģFZ†£®®Ž©ŖŖ"‘:öŹ€““sźŌ)†½š"фŅ2 įįį¤5Չ'HK;W®\aśśśH4č=ŠzKŽ!óZ&‰¦G €–”*%“ńBž‚d CbB"”J%‰ŒOu]5BĆBˆ>YÉźGym9’³ÓT”V ōH(RÅ©$3=½īÄyÓūhmk…jDæĻüpöÜYtuvA!WąäÉ“ŲżēŻäՆKņ@‚wĄŚjźż¹Š!ķ@dt$üžā‡Į®AK<†üĀ|$›ŒC{!éŪ$ÄDĒ@*‘ĀūŽČĪĪʱ“ĒP{榦oO]ĻųwāŽĘńū¢±”—Æ_FpX0nUÜB°o0¢"£Px«)))H8‘Yæ ģå9<==ŃÓÓC>E?VÆX‹ā‹$š päĄ<ģˆ”ų¬Z³Šl™Ž¼)ĪŽĪø”~ //`«ēVH[„h–6ĆķwnP²‹”knjĘčŅQͽ3)ć7ģU˜…7|ˆ¢ģ"ģ’r?„®BD|%K–ąńÓĒ ‡——¢#¢ńŽŗ÷`&0ćßūs÷rą%¾śę+¾ŻŪ× —w]P™Q‰ ß @H<€ŲæĘ¢¦°Šģ ߃>ųe’+CoW/Öüj ’^}Y¼h1:ū:µž-ś)äCrčEqN1ÅĀēųœl™€¬õŹ\dŽ/ü¾@My ’ \]”™—_ŗ`Ė–-lMĮ0»X²‹>5=n‚…Ā–Ö–„P%„¹µ9$­~ąĒa=üę£æģ© O=…Ņ‚-oCJŲXŲ@a®€jH¹BN^5Įf "£"q3ļ&6{lFTLD"tÉ»0Ś<Šžö<ģ~»j;ųļ÷ēß#ļ’Ća•LŲe.Ü®¹Ž”^X±Ė v1c»tĖŗÉ+“W\Z ¹‰¶ģĀõ7gŹå3Ūżī®ī8vŁyŁųAśd žt=A·¼k—­ÅõÜėXł›•Ø®©ę÷Yź…TŲ.µE@@łķq³ žyżb$ń WUV‘@Żr‡å¤õzÜ h%°bO6ą†bnÜćĪH®­"k®–sm®K¹mć»j¼Ķ?ģ¶Žī  #<6œ/BšxmøßpW3H¤‰DĀ_ŅOĒÉÉ „„xÖöŒļ8g+g4IššéŸ>…`TK%ŪūäÅzpļŽ=”–Bd*āÆ@Ę,Ų*N:žĮććYžīr\žļe„‡‘ĢģīHī@.œz¢sZ%­¤5;ł“N'ĮŻŻwkļ",< ŖAŹsŹa²Ō_§~ ńßÄØØ«€©Łų…\/Ӌ?ų˜oĻĮ J[%Ūlg ²Ē›­Š|Łįw’ē/ž£ųf1¼<½Hfv\1įN~°»D bĆij–H(‚ÆŸ/Æ%&&ßżė;¤¦§¢Ø n>‚øYŒ•.+į³ÕĪĪĪü{øbŚ^ŻŽä–dAh9õ»¾)@€OÜ?&}æ–ęŅR×ōØé§=6{ØO¾īöĮäåŠŪõCƒC8’Ÿó(Ģ-„ļg¾ćŪŽ? #3Mfeeńė”—CLZz£T)ö÷SßPĻēÓŅҘ£G2Ēg¤-R>§kŚL~_’=ó|ą9‰f6—Ó€·oߞv m®i: 8¢azžõhvs1 ųźŅ%M§3s2™»ĶwI4;]LÖß©gĀƘE7H†aBCCIkzćC‡žy{{ók+”üżüa.0‡½½=\ķŹē¹§ęāāā‹.+ųœ!ŚąŗÖ¶ŗ¹ 8“7źü*mp÷ģģI¤{Ǝ!Cāó{¬_­žSQŸ\ėŠÓߜƐbŃĮŃčhė [f6/€¢(Żą;÷ńōAüŁxädē ²Ŗ’l™žN.((ĄŚµk±lŁ2’1\»wļĘŋÓOįp³?g`ccC2šéļļĒöķŪg|xß¾}X“h?²sŻa#|gg'vķŚ5ķ£Ą¾¾¾|æj«¼¼œß§“’›6m‚‡‡‰ōoņ¾/..FII ‰ŌÅĒĒćšįĆ$ŅÜÕ«W±mŪ6,\ødtcąÅģ¬g~ÜX§ „„ééé$R§]“æ±nŻ:ģܹ“D5»²²2¾@ü„PØżMʹ@’7 E1z€¢Œ-eÄh (#F E1Z(ʈŃ@QFŒŠ2ZĄ’ZÉYĻuY„eIEND®B`‚¬SŠAœwĒ;°vŻZ^Ļn÷ń‡Ćo”ś{ōĒŁÓg±xÉb$D& ĪT‡©/NÅHƑaĻZŅÖ“˜ZŅ7ÓōėSqĢ2€ØØHIŽ88©Ė§É5ģ—“h·2M(+&ėÕ*ÉżĀ¹ĘŃŪŽæS@ńxšŅI­ā:®“ž™†x-ĀƒęžHō\ūÓü=ā+}sV—M³Õ5±$Q,­$–š,gr«m ³–ĆŒcRŁh6¶pĮUņ•Ī9a†cīF3Qhž¶Ńļ’śĖĆÓ-Ņ©O5®Š’¤ctģ9¼ņr¹i4–ŗ½Å­Ö¤óF-ā‘<’-H%œmQŸŗ+E.­Ā%ÄLĒ  5—mf÷ŗ“÷z–— '‘q‰ ČrĖ}>š¦jV6vś¾‰%½„¼Oö×’0§g›Ņ€7(¬ĘÕekĖ«{}*ņćģŅŽDh‚–(ÆĘē£ŽÕ%®”,·‹k>›ujĶ:“i•‰ĻĢ(żS#–9Ö9Ś6ŚįX§Įō8#ó ^B×ķ\MlǼ‹nįōÜż+?ūēž† [󇒍ֵÄüæŲ¢Ę-rī Ōēw3Ž™‡'ŽŚ=AĄĘqŌuŖ kØ=Ź»x¦Ģ*Ūł ®¬Ą’#Ū»ĘXį‰žżźō3däʤś‘IåE’<ÓžłĄM¦y“ŪÜ'Šmą‘2ꚬ…K(Ėcœ§8ēnqŚ»Oķ#ž‚–?ųŸćVüØæēšß"*/łęŸ÷Č zõ­õ_Ų­Ž°Ń˜ģ® 5¤‘±åįĄ9 F£e%†„¤]ĻŖź0ĒvŪÖP…T%ØRć]¢/ŻU_ „  ī¬m4¬ÖóĶa˜anrŁ9>¬sÉīrjøµm7Z°¹ŗŌona6sĘEĄRŖÄÄ@łPrpzśéč -¾š®Ÿ.› “: ÜǘÜŪ1·Ķ„łUIqłś*EUÕ|!»PҚĘūOk[SųTŻóēCaQšõŁō׬uńĀK/`ī¼¹hhhĄž½{Pv” —ó/ó®EoOÆō[†Į05ĪøĢF48Å͆AĄ““4lٲ… ‘"ÜęĶ›iē„Ž„”A@1„wŲéŗcĒŽI5ā‰Ÿzź)©63åååńn µä'<bµZi Hźį23)€(ˆpK—.•JDnˆp旁łQ Ā•——K%"7$Ā9Nś2 ōW'Ā:uŠ”@„Óéh>FQØ @„„/ B-"\vv6u”@„[±b…T"r£@„s8hn@Q(įXŽC" įŲ&H߃ZD8öup:‰A€Ēņ>1Ø @„ęią‰üØ@„ĖĶĶ„.€ ˆp+W®”JDnˆpģR`""›·‘ˆAƒ€„ĢbŌ ĀeeeŃ   ˆplŖw"uˆpƒƒƒš÷÷—jDNŌ Ā¤P؊rØ ū țD¹’2Ÿšźüćų¢ö‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜ž’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’8@qō ūŠ—ĆÖXGr“CiyC"Ū€Ŗ3ƒ÷I œdõźkRŠ’Ł%&'()*456789:CDEFGHIJāāŠ€'2‰PNG  IHDR©0śsRGB®ĪégAMA± üaŒIDATx^ķŪkPSŁš?…"…ŗS^>ŗŪ]gש“3¶~X±w¦­ŚŻuŻ>œŁŁN»]?ųŃvݱv¬ƒn»t‚°H ne× ” €Ą0P °<äŁ $&’D“œŽ{sČƄˆ“×ū›9ćł'ēĘ{ĻMNī9¹„]ؼ€Šš¼SÜP ėdMÅEňYCSšŅĢjšŽĮ÷h ģ šI*•ŅšožŚś³=Ÿrrrh-x„Ņq@ ų†x¹\Aė_„@šb3j1Ø6"’ć|(– ęÓräfŸDŻš]ŚB°œ° ØĘkŠźµ49tttąŌÉS4y'‘H Z+bę®L`— ˜ūśńĮ‘øē5½ø18‚šÖa¬\‹Ģ—6ac|LĻļĮK‰ü~ß½ūĒw±ēg{˜QŠ ģ¾³ÅŹ” =1ŪwlgB€q @ŲłŗŻnw*’]ŲŚŠ•f9c5  ½½ׯ]gcl½NčŲh,^“xÜwųņŠrädē° ŃŃѬŽ"ūśųZ„µ_׃Ž777^3qč_Ay ”²SA”Qą‘›×ä}ĘT"zņG– €N©·ÆŁYŁØ®©†bHww<ųЃ°×Ųó­&Ę'łŪ߆ūąį‡Fjz*†‡ŲŚžÖ[qćś ŌŌŌĄh4ĀŪÓK–/«ƒ+Æ%¢§Æį!įØk¬cĖ\E¹EčŃ÷ĄÉŁ 7Lޤנ~—®_B{};l5¶šööFÜŅ88jå5“ł&źźź„K°Ģ‘čėļCyI9ņóóŃoźGoKšįééÉ·˜\žå œ“NhnnfJ„³«sda~¬Ż¼GEŲü0–³€[īz|~ż»_ćŃõ¢¤²ż½ż,\xTd’o$#'/qĖāšüsĻóO˜|(YJVvĖ‹@CČˆHĪ dC‰ń@ Q(¹‰T$%%aõźÕ\ȑ‰%1ń***&%öŪŃOŽ"53•MˆŻ·ā>ÄDʰ;T `횵ģnNC€–Ę,_½œåøyė&†/dw~²ōóņCĄÜŲl„ŖŅ*±å½“Ģ4„††",$ >>˜;OŗTX“l oo6üø’tåeåpuqexĒś<}ś4āāāųŃ'Zšń™Üœ ‚ÉEvC€žŽ”–”"#;Z!Į!™OėO—=^Ś[ŪQRV‚ŹŖJ“õ·įŲ˜ŅÕ:iłććż÷ßĒK/½Ä„ɇrFDDpI GdÓE£ÖĄĻĻK/ETL“.Zdęd"įrj*kŠŃÓ7g7f‚;(!u’ī;ˆœŪ9P«Ōšöņfę«t‡„‰8ZĆ~ó×oāzźu±¹ ²nS)U(--eiŅ3ŅńéGŸĀÕŻ?<ȓΛ7ŹųčķļEnv.RÓR‘”œÄdQ.ŹWčėē;įļOdddHjŖK֖ż-ŅbUĖ€CĆCččģ@Āłt–Ó/84 £Žyłļ³>c)¾h`2˜X—žę’3’䄞”~<żż§ńĒ?żśN=üüµ8 GŽALh ‡Į¶ßUuU ƒĀŗaŒz#–-[£¢ÉĒ¢ņ"”•££µvĪvX·n\œ]XŠ2©ŗ@sRĶį&«Z¤„Ęąéī‰'’öIģ~n7ūĪc°·³ĒæĄĒŒ“'O¢¶¦–o}ol46hokgY€P;Øaļl'G'„Ē„ĆÉÕɼŠŻÓĶŗŚCvCģnļ`ė€öīvų»ų£×ŲĖ&ɰĒ?Č,wöZÜųkqāä |ņé'ųč³`3dƒG{”}Æ'v>wWwI’T@“€ycU=€oƒ’Q¦¤¤ ŗ¼vvv°×Śćžīg]yK3°ŅĻqÆmæķż»AūtõtįFņ t÷v3"æ9~Xżąj(Óē0$u`<æ•`j™Q ąėP÷>åZ Ś:ŪX7^ijJÜ uĆi¾ 37=šuóEų‚p°oƒā ŌÖÕ¢°°le"vI,‚ę±yk@jpįĀlŲ°K92kĄ×1 hØkĄ•Ä+ę»~~X°`ęųĻłĀģ¶¾¾žuė)¾€¾_U®Bš¼`Ųi¬3o€Ō €–Žé7Č”¾rö!3`r"æ'µĀ¢ĆŲ,æD¦©ŁÄÄÄpI G¬jp*q°w±ķžyÖ½īåē°zÕźÓų§ †"7BX€aPdĀ Pž`„ˆö;(r²@Ž`qH0v¶lŁĀK¹"€mDzšń@īĘy#€XCō9²iÓ&^ČqeßZ!=zä(’/%#%5…× ,åņe‘QYīpČ_ ¬ŖŒyė )Ä<ĄXF@ņĒ* Īœ9ĆīĪSٳ’ę·æĮožż7SęŁFęȔŸPj¤6¢€#ÄD cHXĀ‘#GxéKŒF£éģŁ³\š:>üšCÓšššŌ= w©“šyčŠ!žM„å½÷Žć%iHMMå%\±Ź!݉§ō©¾K„Ļ™‚*dŠ(’hłü…ó,*ļŁų³Ģ‘‡‚P^Iø‚ó—Ī#/7E¾™qž8—/ĮYķŒÜ¼\”V”²Pą*µ 999(ø]€ó—Ļ£„©…å h@WÆāFŹ ęĻ’ŃDZä!ėžrāeBĢ|·Fem%ŅRÓŲyQ¬>/O/öŪ|~ųsxyyŁŻ˜< £¢¢ø$RǼ–|e^ČŁõ(ÕÅܧWŠ)×ÜŅĢž”¤ƒ¢āÖTÕ|eüOļ‘ÜŁŽ {{\»t -­-,쵃Ś]½]ČĖĢCBBt=:üčÅĮÕß{ö큧›'Glū;{;aģ3¢"æ­M­,Ō5p;G;x¹{Į8d„‡›œµĪl¢¼“œe*zņÉ'1/-]-l 6BPJ¬y>ó ŃĢ^+Ā5­į%\™Ų$ąąŽ~ūm6ŪKYl(†eÄ„z‚’v»V›ß²ŽØ‡R©„iŲÄĀw±tŁęOæs]ė¬eYpLFkx¶Ź‘÷¼]¼a«µ…ķ€-ĖāóĢ3ϰśÄ+‰PŪ«Q\V „ł±nĶ:ü÷;’Å1‹ńŌ“OįvÉmöŁĻÆ£­K-eŽ}”¤“”ž¤FJwłŠŖ –€āńÅÄʰX€ļ&åōzÖųkją„õ‚«‡+jjkX"ŅŪy·”rTįžå÷³ˆ½”^l">|;wīä’tH= xģŲ1lß¾K92!@P#§6ƒĘ°R'„ęæ»Ū|,چŪ }Ö7Ū4d‚fXƒę®füō~:²ƒĄbhŽÄŻĆK9b±˜Ķ¼ūŽ»xł/sI`)ƒTžˆ!€%Øų«`LlŁ(’ƒŹ”,Ą4 :Ić"3 äP`;$~¦ń@ARņF\Ł@“›‚±“W˜ĒK¹"€°UĮ˜ńņšā%\ Ąlāg ÕģŽŠl ˆ+ŪÄ`\PŠ5¼ ąP£¤ä$#?;Ÿ× ,eAŌ^Č”īMž‘1Ėļ’š{4µ4ńZ„¤¦¦ņ’@®KĄo”¶¾Æüčœ8|bʳY;ż=żppI¾*'V©žžļ’ .ä’ōōö÷Bė0’l* |†?ųĮød½?vŪ¶oć’@ŽX„ø39čLdŖ’ƒJMw{7œŻ¹$#VÆŖkŖŁ$]OO<<=Š××Ē2ū†E†”±ŗ>>šńšAZzT üü½0ČÉɁ6mŚÄŗ÷·‹n£ æīprvBqI1Ū'<2· nĆÓĖsüē b~ūl©˜) ž\<6mŽÄ%±źA-é®kI×PSQGGG”– ØØˆ•lœœŒģŌl¤^KÅ}q÷ĮÓŪ•Õ•(­)eÆ­­­putżbl_[U {{{–āvžm–ŲbČüČĻĢgŪ8i ėŌ”¾¹žm/ø7ó‚ęń’@®X½ ’}{g{¶ä¤ŅŖąėė‹õė×Ć{Ž7\Ü\ ŌĆŽĮµ µhkjĆż÷ߏ½ļīÅź•«‡•«ļH^”Ö­[‡—_|™ÅžŒ'v>ščp–xٲepņtBWGßAp/tF/ äŠāfxŁjČĪĪFll,kü-m-˜?>BCBį q€³‚ƒ„…†‡ˆž’’’«ž’’’ŒŽ§’“”•–—˜™š›œžŸ ”¢£¤„¦ž’’’Ø©Ŗ­Żž’’’®Æ°Ō²³“µ¶·ø¹ŗ»¼½¾æĄĮĀĆÄÅĘĒČÉŹĖĢĶĪĻŠŃŅÓž’’’ÕÖ×ŲŁŚŪÜŽž’’’ßąž’’’āćäž’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’ļ$÷8?Gż¶[Ą‰PNG  IHDRxt,~sRGB®ĪégAMA± üa$™IDATx^ķ‰S×½ļæĄ°K «@;hG»„$K²µŲņšŲNŹ÷–“TŹ)W]W’Ź_pė½[uļ»q½¼ÜŻē$–mŁń–X’-Y«%Iģþ ū¾ Ģ0 ė Ć ō;ēŠ- £n`` p>ŖVŸsŗg8Ż=żėßļōļw~^gIā-®9Ī„k ±¹ŚN-¼Č?9‚ƒ°{ĻnV¾tńāāćXy®téŗšęėoе„ øø»w—¼HMMÅóĻ?ĻŹ™™™8zō(+Ļ•ģģl9rD¬-=ø ĄY°”—— ¼“õ õør6ۘø…3Søą>žč{„%=żZšŪÄ=7ÜąVv„>bbVѓn}·Ųź>¼¼T8|ų .}s qkä³¼¼|Č>ÉųĒW’ĄŚ kÅV÷#õķĪw°bėĢŠwéńć7,Ö߀T 7žŅ½ŃO:ÅŹ}ōvģŲĮŹs„ŗŗæśÕÆÄŚöĄ`0¢¤¤DƐC:_ *œåöķŪbɳłį‡Ē dee‰„'±Z­Baa”PPP a ¶ŗōōt¶~ųš![Ė!õw¾ĻµŌ·©ĪŻVSS#ŒŒŒˆ-3Ēń{§ś;O‹ĮĮA”®®Ž•;::ƒĮĄŹrܹsG,-Lę4p'å>żüS¢žż€’ó§? =#g’ū’āÖķ[l{Yy1jźkPTPˆĀ²Büå/Į•ļæĆ]bcŻøuŸżķ3|wåܹ{iéi ?vXmVöYw¢.™°7§"æ@Śŗ&téōČÉÉĘŻ“tŌÕÖ”¦¶łź|qÆłƒ>‘ź됕…ŠŠR|łÕ7(-+…¦²äNJ”»)ø’ąźP×P-~j~hiiŗøeee(.)[ÅDȿń¢ q?~ &‘ˆxķµ×pżĘ÷čhÓ#2.ĀØ­® 1QQĮ©“'`µįā…ϱ2&ƒ½ĆŠ“›i͆UhlmAlx,z Ż ‰„Źg~~PyūćÕW_uZ­TāģŁ³8pą+ÓA¤wß}f‹u5õŲ¹3‰µSØ-łå—_²ØwŽy‡ ”×®!4,–a+|ü½Š„Õ""2z}~ü£×&~ŚyΟ?­[·2Ӄڲ£££šóó·Npį¬^½xńÅ™p5¢¢¬ÉĒa|Ģ 55µˆ_*Mž=‘ o!•5UX…3ƾ,~“s|śé§Ų²e QóqęĢپݺu‹mżõ×įļļO„ŃWˆ‹#懓÷ā`ņ3āžOr’ž}ųĪĀVZōōō°kŽ M¶nŽ4é÷IjŅŲ…' ÓépāÄ „††Š-Ó@€³²ÅŅ“Hj)±Ė˜zd±XŲ2b™ØŠ©vu5uLM“YGˈ…©Ś&³‰|Ī$›NčķķeūźõzĮŲgHē…±±1öŻ®@ÉhhnKș}żż¬oō­¤Æ““>bq^ķuÄŃŠé»ŲŚ©æŅ¹¦ē×:jśŒFa”œOrc’siś„įįar £ģ8h™n›-Ž&€RßģMzNL&“0DTg«mźėgö&@ss [Ūći&@[[›Š××'Ö¦GQHš'k“9wī’’?A=é)F”ƒMJ”ƒåĖ—3 €6¹驞ńĒcūöķbėdč@Ō /¼€>ų{÷ī[ŻŌ·‹/">>^lLgg'{ź‘›Ćé§95W~łĖ_Š5χš^t€’ž>äčļļĒK/½$֞>ķķķ¬Æ3ÕĄ½‡p☼ąp8ž‰³@yPĆįpܐĆYĀpĄį,a¦ćāšĆį,Vfõ „„ 6ŪØXó\Ø{opp +›Ķ#čģģ`e9āćא’“·»?dٲDGG¢””‰ŌämxxĀĀfų.—ĆqŁ[€©Ą7łe{2Ō鄾ҢŠ×€{öģaeGØ#}=EOuŠQņGwjuŽ?†““t9rXlLaa”ĖbŽ9K—½˜ź ļ~1l6”  eVojlF9)WUW”JSĶ"øt]:¶ĶŠŪ‹|ņĆojnf7\a‘¹yyhnjFvVŗÉ~ź‚Bh4•ČÉÉeŽgōssY‘Ś{I_ģ÷£‹„T§}ōööJåĖ<MäX%Į@ėöŸuvQ©&<Éüż'ޱ§×šÄ>ŽŽ|x†ć~eŽīŸrTWÕ±§TGG#© ččĒؘĆĆĆč4¢©©¾žŽ"M-8|(Ķ­ 0YQVYró›MfXG­h$åؘhØĖ ɾT5v#–舘 zƒ?ČĢ@Nv>JJĖpē‡Ūųīņ÷ø’ W‰öS[]+īéĘǬ0ö÷‹5gžP42īe`La‚“ÉÄbŒżF”– te(óS§j¤ĮĒŪ˜ Ś.-"‰­kµX‰Ż» ½Ę^$lŲČ4…ŲųXD¬ CmC3LC&¬Gkg+Ö®[ _ņō[ŗ!ÄVž ųĆyŃѰĻßüę7LĶ/,.Įž½Ķś“’ä“OŲ¶÷Ž{=éoßIAdä Œ[½ASks–-ƒ7’v%‘µJü“ó\¾|™+źGOhE™[¶o‚Źī;æśź+ÄĘƊ5gfčõzę™8S@1 ''G,= žR_fĢį8ƒĖbrssqčŠ!±6™›7oĪ)n¾X±b¶mŪĘŹĢÆ[z Ö­[ĒÖ­­­b«ū ö==·×Æ_ĒŹ•+ÅÖÉc×®]bĆ™.{ •›…g)‡ur8ĻĆeo|Ę]“Ļįp<E0ęͧXęp;\ąp–0ShbĆį,Z¦Šø Ąį,v¦Šų„ ĪbGń5`^n’ÉŖäå`lĢó£6#*jā={ooŖ«5¬,ĒŽō»€ŠŠ²‰7B#ż¶lŁ„‡³”4r\ܬ]ĢĢ\x{Ļ-4›fŁŁ &)+«ÄА¼Ūń²e”HLL@qq”ŲāZ¤ė188Œņrå©Ł·"2ŅóżL<g_*zęf劄'įž€sĆO@WœkūcŸź<ŠmMMM,1†;®GIIɔ³?/ōdOg=M€™¼ĄĆū”ÕéŲŗ†Å·­mhkoCyY>4šr’'J[{'ŪFg„‹V«E}} ZˆÄźčŠ2/¼Ü¼,!††‡Ų¾īBƓ÷\(Šžä¢¬ŅżŚŠ= uMč#š”mĢ&¶ĢšŸŸóōP4ŅRÓ(N¦įˆ”$3;ĻNĘõ«7šŹ_Ę’ü’Š’ų÷’Ľ‡©D‚x£ŖŖŽd·]ä3ļżź_Ųō×®^Dš²pōčuˆˆGą²e8“?’ńž’Āéē^`É £&*Ŗ*°~=Ś:ŗ¶œEīHځPrćĶ¢>Oš„&”¤‡[PT€ū’ĄØ i­č6)zšĘĶkDDĆ:jCDōJ“µ¶ay~’“”RĶ>Pꋔ嶽£•œC:#Ńc¤}¤s]TTˆaó00ę…+W 66ć6åĒ\ˆØˆ(Ål¶ŅwŁ—•žęŖU«˜p¢@£)#‚8µUUHŲ¶*o:“:xŁĘ`¦M‰DŒĘ>„cӖMā7É#]:Ļ>Ķ+A@ŗūL))),'Ēy\7›'–žd¶v)µū\™łg:”ĘĘÉ?{ųĄtŪ|ȝo>0{\ ˜—“‡d¢ŽĖqåŹDGG‹5Ļ%((čQ޶ššfŗČAUqš‡ž :6įn؉qģŲ16/@LLŒŲ::!Ėžżū'©ļ³…ę²K&Z %-˜vDC“ƒfE¢ˆ•••nÉß']qI~؊SÆQķcēĪbć .‹ĢÉĖĆańGĆįp.‹ō–— g”läą×8ī§«K‡¬¬L‰-ŽØšā‹o]žėæžŪ¶M=Ųč -ųõÆ’E¬-|\fäåä#łšA±Ęįøšm8 €åą—Ćž­€ō&Ač eÆ9Oįn’†d1ą2><€ć¹”WU²×‰%„Eørå"ŒF£ø…ć Š€:|p8īäƒ>`OōŒŒ ±čėėK)//gūх¾A”ŒZpėf*ņņ ±~ÓOc/}$}·“\»z m­ķā‹jȑ““'ĢĆ+qĪ&55•­;::ƒĮĄŹF¶¶ĒŽ/ĄŽ·ĆČłEP?ˆŗŗ:±¶°p™@~~>”ør墣#Ěē“»E—ßšš: zVv„:ÄĒÆ&ĀŠjŻ+łélƆÄÅÅāņåļ%n™ŒŸ_ öļ߃K—.“}å}fJppvķŚĮŹii ”ZšĶ£dæ$Ń`öžŽJŲ_ŹŻ»wqśōi6ŠŠŠ h·RŸW^y…•Ļ;‡Ć‡å=Tgõ„nÉö ±¤©ge__?Š‹‹]Óżżƒ°o߄Ɖ'ą2OĄ<¢88Ģ=‚ØIbɳQņtd>=Ķf³@n0Vž/O@ūļšO@ I PĻ@„ÅžšČmŸė∽`ƝČįi^‹.‹¤S‚ ӌfÜĻĄ­”[Ģ[z˜]»q Ej¼’æ’Õ5üéģ™”ꟈīK½›Ī–ū÷2qóö-äØóŃÜւįa¾æö-ī„§āü§ēqóÖuä’mRy^ jw¶·vĀŠkDII12³³ŃŅŅ‚¦ę&”ĶÜŽ“w“³lĀźüę£ķźÜ"琾­injbOIW£ÕvĶ© šj JŠKpłū«¬\VZжĪ6ØÉµ./+eY— ½:ńS³ƒĘ(-ö#żrŪēŗĢ”ņŹ ±“xP4RSÓ'żŏ~ō#¤ßKž½‡p‡=» g°Ū7ćļ’ųæųÅ/šł×’ĄÉc'qā¹š šGzĘ=¬_·m‡›ĶĀŌ,?r~ČHÅų7V¬ biĮz=ųē·¦Ž.›Ž÷ß’‘+pmm-~÷»ßĮś7Ndšńd¼½żpāÄ1V.((F/+;266Žø8  ««cFuU8uźYœ;w ėÄ6G|Č>ωegf8;Hō²ääē+:¼Ų;QēƒŽĄœ²²³˜ćDEY…`4™ƒ éŪ‡:żäOńī@Ɉ:ÆŲ3ß³§§§³µääŲŠ}9œ™2•#®['\żžŖX›@Ńš™Į»ąĀRšCĪśn”¢@]€ĪŽN„E„±ÉśūūP[§eŌ„ŗ†jņduƓĶL ļt5µ5bMr^pūę-äŖÕØ©®ÅÕk×qī£sČĶÉEśŻ ¤ŻK÷t --ķlF^Ēh»“HMKˆˆœÅĖLzӖ•Op©­­Ē¦MņcR,ĄĆ̇šńöŹ×‹õuÕÄlŲ]§>AźCäŖhŒYm0a¶ló œ/!  `·²d{÷_Ś÷c&³s8Īąģ”`Š&ĄøĻōž€Ły¹(*(Āå«ß±YtæüźKäåŖńąžÜśį{½Fn,¶ļ÷7®ćĘ­(.*Ęķ”T”W–ćęõČĪĢĵėטäš/4ÕUbI™jM:“ŻčėķC…¦¹äXŪ;ŪŃÖŅ†ŹźJq/×P[ÓĄ“g¾Q4īŻ{?š~Qly 9–Ī~ĮŲ·k/.]¾€°Š0ąäÉēqīć?ĆkĢ[·ļ€ŹƒFŒŒŒ"<<ę¢WFc×^×Ŗ¼gĻž}4w”F£Į»ļ¾‹Qė(jŖjŸ˜ųĖ/æd7į;ļ¼Ć<Sļ¦`łŠX̬£ƒčķ@Td4zōŻ8vō(āWÆ?ķtnBū)ĮØ' WŽz†…=6«.\ø@Ģ’Łż ĪŅE§Ó1’‘¹›źéMɃM­ĪJĖJY}Ģ:&Üp_Üf ˜:«ėŅ ]ŻZAÆÓ Õ5ÕB”[2 ĆĆý{÷«Ķʾ˕(Ļ \-–&3ŹŹŹ„ŗŚ:6‹q’аP\\ ŌV× ]:063AĪØ®Ü 78³Įu&ł7+V¬`ėżū“±3i'«{«¼qüŲqq›öķŻĒ|#£#Ƃ6oڌ•įQXČfŸ}ī¹ē ņq}**%6oœŽ‹1)) ‰ X³v B‚ƒ°{÷>$nN$O$¼]ģµ9Ńó½*9‹E€< ±oß>Ł·4 ’[­'±sēN¬ZµŠ•©jTTTÄŹr:tˆ­sssŁŚŠD”[·n=2”ĮB‰‰‰bĆ™ξPtZšłŒÜćp8sĒe®Ą^>Š›8Ī"AQ Æ½’&/i  §»µ µbĶuD„G`Ół(@g.øĢČŹĻĮ‘‡–“xbņį®ļåp\fĢą%‡ĆYą( Yµ`‰288€o湈>;‡K/ą³Ļ>EśŻŁĻ H§T3ō/FŒĘ>q+‡3(.Q͒믿ĘķŪ·ŁB'6„“µvĀy ž=~ĄéÓ§°vƶm6ŠWØC}CźR~ų𔸕Ù?Dzórpų ü€Édr[YW•ʇ•i\ĀT3ļR‡$śNŽŽ>—Źō¹RŹŲ·ŃsKϱtŅGŸ‰ćāpģqŻ GĄ_|…Ƈ“ÅšēRW׀—_žpŗÉŹŹFTT$+;b³M‡½{÷Lŗ›››YnxWC/nĶūæ[RRJR ālcc Μ9-Ö8œĒ8+c2s³§°Ł„¢ā"A§× ź|µŠŌÜ$Ø ŌB·®{ŅĢ»5U5BŸ±%Ą` D²²„īīnA£Ń°X€²ņ2a`h€µĖ͐;[œM ByZ>ųö·øøX  +;Ī`L¹sēŽXāp&ćl,€¢‘õ[6&Ź>…ØKķK/½„‚|57oŸ>ų¶oŪ‰Į”>ģMŚ‹Āā\¬[7_’'{Švk!Œ °ŒŽ ĖŠ‚†j-6oI„^ÆG o Ž>{7oßDčņP„Æ ĒsĒ]“ė›o¾y4³.um~å•W˜z]XZ‚yīŻ»Ē\‡édØRį|b’w+**Xæ©I’Æ.ÄĮūX»Äŋńģ³ĻŠ5ē1Ų°aĆÜ_Ŗ¼|ŁPn‘ˆDAa¶ķŲ‰Ÿ¾ńāćāYømę+ (8­-ķ0™ˆz҉°ŠXņCßGlņQ,]Žåį”ŠTT!2: ī#‰māĖ]€\æĒČ?9ėYŚ'99yŅgękqü»>2s³Q”læ/_ųbæ8ÓdČ/œ>7ątÜæ_(Č/k󏳉A<É ‹œIÄMŽ.3ؚægĻYąŹ•+ˆŽŽkž Ł—RƒÕŌŌ°‰Lä fA||<Ö­SŹŌ;æ“““°Į„A@:y5W8G\ö`*Ąįp<×¹s8œEΆ g Ƈ³„į€ĆYĀĢź-Ą¹Ļ!ig’Xó\qęÅ3¬œ™™ % (DGN‚ŃŪ«[ŻĒųøŽ=Œ?ü;wn['348„μ€Ļ?’ ‰‰³<“§£C‹ŸžōMØÕE°Ł,bėdhXņɓ'‘Ÿ___w<|päˆ|É7ß\š5qbMžG“ŖržÄe±Ō1f:G CP„©¬V›`6„„„BOOŠŌŌ$ō{Y½ææŸķū4Pr2›Ģbi¹¼ī$==­g’LĪéŹlȅf##&±UFĢĆbIéšNļ@ÆŻąąą”ūĢ…©¾WŚ6j,£ĮŲgLęĒĒG±æ¦œ'qY^€™@żėÕÅEČ+T#;7 éiéČĪÉÅżūH»›2„3ĖÓĀ6fCeUµX“‡:ݾs……%hlhĘĶ7ȓųs䊓g™ČńŻ÷œ?čß}š —¾ūŽōæź‚"¤¤§į›æ_Ąw—æEzFŅÓ]?§=©i©(.-CNv6RČuÕh*pł»ĖLsr„ÅhmmŃūYجœ>gö( €ššpäää°0UĒ…ĪhC  Į/Ž~ž~^ĘĒ˜Éą­›Čxė­‚J„‚Å"ÆjĪŌūOź3M F!@xÉDŠÉ?¤ @ˆ`D_z{ōØØŅ $<ŒŽŠ˜=Šué|č Ūo¶466²>Ič Oš4]݇ö…b4”ŖNƂŖF­ćPłz”£½›¶n†õ ĖóĮšõkŲ¾SAæ³¾¾ž•i½ĮÉĖĖ#ęB+÷°˜GP[SF®©€ąąbž˜°ncü¬ę$ ^ŽŅ5q\ˆ¶ČöĆ(ÖÆ_‡v½8n„éN2ÓX€§’ `č3ˆ„ ž¶ @UzG¤ž:žė>Ćä¾;ƒ£ @Ķ9v{M€Žö>-Å&Ų/³Įž:8"m£jæyÄĢĀĶ½“c!ø 05.‹˜ŠO>łŪ¶MäŻ÷dč¬:§OOLœAŸjäGĖŹŽŠvšŹŒ> ‡‡‡ÅV÷A’ĘóĻ?óēĻcėÖ­bėd¤¾’õÆÅ®]®IšJ5Ÿżģg,A©ŅӛfP¢}£‰aÜq«««C™SSS‰†,Öäńóó{b2Īc\ ĄYŚP!5Õ“d³…Žą4H‹ćøąp–0Ī īÄį,aøąp–0\p8K.8œ% \äŠÜz}·X›ŒJ參÷”¬¬CCb«ėŲŗuĀĀB™™oołŸYLLāāb™W©«FU*?r|ūŃŌŌ ­¶]luÄGŽB[['YšÅ6ב°QQįbĶż8;8+G ĪĀa&Ž7Sķ3ŖæõÖ[bėdØW$KŸ¦{ūķ·É¾­ČĖ*€ĶĖLn? ÷#",5-ųŻÆßƒæŸæųəqöģYÅD3«œ×ćbĶ58kųüA,s0ōĀSŪÕ«WOZŒF#[·w“"$dņ‚f‘”ł©ū/ݧ“¬Į˃˜Ą¦I_·ƖQųĀėׯ' ńƒ3ddd„ŻŲŌyćʍäIނАāÖ hu9¦c4éifvVÅĘ"q{"¶mڊõäscżC#~jfHĒG’=>+ŃfŒF‚‚»ÓóF÷dūTVVĆKå…-Ū·aõŚ8¬_»+VFa9±¤_ĪF·uœey¢ßķøh;ŪČz"€‹>‡ĖĖ+˜Ą–[¼‰žŽƒ’ s*PĖi ēépóęĢöTZRSļ 6›MÜ{jRSSÅŅdč÷(!m“Ö®ƒšĶ€+ƒ±OwŸƒ©Ęģūe±X&%„q\¦:{ę%ˆćØśIŸJŌÖÖbķŚµL¢OĒŻ»w>ŁSRR¢˜…^zśņćbOkWCŸģō©yćĘ öt—#**Šå²£}puŹséų*++ŃÕÕ%¶N††¶Ó<—4tœj®†j>J g²³²q䙉ŒŠ“4PŠ&|1-eeŲJÖ.AĆ„„ģŃSᬠĄĄSDM­M°š­F(±77lœ˜Ģ€ć¹d’›śØxSŪ €źšZ¬#×= ąńuē`" €|uöīŪŌ”DFĒb’ž=l;½†^ųŖ|§¶æÉ¶ &~’ņ+hµĀח c±ZŻ|ōĘtg­SäŚĘlcŸb*2śĒ_“«ŪģĘ—LfµZŃÓÓĆ-;^K:W‚”ēr*¼¼½±2<|ʃ•\ėśgåd”¼¢%%%ČĻĻgŠ$48”×ÓÕĮ!Įpuu…Z­ĘÕ«WQW_‡¶–6É3Ž"**ŠKÖKEIērI GÄ$  ™)sµµµą’@ŽX„xė­·°cĒ.Ķ<’’’°{÷n.Y/gOŸÅ–ĒDP9c•  ¦¦†’g*4‰éįįĮ%ė„§«GD–9V©ÖĮ±£Ē°żńķ\Č”’”ėÖ±‰U|ĘķÉøœt™—rE(dDFDņ’@® ŒÖöV^Č”’a3,B)É”’įįmżK™3”’”vPó’@®ˆe@`#zĮ,F(`ÖüQ$¤¹ĢąV’IEND®B`‚ž;µuµt©Lwź‘š å¬YaÅē+pĪļÖ­]‡Ä{‰ÜĘ×·o_L{{Ś{?üš>]ņ)ņsņ±tńRųœńŪÜ4ŒōpŌū(ŠŠŠ°zåj؉Ż-15Ć-‡ÓØs*•pŚåē]ĪHĪH¦„гčgŌĢTuž¦¦&“µµ¹Ÿõäłh‹ö+ģqīÜ9ŲÆ²GrZ2²²²`ff†f|4Åy·3ę2O3ŸbŊšżÅ[¶lŃ052…÷M3 ]|ńÅє)S¢~ō£ÉŃĆŁ³gO4jŌØdĻ0 P&žóŸå{͚5•õė×WV­ZUŁŗuke÷īŻ•7ß|³ņ·æż­ņļ’[¾’ńT–-[&ēgĮ5žóŸ’${]<÷Üsņżæ’żÆņÆżK¶®Å³Ļ>+߯¾śjåÅ_¬¼ņŹ+²Oŗ8Ę5]ø¾žÓž~śiłÖ“æöŚk•ƒʶ¢æF4¬  €čŻļ~wšč]ļzW“vķŚhåŹ•ŅņĘ!ڹsg“|łņč=ļyOņ|lŚ“)zßūŽ—ģÕG\Ł¢+VD=ōP4~üųč±Ē‹žzź©čüc4yņäčž{ī‰žxā‰čĮ”snæżv9ēcr…Žqä‘GJF£(¬ 0oŽ<©xTn.É7 Ā^}õÕŃźÕ«£3Ļö±čK_ś’ü7׊[f¹‡Ž'n¹EUޱc‡ģźSŸ’oųūß’.‚GÓå¦č: ŠoŲ°!ھ}{tōŃG‹°āyH±f½óĪ;ŃĄå÷}ūöEŸłĢgäæ_pĮ c“„aµšQž "[ šwyČ= ‡(‚j†@ŲüæšĀ ņĮ ߯æžzeńāÅ‹;|Ÿ½æRĶŠĮżėŗō6((éZ»vm²ēgūöķ• 6TŽxć ŁĒ)ėyŖį>ł“~&—'žx"ŁŖTęĪ›lł!ŸY£!‹X`Ź ¬Ż^”šn7MiÜg«ö^ń”Œ8p 9R‘ķžóŸņšß¬ÕŠ›üvĮ øoµ“uŸ“²öCč]VĖ‹,ņž·0 Iī³·+_tå•WFÓ¦M“^Ģn‘œH;$#&Į““Ņ?ųĮ‚””ćĢ4(Zŗt©mŪ¶ML‹?žń'æt™cćLYÓdühUY¹‡ÖŠˆ0:Ņ0įų2īœPćüĘsT”}}šÓf“ Ā|ó|“$ų7Č“–•~³~ī¹ēŹ6!Ōń™}ųᇻ ¢xV —ŠH3é䞘7ÓŅ’æ'¤gäy Ī³±Ķq|0š« ?ŪĪūā9āŠ&ĻBó¼¼s·ä=aņi8ļŻ~#ƒ ’mŹĒE]$÷"Æ0¼Ņ|Ā,W“›éÓ§KśŽ;ī8¹?Zå±Ē+ĻCHxņ³pŹ~ ¤—s_zé%Ń6øV­Ä–ųƐ6M§Ź<å& ·e^“h‘˜“&Ÿšé@“½±„iŗˆŠą~ˆh«ź•įä“O–Ęq~Ē>Ÿ &C(ģYqŌ¹Nśśī‡‚Č3ßu|’яĀ5x>t °Qšø,¹å8ž2 )÷b- !Pį(œ¼ ž•Mb®Į¹µ€į>T šltŅÄ­a÷¹ ÷å9`¤ų/Xś,cŅ}Ā 'tGX&}ZĻ·ZņžW®A„’üē?/ÕuŗĪGq_ąiČS*ē!ų’!Œ(Tf„ž ”„•™Ļ…šį|*9  ĻIžÓĄß\g -»Ē„ČwҜ†g༬Žf.)ņ³ v·÷Ä )„ gB²Õ;Ŗ©8īļqĮH¶ŗˆ_T²åǧŹq ŌµøP%G‹ūMµ.@,ää’tKŹFÓ­irUwÅ}6ß{%½qŕēn¾.@Ü8$[‡Ø· ĄsåŹ‡//j%ļKüӟžTČā “‚Yƒ€Ø•“>hI²ŌniŃZ 4qoZD<]7e÷܉'6e”S…–’¬,’ ׇƒ®ZI+ö‚ję¦ŅLé²²Sh”Įé4hrx“ę!oĄ| £`Ąh;bµµ{ģ! żv4ZÅ"aźųćOöś&Œ¶ƒ•—/æüņdļp(OPt™b%jµAčKä­f h“Ló²²4żr¦ ™d“ž©H¦q#!l³Fķ˜0Z*5•œA^ՈżéOZ¦m öĀĄ#öL»1jŌŽuŒ†Ą ̟üä'“½.˜óg•gl҆:“šŲ|ó›ß”ż•+WŠį•£(*?šcz]l(Ū!ʏļ ^Ūl0ŌBĄa,—‡ÜõP½™Ć4ś>¾ņ‘e#Āłe”)7Žd«‘e>]¼ye€Ń|åSZZyØųĢ­ŅÓĀÖjŁhs2Ÿ®FŽśgĄhV>ŖÓ `ƒ€†ŃĮ˜`4_łĄß‡8`1XĒ’Ų. „Ī>ūlŁfę@øŅąHužłēwß;+ģ|=0m©qŅ4C°A@£!ųŹGV™į7üēׯ_Ÿ)÷žY÷ßŗuk·ó5xøhŃ¢d«'Ķ“.€Ńąž‹»3īŪLā E“ø w»˜c/T, 4ī…2éĄŃŒÕ§)Jœ‡H«ŗC·:Ö0Āb++ĢŲ“č«­‰PNG  IHDRµ°!sRGB®ĪégAMA± üa+ IDATx^ķ\Gʤ+¶Ø±Å‚kģF1ÖĻXbŒ‰5ö b/±#‚ˆŠ=Vģ%Q±cDŊ*`ADT@šH‡żvę䚎ćŲłßoøyggg»Ū÷¦>£!ˆ€ĆįH’bģ™ĆįHī8 ƛŹ»Øwš{čĒ,iP²TI4¬×YŅ„;eóÖĶčܱ3Š“N„ŠŃÉkVÆa–4į€CŁøq#ʍ')`kk‹„K—2Kšš>GĀpĄÉ‘ä”d\»zY™IŒOÄö-Ūqęų\<Xµj=ö䑎'Š8§pĆ'G޼Ā°[e‡Ä¤Dx\ó¢é.zbƒ‹ nß»%Ž];aųčįųk¶B>Ä ģu–-[†uė”œ„“§NbŻ¤¦¦Ņ28…ī89āēóuLMŃ„[ø]ńĄm7¤„„!ģ•*–+ƒ1£†Įzüx“iß÷Ä×°œ7ī?Ee“ŹčŚ£+ŖU©‡ėž÷ž" ź7Ą±c‡YéœĀwœńøymĶŚįiĄSŌ(oˆ”w CŠ«‹ ALBŖWƆ]{¶bђ…ØQ³®\:ƒ$ xˆ5‡wļŠ»wg@æ“^‡¼F«ĶXéœĀ;vģĄ;w˜•\øpįć(i’o]o€ąPTž¶Ģ'™cŹ”)ØTę[tś©žæIFÅJFhR·Ü=.ąĀ™ (U®Ę™€'įo°S¬ś [ŸnhVæ%–ˆ¢VµZ0·0‡Ž¶½†Ŗ™0a“““˜•;zzzū8ŠÄp¤Ų&g±Ļٰaƒ ¶Ļ™% f͚Åb_Ft,V“ąMGĀ(½ @Šß·māŇ:”#>ü1:zS]}š ·n]a–|艏Į#C£˜KɞåĖ—ĆĘʆY™įrgāĉpvvfÖ'®ŸæŽ‡/2K>ŒtŒšūŠß™„”īȰĻZūµ˜j1•„ØgŻĪ¢UėV(S¦ KQ.+V¬„„åtfÉĒĪ;1lŲ0hkk³”ģÉĶ\»v ĒŽc–4022ĀģŁ³™•;99€3fŠįĪü°råJź„T qŹ$%%E°³³c–śpśōi!<<œYŹG¼9YL~¶mŪ&$%%1+grėąäNN}VVV,&?bķƒÅTļąp$ŒJ@\|Ęż9ŽVŸHš{ę{'{zĢĒ×”””HMK…Ćŗ=ćó&gšĻf¶ BBBh{5»v|,ĒćŗK-¤‰sēĻ!-5„pԁ›ž7§S”Uā4µ4éų+W%Į؄y>Ä=ßŪšõóE\\$īÜūÅŅ"ū!–N !ł†ū7½®āśķ«b)²®‹ą—Į“-EŽ·mӖ¦? @ RQL“WŌŌ‰`ļ–}Ģ*ÜČŻ //ٜš¼@:½½½1}ś§®č÷ŃčŌ±Zµl%Z†°°…ėW®!)%åæ­ˆF¦õą²c;V5EøF$Ž}T DĘÄbäŲŃ8¼o76mtĻՀլ1ˆ‹&=õš7n2š4©M.ń՜9sńńń“£Ø Ųæ?\\Č’ō‰ƒ’F×valdĢR²gūöķØT©Ņ'µģŪ·ƒ bGČb§©S?ļČŽµk}’³āøÉSžœĀ¬ģY¼x1ڶĶŪ–””!š7oĪ,Å!·8wī*V¬ˆ²e˲”Ü!ĄÕÕ5“HJŽĘ4 ¬_æŚoBßąģ™³čŅåGXŁZĮjŚ,ø»»cP’AŲ“oR¢R°xįb¼~ ÷+WpÉż“趈gj`ÉŅ%˜=k644r“āŖV­ŠŅ„K³åāää„%K–0KʑN c»ö(eüeеk×<Ļjć(2ŒčččȬO8:ø`ŹŌqĢŹrīØQ£˜•; ,ČŌōUłr7Ę7ß|ĆRr‡8ā=3:€ˆ„8ĢibģŹĆ’ŽÄčDź Oœ9jåĖƤN}/nÓøżü6žœ5k³rgņäÉX·n³qņpöģYįķŪ·Ģś2|0oä4 čyÓSHMÉ}Šn^‡9Š'»aĄK—/ iy˜V-Ļ0ą¤I“XL±šŽ„BNĖ-y' šŃįĒŠP“•ü›ÅįH˜éčׯj×VLļ|AńęĶŲŪŪ£T©R,E¹lŚ“ ϟ?g–|óöģŁĆ;U€ŲČ÷ūHGņ‚²ś”ī8Ī×£,Ą›Ž„į€Ć‘0Üp8†;GĀpĄįHī8 Ƈ#aøąp$ŒŅ'‘­¤FLCmC–¢Õ†ökķé:ģ‚ąšĮĆøä~‰Yņ‹­Ū·BSS“„dfōˆŃŠ7Šg–|”ÆYs§ĶeGUšÕ€LQżš•dEuC uƒÆäp8 G%€l-žjQ…“Sn§čę!W®Ź6Å8tčMOH‰*Ž÷óG\dĀŽ…ŃtüžśįĻ$''Ó^Oį²ĮÓ,F#šU ōK}ƒ›7<ń>.‡¦» Įø,4µˆüU -ļCD Ο?FՁ>Jӊ·¼oć×>æ2K±Ō1©‰[w<™Å‘*ł8}ś4J”(ĮRr‡T_‰®^FMĄų„hXN·³ó¼~ūŽÄsæ‡07ŸmMm|÷]5Lj‰­źB+Q žĻCбs}$½×BÆ^½°ņ/; D*ĢǚÓלīī’G<ߜ]įė!š€ä-^¼8KQ.dk.²=wF=„®»Ą8¢ 9ŽmƒĶ›73Kƻȸ¹ż‹Į‡²”ģ!b£­[·fGUųśśāȑ#ĢR"’Uō}Ü{ <µjւNqXĻ“¦y,-f`ö¼9ŠŅŠ@ēn=‘–‚^?AĢ»8:;ĀĻߏ^·^“¦(©Æ…ėWÆÓ/żOŻ~Ā&—MØV­ŒKĆŹŅ śzłöJ§0ˆ‚śˆļ°Ń Ń2…Ÿ¢Ī·¾Å°Ƙ•w¼īyįŒŪfɇ®¶.¦N›šć˜ż¦ ›É,õ…üŸÓ-č䤜prtBl\,³ä£¹YstiŪ…Y… ¾PM˜9s&‹ÉGa-Ll޼YHNĪ}£„„%‹ÉĻĉY¬šĮWr8…Ƈ#aTę¶lŪBÕfV-[…·ÆńŪo©¤×ŅeKqäÄ*šIģKWPužgĻŸ—=.č? ?=FŃ ģŁ³'O4ŸˆŲčXų>ōŔ)S`ec…ČšH¬¶_Mƙ’š‚ `ƒÓ 8^抣CčŃ£=Žüyøqū>|HóļuŻ Ļėžō¹Ęņ„ĖizAA^ļŽšŖXUąü°uÓnģŽµ ī×īAH°hÅ"> dG />Į>xģū˜Yœ¬ØÄŁŻżÖ99”Z£†xę‡_~é…õė×Ćv–-"##±lŁ2j? AĆ& q÷Ę]DE„”¬‘!ŒŒé1 ŠPé.ļŻÆ7ų>ĄŽ-'Øxč¢y‹°|ålæ ¦×MKKĮ«˜0i:žÆ#]‚Ū±UG4iŅNākŃŠ×@Č«’äoĆѰqC,X²€źāŁŲŚŠō‚ĀŪ;5«U¦¦ā?&3z ¶ü½…J²'g掑a‘˜a=cĘž‰·oŽĮfš ,§YāÖ#/„„Eć}Č=„G¼E€7nßæ±cĘbĒŽųēÄ?Ō”ĻžæĻ0|čpŲ­³cWS¦ßšbĻžSj»"UŁäKęąĮƒ(Y²$³r';M{}]}Ų/uæXÓ”'>šL„]»žĀ­[žhŚø)R5SaccƒĒž1eŅT”/WOßB÷fŚ45ĆŚUĪ“W“„~ X̰ "„O>¾‘>VŁ­ē­³(&Ž4DŠÓŠ b¢Å«¾G±bśāĶDz“”§K¾‘āėÓ¦#ļßæG‹ZĄ ¤M'č鉣 £÷•¤œæ’ž›YyēīŻ»,ö‰æ{ų_uȚ}²z/;ŅåÓ3R<µ8Ŗ›TG‡ę0fŅŒ>WOƒwó¶Š»‚ĆqéĀyōŌÅ4ōšģį5¼ ‰EĢ]\¼éć•PµjUŌØ]ķ›¶‡½³=u³mę@7YÕjVC³ģjŠƒüŸ¹­PĢś}#yMšUʇø–Ģ]Č6000_Ÿ]AĪbŠ%_ OŸ>(W®³r‡xŽ 60K£\·a1ģ×:`÷ö#x”C‡bŲ0ŁšŁ^W,_¾I©IXdk~ż~‡i„Ŗøū8ŻzTDŻŗu?‰¼’ŠīŻ»Ćv¶-fZ™#91ńoušįĆų½ōƒ¦&jU5Įķ›~Ø]æ6ŹTŖ(ž„øxrv)ŃiQ±’„K—’<z·SnhŚ“3ވekj–Įūų(ńČ{züKŠę…¼Ėj)Ń1*“<žų0ZZŁœ7oŽd1dßƝūvb꬙8tį˜š”O>(_į<óy„”#†ĄuŃr“kŲŗÅÄŽĖ ?Ō’~”žā{£ˆźØ×¤6önß Ė™“qüœ;““Ė"":ŚśZŲ¶-,¦ĢĮCÄ|õŲUł?srt„°Ų'ā¢EØńåqhłłģ ‚¬Ÿ”¢ČWŻ’(Ļčččä9dEOW}ūĘ¼yóP¢“ÖnHe­‰½ƒ=ŖV3…¾¾>*~S?’@4kó#ŗwéLĻ711”yIxł&ķŪ·„u0už-<ļ߀„­%qŪć6fN›‰1ĆĒĄĒĖė×®‡õD™ņnÓ&Ķ §— b花9M#TÆZ •k™Ņ²v]]]ZÓh×®;Ė‘;dŒ:»÷ąK!»/õ›ćŸN0+wrūL²Ž›ė×Gƽ°uėVŒüu$ś÷źŠÕŽ«ÅŚF74j\]ü'€īķŪ s3œ:åōŹ”n­ŗčŪµ*U­…Ī=Ū¢m‹¶č’[7ģܹ£@Ļ^mńג%hfŚ æt ēõŽč×§7»¢āųŅw/+q qHKk‚_Žä•Ō²+³0„Üę>|²ŃĄ¼Ćē䎢ēÜń½#¤¤*VXŃD½ģ׌ Ī[YŠrČĻ<€A/„ØČ(fåŸĄ)t45m ĶbyļƒPFF°˜j £&°”ĀCÕ*UadLśr8ŁQ ¢ ¤C“ń„ŁDƒlR*/dD‚ōe䲯ā¬Y³r%›†ˆ5f©/dgœ9sęäŲ×A1bD¦Mhä!æŸ]A ¶¢ ¤x¢°+H{­N:ĢŹ;aaat ÆüŅ AƒŪ‰d[)Eļ0¬*rū? ä»&ēWś#FFF“#°0¢ÖŖĄēėPkU`‡S8į€Ć‘0Üp8†;GĀpĄįHī8 Ƈ#aøąp$Œņ§§„¢ß~ØXŠ,ĆUOLj˜ĄĀŅ‚YŹaǶøuē³ä#ōm(öķߗćپ}ś¢"]­ ō °bõ f}bśŌéHLId–|D'Gc·Ėnf}ø*° ±¶¶f1åQ”U'L˜Ąb™±°°`1ł™?>‹I¾ĆįČÅѓGŃ„[īūØÄ$$%PÅöģŲ‹ųø8xyyŃc/^¼€·]·hŃ"¬[®„jš ˆ{÷ī)}!ĻĖēž…F3ļĘuOć䇤ä$œ=uS¬¦ “ait0ėĄŽdJ€†ųzD— æKś€‹7/ćĮ™øqē JźcŠÅ¼{÷“m&Ót)ņüi üŸ䪁—_ž‰eµsWĪaŚt[œüē$ÖŪÆĄ•ŪŸk$^w#9%™Yœ¼ņ!īNżs ó—ĢGń’ÅįøŚ?žų#;š3Ŗ©$&ąĪķ;°²²Ā³—¾Ø_„¦˜*®4¦Z£Ilɧ“•\ƒ^ā]žĒ,ÅņŲ’źÕŖC-C“oŁe*VEÅoĖ£}ó¦,‡jhڦžčd?œ/“˜˜ˆ#G`åŖ•(SŖ –.XŠvfķŲŃ/“ć(Ąā‹ś.”YŸxłņ%Ź–-K5ūņ)¾F™D’’£aaaēõ2±ŠˆØ(lqŽŽ™¶Ó°óĄNtż±«X¾€łsĆŃQõ DvœČ‚+¢ ģįįĮ,īÜŃøYc³”ģپ};nß¾cM!>>[¶la–耰~Żz“ļŚ÷}ļ#,8eæ1ʰ?FCWG—åRfffTz=+OŸ>Å©S§˜%ć¶×}¤Å'¢e›–,%{,--³U;.Ŗ\¹r…j_f%19Q¼‰KĮÄŌ Cå •ŁK–,”"*9B€<(b 6.Vppp`– ˆm\įŠž3“·ųĄĪTOl“ ĪĪŹÕ˜Ė+Ŗšī/?}œY9#ļ(yæ·ģŚ"˜O5„©V…żĒ÷Šte Ļ(€Óŗķ‚XCdVĪšQ€Ģ„…¾Ö¬š#¬^ē,æ f©‚°xńbĖ•4ˆŹ.ٹ'RŻ’mp7*ÉŌoX?ŖG~ĶÄ/Ė!MjU«]¤)xg ņ~2NkP«V-¬]µzĪUi§ »śÖ¬žRj!E²å*ĄĀrĘ €›ÖbµĆ:„„†°£9£ĄÉä†ģŌ±ŻäD ]ž~ź©ųĶD¤ł¾—ʬ¹+1\t.›]qéæģhöpĄį1ˆ#(Wę,˜= ‡ę>[²@Tūöķ‹6mڰõ#&&ęćĪAŹĀĪĪÉÉłž"söģŁ“ćT`²óQēβMUTŸŸķØĢ Qš%»<å‡[·nįšįĆĢ*śpQPGĀpQP‡£pøąp$ wŽ„į€Ć‘0Üp8†;GĀpĄįHī8 £ō‰@DĶĘz¾54“5YŠz‘–’†å+—+E”##Ļ_ÄŁóg™%ä5.[± ššŁæĒslē %-…YOķZµ1jĢ(f}b£óF2K>ōKėcžĢłĢ*śpQPįāāB’eĆEAåƒ/V ¼ ĄįHī8 £³öf«5kn‰Oż°’~zģ’ū%\¾tć'Œ§2\“&ŁŅōtžóųĻž=£ńˆčĢ;‹–,ĀeĖtK+ ģ;“£G¦åosŽFóŖ#DsėÖ­ ÉŹ…S'œ\8äµ¶ŗle1NA @_6l'''Ō®WŽĮϐ”IĀļŖ—ĮZ‡µhÕŖ•˜'ó2\r<--šĘõõō‘ ,17ÆśP‡ż%ō ±xńbZžØ‰Ÿw>© ÷¼|Ѥå÷J9żļ9f$–¬^Gē­ų{Ļ. ī÷3Ī_æÉrØ C„G†3‹£lņ5 ąīī–’;d@OO/“(htl4ŗ’ļ'tģŲ &õLØņķł³ē1lŲ0œ9犺&-Q”bEXϜ ‡Ķģ,ē/žĒwU«”V-¼‹ Āņ攫ŸėįøŪax\ü­Ķćī§ō5¶iÓ ½z}.¦˜W6oތ°°0„÷ōōéÓĢ’įvŅ ­Ś·‚±Ń—EACBBr 5&fÉxą‡ū\1bĄlw݆–m:”j9mŌo¢x݆œō<==qōčQfÉø’ų>bĀÄ¢™Kɞ3f L™2Ģ*śŃ×C‡1KŠ®@9PÄ(@\B”0aĀxf Bģ‡8aĶ |ŠAƒaģȉ“œnŻĒ¢…KŃģū–T1†ä¹īySGŖ×©Ž#ĒŽ-‚оų~<>}0 ’ŌhŠ?tī‚b*ł:|„Ō½ļ_A£&X GŁØä/”­Ö-3ė¾×1­‚!C† Nƒ:,h޼9•ó÷÷’*—¦łHhѤš6mŠśõ›ÓüŚZŚ0kk†ßÕų˜§K§Ü÷F+Ģ”/S½zō¢[„)šĘ¦1ą÷040DŸ^}аvCvDuĻś—>æ1‹SØÖåēmtéŅåcų¦œ“¤Č*V¬HE„€¶ųĆP„jfq ‚Bļ8Žņ(µcĒŽ„#źŁ{ō +{ąÄ‰pssc–|×øiÓ¦GČ+Ź~ż¹Q³fĶL£@鐯”ÉVsłŌÖ®]ˬ¢Węp$ Węp8 ‡;GĀpĄįHī8 Ƈ#aøąp$ wŽ„į€Ć‘0JŸDŠß“cā"ćXŠz”Æ«ńĒ+}>¾Æ/ÜĪęo& ž®UPŹi¶ßßŪ’Ī·ČFƖ ѵ]WfqTWVEAŲÜܜÅä'§µüœ‚…«sņTVräGeąUČ+"""؝¾ę?*" ā? 59U–Ol¤<‰„ D<3** oCß"%U¶Fhh(='½Ģ°·a4]݈‰‰”Ķ(E!Ó`äH•8€ųÄxtźü^½Ä»čwŲ°a.^HoXź Ž¼Ā¹ĪįѓGX¹ĄžŽą‡dÖCū{ļ߈§ń°ˆ0ģü{ĘMž„Ė—/#.!sęZbėĪĶ›+“Ģøź×‰Ż»w3K±\¾ę7o3;UŽōPz' QyqppČ“ō}ź{L›8?4m‰>»cƒÓV< Ą žĆÄ£šhݦꮓĆ źB#9­:t‚ū…ŪųcČ/²D6lŽ€aƒ{”D‰*xõö9¹Ęc“iܝ{4Ā¢KP³ve4iŠZZZ01©ŖU+°³óķ÷kæOKms«Mg|'3Ę3ž“Ćłöėģ1oīΜ=#,]³THMKśōķ+ˆķ}š?ÅėV 7.£łĻyœģóÉcč1·‹g„~ż{ ­\,ˆ70Ķć~՝“UŽÜŗsKšęϬœÉĻŽ€OŸ„gĪ]fVĪšQ€Ā²FT6 ˜~S‘&P›|‰I vz:#ņŽk×®żBކdʟ^F:$NŅŅód<&Ŗtq q‚ĆZ‡ļCNČėRRS„­Ū7 ±1‘,%gø(¹aĄō65©Z“ ,Ä&mXˆžN ĒHUŹ”)CÅo*fʟ^F:$NŅŅód<¦.IHS¦Nłų>( Ķbš5āO”(™{ӂSōQ™ČÄ)¤‡óõČ(Ą¼yó0j”zīŃēźź kkk„× V¬Xß’YņqųšaL›6Öt²cĈ˜;w.³äƒw’ŽPŽjQ[QPRüÕ«W™„ž“k×N鵎ąą`<žœYņ“Ūk¼vķuÄł”T©RhŠ ³8Ŗ‚«s8†«s8…Ƈ#aøąp$ wŽ„į€Ć‘0Üp8†;GĀČD ›b,Y– vh”mŪV0č-˜%/¹æĘė×ļ"55‚(ĘĘåŃ  ³8ŖBm'‘h .ʘ1ź9xß>WXYM/€©Ą«1hPfÉĒĮƒ‡1eŹdhkk±”ĢŒ5 äo*š’%Ėąā²YUĮUUDQPžš„¤|9pį Č-ęp8ŖGeąā鋰µµÅø‰ƒńęåŒ;†Ś$øŸsǜ¹sŠŖU+,]³”!ćÜÅsxņä ńĻ™3gĀÜb8NŸ;M'šOı“SĶRÖžūi^u$19ėÖ#-U¦~¬(H³ĢeŸ ā?ČDU9ŅE%€høśēžśė/ø8ļÅė°×ŠŌÖĬY³hhß„=fĻžÖ­[Ćvŗ-;KFLlŒųWvC ©02؄˜·!}ŠÄ¤DDĒFÓ6)«oŸ¾4Æ:ā}Ļ’× Å4ū1‘žŒn­»Įó.éœåH™|už:uŠ*ōä¢ŻOD>3Š‚Ę$Å`ᬅ°³³£ėŌė˜ÖÅÕ+nhÓŗ3Ušżõ×_‘˜’ˆłsęĀŃ1³šķł‹‡ń]՚ØU« āĀ©’nbš–-^†½GwįŚ„čóK>{ccc4ū¾4Ź’rV²>00Pé£×Æ_Ē… ˜%Ćõ˜+ŗuģ–'QŠ€€€•ƒˆ4zÖ5żDōŌ)w ō+Kɞ®]»ŅšGµ<|ųGŽa–”=r ØNĄ5Nk÷ÓīĀõ‹×…æV¬&O,ųśś >>>BTt”,Lž<ŽåžÄ”ć‡ŃŃ|/B^ć'ŽfĻM]ŗ|Z0ū±µp蘫péŅ%ZŽóĻé±ü¢ŹNĄ3—. Ž~¾ĢŹ™üt¾ œ8ʬœį€…ƒ"× 8Ł|2J–/ #̚9S'OEBB‘š– Ć0cĘŗ)łuLMź4Ałņåi>"=Ēv1ž÷'-Ó̬+vnߍf`hhHĖKNR׳Ąā/ļå é\ EBŹóøėö-ĶX GŖØĢh‰ļæ’M›6„7r͚5iœ„ŅĘ„i;µJ•*“Z[”B…OįŪ óU©X•*UB•ŹUh™Dģ²zõš(SŗģĒ<&µŌw‹ž¾† %›„(ž.ķiifq¤ŠŹ@^‘ŻŌÕ?†%óÖ÷PT040Tx’)H}q8…Žp8å”ō©ĄdĄĘĘFįŚöyżDWŁÆ’Ņ„Kps˼5X^!Æqٲe9NW&ŖĢIIIĢ’Zµja̘1Ģ⨠. ŹįH. ŹįpwŽ„į€Ć‘0Üp8†;GĀpĄįHī8 S ¢ ĄRŌ ]m]XL·Pśr`Æ»^8sö ³äCG[Ó,rœ¬“iĆ&DFG2Kš4nŠŻ{ugÖēģܶÆC_3K>jŌÆž?ēOĻ1ÆpM@!uMĄ¢Ā—–5Ͳgńęd1åĮ59ŽĀį€Ć‘0*sī?‚X­ĮˆQ# K ˜››ÓąvŅ ćĶĒS9*ssv†Œ[·oįŋ4…U«ž‚Ć:ÜņŗEÅ,^¼Ēž=B°²¶®ßŠēϟcųČį˜`>ļcŽÓsÕ"rźźźŖpQŠüpĆÓĻ^>£ń„ųšń¹EćE™“'N"1>‘YE•8¢ņ³Ūu±Įy|īł@«˜ÖÆ_OC·Ÿ»ĮĮަ¦¦¢½œ%#($ÉÉŃ4®§«‡ŠŠ„¾Å¹S’Q1ŠĄ  hB ‹-¢e6£’ł¹ 0göÜ÷½OĻU¼½ćŪļ*+\”ąķćU+Q'üįĆ,³ŪHU7mŻ̰žŪ™¶9n$<oų+ØV©=÷Åė`Ä%°µ±Ę¤)qåÜ\ņøD™69ĮļŃ üc VŲÆ łÕ•¦ĶZąģł+Ģ*šäė›E¤¹’=ó/žuĖβp.C`iYBi$„$įąƒŠ7‚C‚iOēäÉVx÷Nvƒ‹æ5ģł„ ‰…ĒĘæ’j T±XL? ē/®Ž"bžaΜ9“¼C‡ĪcŅųIøxź".[ˆŅšņ«ą¼ī?Ą=¼Łóšę%#Ēˆłdį¼Å@ž‰-;ߋęĖZ±ƒ^‡³«}"<ä ֭Ϭܹ’Ą;Ēא’šŹr}Ā7Ąƒ Į÷ßׅŸ’#“iRĻīæF}#¼ Ę4 K4­[s§[ć©_ĀcSØrįÖķ»(^¢ LŖ–‡åt[ÜyˆµsÖ¢UĖVx|ū&ōKƒ©‰)~īš3ĶÆ®—.‰šˆ`fM²ßK*:wīŒąĮHMf_ŖōADņœu@Qü¾jł“G2’tȰU‚FāßÅ£wŸŽ˜g³ •*V‚Żj;–ˆŒy%: mf}"R¼¹«B¦fSBŸ Ejˆæü1(UŚŒćń8 »vƒ%żńķ·ßŅ|+–ÆĄčń£Ń#±Īž9 Ӗ¦4=ƼoD2Ħ!žƒé!#$%ż9=däS~AōøŸŸOH‹ a±O”0,žł{šoÅ_eMM-Vz–× ~!š‹ŽOš[ÆŽšņ…f‰g(~SĢĮĢqŠØ~ Ž„‡Ā¤Uų¾ B³ęā}O¦:L$ŻĆĆŽ¢XZ"š·éŠGOüѱ]<zŠ>Żū |ÅņX»Ā³ĪĆĮC‡aś½|ļµ²šõõ…„„%³>'2ņóaŅ“rƒ|Y*888ײA5XL±Č=@^Č&¤J™Qœ@.KŖé)))Xøhöي€ū2oūŪĄßŠŲ“1•ļŃ£-#āÆÕ™½®t\¾eū–ŠJÕBqżT“oß I 8~ü8jש#Š<ÕMŖcųĆ1ž|*:eź±– ĖJū2DN{ŌØQ°7ą X[[3KĘĖ7/qįüŒ2‚„d‘2d“µ?w˜„¬cČÄy»ßpG»fķąqß•ĖTƮݻмAs“3k‡Š„Pčiꔄ^ :6^ż»źXc·†~•«WFóFĶQ¶|Yčjé"<2Õ«U‡ē%O\¼q‘~¦^½pāČ Œ?ߖ«Č®ŖZ&Nœgggf}Nvǽz#ń}š·jĘR²‡lBCš³j qŹäkē|ˆū@ĻOžOüŁ‘‚AÕó|ś āĒ¬ģį󾌼óĚ«pćś fåNAĢP…~°ø~qZ{H&5„µUµi=Sµ•SSgHķ±U뢿!J4HÕv芔,E½ »±M½‚hüōÓOĢ’Ņģ!Ū åŌųć?čŠRĘÉÉé³Ż‘2BšP3fĢ`–|ęՖ-[˜„^(ݐāIŒ:Sæ~}„Æ £[xå—Ü^#ŁVŠtĘJ™’%K¢Z5Ł0fvųłł!99›ČčėėÓ}-Ō„;‡SxįKGĀpĄįHī8Éü“ńAŪRū`IEND®B`‚£>Ścō]=}`²‹öxjō„ŹĻ¼?vÄ ą·ĮƒGS¦LUß ²1tčŠä*=‰[ŁīųXŽ;V¶Óū€ßuH*<&ď<ņˆTpā%p~Ų%@…4ÓÅą9” ‘†52">Cė_ę!oż;ā’b’ķ^AfūĻč›H…JŃžo‚Ÿ`ćŗsxW[ZTEüAĆ hĄ€ŅŚó;•!Ae%šŒ»€l®£é Rė7×rūų“ņD‘¢bs-=ŽD¬ēc>‚ ' „ˆ ÄGć öQ- (–ūbįxć7J” ¢žųC!oŠvą2Ź…ś“µBŃ ¤‚h`’žżņ½wļ^Yņ).t•ørČńøŸ,ß|āÖV¾c!Qyė­·ä?>Ņ÷Óż8#*qŐmÅ׹Śq_·W°Ź$ Ü3²OųŽ+ŠœŸ—P€ū¤qŸI·cAѝ–X8É·¦‹k“nöÉWĪ­†^WæcA#×pqÓa“yßY郀æłĶo¢&{ŁįĻm·Ż–ģu™ųbHćó^]fĀ„ XC NX'ü€īMڈIĮiŲ°a²ÉpÖyQŸ ßJ= ] “3£}Č;h†@†ŃČ[’¬£gŒiFĖĀ ƒ”>\[Z±Į³³Q0čZēæXĄčsd•)÷7]-øŒ1“­VŽó¦ĒŗFŸ‚©\¦}™Īž„éNV3bYo¦c™&f™iSD‰ĢÄ 1ēcGĮöļߟ\­ļcĄh9īŗė.1ĢŹ2čĀ@Šsųø1ō1āĀō[256_11f2a04bea4aeafd*&’’’’.Į256_baed89ecf4a57e3a*’’’’’’’’±SD256_5a792d142ceedda9*’’’’R© 256_ee7e0b08ae4a7f20*’’’’’’’’’’’’Mī’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’ģ8ˆĘ„M&ŁŲ™ -еĄžƒė#°7™={v“dÉ±æą·jąb®÷ē+W®L~i/¬ `“Th œ“La‰It&7\šÆ @D)¦RüAĄT'£)ŒŗØģōß/ ņ³^!’ĮøŠhŃ|8ÆŚJĄīż1vCƒ8łä“eæä­&Œ–CV‹,[ęUżę›o–m¢čĄ3YŠPg41” Ī•ėž8ƒßłĪwd.ō(Øzćʍ“ķ;īø£ĒrĖe‚Ł3¦Ęŗ”Ó/~ń‹ą*¹³i rPŚTøčób@…Ś2ovó•JX¶/„{?P@KĪ'„~å½ÓŖ74upˆ®D(oIėW\‘ģGīP!SÄø$ߘ®bžŖ¦¶˜ėbŹŗeĖ1c_“˜¼Öƒ{Ow;}7 š c~ŒipŚ$¶ŠšŒUŁŗó&„^×½~šP:BØ95fŲŗļĀqŽoˆō=ęĶ›—lµ˜“ĒŒlæōŅK²äIš¬÷ß|ļ ÓöłóēW–/_žéIĆi”‘’8ŃŖLŸ>=ŗēž{Ä)3^Fj‹Ha‡ŠŪÕ *ļ¤I“D•dtXŌĮKODZ¢ų…ÉR³`d?>˜“6|łI/ĪA“äHb/¢—óńä÷$ ܇,}—¤ƒ÷HæzāĉāŠÅ;'Ł/[‹hEllq½–w„×(Zęč!j꠆ŭhPÅÖ§ŚRY€B:hŠ )8Ųģ30ü-BÕ/8®_>•@—łbJgōčŃ2 ̵܄–™¢£¶ęo@ &÷fŸ@œÜaÄ4ĮCxf¶9ē§?żin#ŒTxfĄbĄ o@ņ%œ”uŌkU’>.łŹ“SUTp¼ż¦‹@wēäw*ŽücÆG¦ •õ”k]żõ’žtR„zSj¾2½†Ę‡ü}öŁgeżzÖN mœpg ßņšćĄoŚ_÷į¾Ēv„²‚w'ĻI¾ā•Ēx­t’ÜEÜÜÕŪ“HÜś‡Q÷ŠūdvERµ Pī=ŻķøŅ&[]“b@Ÿ§cčyŠDÆ«ßõ¦ĆēÅŲ[ŹzÖfąvöģŁ#ß.źPØ{¤'+K$Hæ~ż’½bĮČCĶhå‘Ā>X4TW"nzę5“2Õ°hY÷§%¹č¢‹d;+dWoŠ•šPåCƒŒh=#FŒmŌȲŲÜ÷Ųīw©•†EgŠ„‹&T’輒„NcӀ†ŃČ[’ĢŠ0:†ŃĮ˜0ŒĘ€at0& £ƒ)}ąWæśUtę™g&{Ł‘É÷¾÷½dÆĖĄ%d¬ĆTČwæū]ŁĘ7”ÕVąÅŹNƒ>šĄ‡y½¹ą¦J(o`Ż‚f†īf:qšąĮb,Åō„lä1ģāy0(Ā'Cķ÷[҃_,6ä#‚±”» Už+ÉN8!9ā‡<9rd²W,¹gįE26PC —_~YģžW®\)«V­ŖlŪ¶Mģļć ”Pį'T÷Ž;*ėÖ­“’…HßĻŻOŪ¢‡ °ÆēÜø‹ń¶Ó>0ęŁøqc²W©ģڵ+Ł:D,dzÜ·VÜ“gm„ĪĆÆ‚ü«Ϲzõźīšį¾ēąF$j×būöķņ¾²ŅĖļ¼w ’\£#¶I3ļ›yŸAą§Ažs7ģ9餬ŌņÜ!Ü“?łä“ÉVO²ž\_Ź€~ŅT»NoČ{ķĀ4Z$]ßɄ÷‹^`‰™)ęŖx€į%H«M ˆé+&ĀóøE.8?×uM1XĮLo7®© lFBŗš6ҘÓrq “Œ70Šą¾„Šba<„9'¦¼Gy¤˜ óŁ-Ē0¬Ą,–}ĢaiéX‘ėń_ÖÄܗėbˆĮ³]|ńŒ†4nŽaĘ:ó[5•ę™0Å% h Ü?ž»{ī‹ł3iÅ\˜mŅAkFž`ŒŁ4FI<ļ€cäšץGž’³č ę˜¹ņܘŗņŒ¼+̇ "iJĆó“·Ŗœzź©rŅŽ± i夏üŒ“h)1œā‹¼p_Ź ¦­źóĻ5yņ„Ų|¼7Īē}šŽh•ń(tĖAšøŅt‡¬gūŹ+Ɣķ4˜‡B¹÷ā¾xR¾šiĮŠ/;żQõ‚ʇŒHAC…e„*-ÖQ¼|­h!µRAn¹÷”™īė PØ9O”,g^›ßI i#­4ÜyI ¶źbīĖāž¤“BJ!§Ą!PH¤ƒ.×*hÜČv7ļŌźŽė¦e3V…z…øƒ4ņ éĮ%•}*öłØ»ų ¬Hł¤•ƒ’š¬<£V~Ö2Ą¾œĀĢsq?*¢ėŌC„ćš@EÖ4¹Ļ¤—“(üwL‘÷\“wĆ?UZÓH^"„ØØäŪK‚}f,'i<ų/¾äēń{Č%WᾚŸś\n:Ź€žēūš< ×į}š<äI˃P!¤,_€ōżÜżų%&[]4Ė .•eĖ–%{aÜ“ė6Ŗqßy€®.ŗ|+é.@\š{øSguŹ"Ö.Ľ¼Ü<Ō.@µ|÷ „ī.€Ž›īIš2ßYŽk—>ˆ+Ø»ī\Q ¾ŗė¢ †iżt„›ßžö· R “v;Do=•SĀók‰PNG  IHDR£ߓĘtsRGB®ĪégAMA± üaCåIDATx^ķ½ tTוؽkž$•T%•ę ˆIŒ`°±ńģ88NŪ€'—i½dżėł_w'éž;ŻqwņcĄ6vlĒƒ1`03hšē±ŖTó<ÜŖūξ\®†R•¤ūiÕŅ=§NŻŗUµļ9{Ÿ³ĻŽš<<1€żĻĆuxaä‰xaä‰xaä‰F-Œ>æŽ|}¾žśkčéīą`¹=nøT{‰9.Æ,‡#GŽ€×ē…Ž®ęø··Z;ZĮćó€ĒćaŹpüųqę5ƒhTUUAGgxż^°ö[™:žÉĒX„±+ ‡ļæ’~8uźt÷vƗū愦Ö&§Él 7·7CķåZ¦m}c=-;ź’hēGa:xEjkjjŖWÆZ ļų~ĆéS§VÆ^ t‘vUgNž³gkN;a;Rv¤qöÜŁ––/óBĀī½»­K/¶Ī6óg{?ƒĢĢLhki3_¬æč©®¬f[ńL6F-Œ¤RWVU NŸ9M:E8÷­¾Ž}óŻx" Į#Ž“tė»g޾:ō$k’%6‡M“—üŽM¹ÓA “ÉŌ^ÆW°sēNčźīņČä2q04[ŒEHĻ›5Æų³=ŸIķN»‚y!aͽk’vļŁ ķķķZ»Õ©©©P˜_Ømjl’S4Ŷā™lŒZAhqébøėĪ»@@ž4ÉųņĖ/->ž(TVTʚښŅW._‰ķ ..ŖĪU Ó“iöå`ź1æ:ü(%Ź„@ Pœœœ YY“ˆÉé@ ĘŗģX™!#5L&ūJ€ó—Ī÷«*pڜPŗ ŌśéžOaÓO7Aь"ē„źKō™sgŲ–<“‰I3ém±X ¢¢‚9^vē2P'ؙćĀį0ø½nˆWų5<“ ~†'fą§vxb^yb^yb^yb^yb^yb^yb^yb^yb^yb^yb†I³6}āÄ Ęįv2”V«aٲel‰ēvLaśč#xę™gŲĻķż–ĄĒ4---PPPĄSÅlE@GU‚ ķ?zƒŽƎW>p:»;A©Rś;»:E"‰Hą±y@§d^ėółŠėž€‹Šv…\!ojlڜ¶`Ey…€œGŖK…ƇƒÕn…ō“t8sę ³ż!9%}uČÕŅŚ"ĶĻĶ”čÖZĪåĖ—aīܹl‰ēvLJńŲńcM‹–,‚0†ŹŖJ«Z©†Ü¹ŚĆ_n‰DōŻwß 6»Mšž»ļ_²Ų,=]=]ģ+vļŁm¾oå}ą£|ŅŚęŚ®p8:[~ŗõŻu÷ßææµ½Õ\[_Ū<Įü®8yŌ\®éĪĶĻ ¦„§Į/x³²³Ī—;Ī_:ÆgOÉ3NLJa4ōŠŠ‰63= zCųĹp±ņ",_µ\ÜÓŪMMM —ŹĶ=õ}āč‰ĖģĖ‚Į ˆÅbČMĻ•šūĶéX§”+;m.[ü~ éčźefdöõõełõ—ŠÖܖ•¤N’¤§¦CS{“hļŽ½ŚæžŸæēĢž“Ęœgܘ”Āx×ņ»`÷Ē»į›ߘļ_}æķÕŠO>õ$HDµ?ą£Ń³!}FĘ ÉeŠÄ"ö•„óJµ{öģ1ģüd',™»$ż“O?‘śĮ/-Č,0?ó½gpX֙ĶfćåK—A«ŅĀņ{—ĆŽ={į³½ŸŁŸūŽséU×­_§-Æ(gĻČ3^L ¦©¹ ŚZۘż8÷ŻˆEbö™ČĀ0#cZĢ31‚üąƒN˜ ņŒœi?ĻŲŻŻ YYYli|IHH€;3-ń܎iæ!k2Ī_NU¦Å0Ķ39ą…‘'fą…‘'fą…‘'fą…‘'fą…‘'f˜ÖĀŲÓÓ;vģ€wŽ}‡­į‰&ÓZÓŅŅąōéÓą ųŲžh2i&½1:®ĖåbKćĒ„ — °¤ä29[3~h4X²d [ā¹¼§wį%Fʤ¦1P=ź{VŪ•`ņ葍˜Ģ&¦ƒßę8 ÕjeŽ1ą(OģóĀXW_įP˜-]įąĮƒŒĆģG|Ķ’Ē_üćY*DQ;wķ¼„ż[ļ¼eŽõÉ.3:Ņž|˜RA¶4q¼÷ī{Ž µz8f«č>üĄ„’ÉPLæżęŪzæßO’ė’Õ÷įī™-f÷–m[Ū^ßfźźź¢_ßž:½uėÖ~2LÓżżżĢė'Š;v°G<\ą,Œ¤ĆŌUy˜pČŠĢŃ“Ūķfž‡Øķõz™cņßėp:˜c·ĖķEEa$C5M”96 Ģó/Œ#ƒ»ĪHs܍ (•W¶āVQ¹üŹ” ł/»’é@©RŹ„R)ć4‹›Æ4IęX—¢cžē‰M8ėŒ‡†÷ƙDĘÖL,eee@z;¶4~ HŃ„€P0ž¶ęæĮm³<Üą,Œ˜«oå½+A,™Z{H¾9ś ³ß}8wt˜č—‚I1?>"p‚l‰'špF!*la 1ŃüĆ*Ą–x¢ wE‰¢@4µ&±G<|ųšŅ³åg'Wx³) ga†…L~¾)łōæżēß&lž?›Æ˜ēx„™Ś‘J˜¹I‰Ć尔W”kÄ“Ųģō9C>O7§pNWH¢›/7ēˆāDz•B% h.^hHŅ$„²/)öķߏ<ōT_Ø6Īș”;vźč’tp÷ŠÉ=4¢yĘU«W1Ög,ƒ‰Ųv‡ c3Śv‡ßéūƒ~­X.6į¤÷ܒ¹Ébé­?Ŗ#—.]›ÓÖģrø äńrų M¤†Œ¬ HMI”ū 2޼¶żµCÅ3‹KūŗśZ„qŅäļ<ńā/¾üV޳āՓ7Å1gaŒōÅÖD¼lŸ×čėė“¶u¶\)æl3Ł2}>Ÿ:=+=\:·T +„"Ńųčų~^Æ]Ńō—/]–)ć•>„Jéōz¼Å³Šg’“II ™Bz»¢ćĮ‡X™ØN\ÜTßŌ—˜¾öłµpäĄX°l$'%³­&#¦W>°2j“Ć=}=ŠPß”pH°9lŽŅ;4&%$ėt:Ź¢£>„Øōõ÷×émæXs1GŅ;YĀTX³pįBƒV«÷”¾ā|EÅĀy üé/r?żķ§ÕÕ ŠSYóHLŖ\Ń0éå@¼›Żęźģģ;N[Xvų¾tŅŪ8Ō‰źLņćƼš0õķķ¦ęśf”P& …!,”‰e"­Z+LŅ%%¤ėŅo†yŗĮY9Üūˆ$cöš‡"Ćičd62ä%+åŹZ«Ćš.¢Dnmš6cެy©G<³ņ³łõĶꟾč§ZtJUUx|X~÷r¶ęęœ8uā¦ķjjj`޼›ū:ŚķvFEˆ ~ōė£L¬Ē®®.Č$¦»>mee%“w¶ĆšÕk >įŠ‡Ž&~æ?ŌRŪ"ŖkÆC‡n•L„ (J;{Īģī„„„TR'‰¦>MF4Lsµ¦;{;Ķ—/\Ö>ņČ#L¹»§š›€¢)=uw˜3³r²<ł9łøiI)‘Ž\½T{ÉŅŚŽŚV”[“ų›#ßĄĢŁ3”½«f—Ģ`~śÆ’Ÿ_C^Zˆ•bX¼h1““·øKKKÅ{?ß+[¶`ōYū <üH*Šßü×Ķ@z(XóčĖ©ć§4¹¹¹śšĖ5iy9yPv“ žėæž :{:­v›=©üty(!%”9ą ̤}4H”Xŗt©ļ\õ¹ˆ 0²mfv¦!7#—{ūzaFń Cuuuj~~>ägåƒT*„Ü·ń‚Å*ęĆÜ*LŁböōv÷ł¬J¢÷]Š‚,X ˜=k6•””¤›ŹYß{ē½Ī”ō”.®ū u šó_žÜż/’ü/&„BI~;ßµģ.F­ŃęĢČqĘŲ¦·åĻł³¹øØX[~¾ŠóŠ™ŗu3Cśų#Ćė[_gz+ŌϜ;w.»¼/)!\¬½K,äŒd ļžż]X“`8x~üćĆĪw^ŠŸņƒ0 „gŸ–9’Ė|¹æ°¤0Éįpˆ;[:!æ(Š ‹A"–@]St“v@Jj |ļ;߃W^}č /d®Éćö0ēūįÓ?„’žóėż«_8ö7īŁéėī³Ēl.?Yļ÷ł sęĶɾŁFÜß³~żz¶4yį,Œūūß½šżÖp¦»z»Š©¢='t9,ø1ŹėóB]CÕŻŽķÓ&k-!AH. tEłEu²ZŖRŖ˜PĒ`Š3§ĻĄņĖįŲ7ĒĢdÜÖbĻxģŲ1Š$ką¾÷Į§Ÿ}jŌit:u¼|Bt¶įɡp0 ”€‚ŽŽfhĪHĻ€3§Ī@zf:ų½~Ø­©…”¬ŠwėŸH‘Ld~põƒZ“¾÷ļßo»gł=Ŗ}ū÷IˆśóKęCzF:Ó«’žl.(„ ĖIo¼p1ŽŚ›Ū!Q“Vƒäńrxų‡”³‹\ é%‡æö@ “Ś­tKK‹‡Ü±FŅ;=YOŒ²“łóēƒBAރƒŽ·F*_«Īd69[ŪZćõ}z/²ÄH"€ ,ZŠÆŽS§°M'5ż¦~ Ę Ž‚t0DōfG’&‰É'Czu:–i'ŒÆm­rĆŗ ‹'ʚŁē/œ“ĶŌOStŠ\"7“ŽV‹ćgäĪp*ÕŹxįV3' 2L»ŪŪŚUV·ÕģśĶ”*¦„tæV«…¹óęāē`[ŽÓN·¾¶õāK/¾T:ÖōhA+÷L7µ4Q-Ķ-ždu².^Aͤ§QĀČzįWęóū(‹ŁB5ĄI†VSĄŠŚ<¶`įŒĀP^^^&n˜Ø9Łi'Œ›_Ū\K„qv,®M© ¦nsōéū|m­m: 2¦IkC¹óęĻ3!ÓPļp9¬ēϟORŖ” z½>)ä éˆQäĪĪȆŌōTU“¶b 0ķ„ń7ß8¹~ķś{&ˤ3 ‡ąRĶ%0ŪĢĶäcŖ*…Åļōēh“UZzš0%9åź3~ N§ÓŻÓŪ#“X-.b![‰~W,Œ©)©‚ŅŁ„)·[ӎÓN_}õÕʍ?ŽX,E·+8Ōc ę¦f“ģk• ė™LęKMKՕ—ˆUOŒźÉć37U„‘³ •IM"zņü@7{Bܵ·`įųĮ÷÷ßw?̟7_óÄcOd,]¼TœŸ0©q*ĮYT )D‡ŲŅōćõąR ¦¶ŪģL’‰PŚŚŚ˜4Ć<ćga”Kä}ģį“'į·½¶Mæėć]P}±Ś)Š™ÕžŖŖ*æŻe÷ćŖżŁÕÖÕŪ%$[wŁ×ešc'@"»ŽŗtüĒżĒ%•B„CįLLLd®ēf“““\½ęH2Qļiø÷Œį VŽÜŽ’¾Ž>F÷śXæi}Ā’EKBMW»¢HD·.ÆßہŸ`тEżeGĖ̱Ä(QHäĖ–-y‚<•ōrĢ‹„b•&EC744˜ē—ĪW×_®õvõ¦aļh±ZāĢ&3:Ų&Ū,6Źļņ'_®¹œ@ŽCīt:ŃŹīIdøŒyoŅ‹jń½É÷Į”yĘĪĀšŅB¢Č ÓĶmͰzõjFüxüŃĒ]Ųü‡¾¢Ā¢«w‚˜Ó+W®M¢FJzApūÜŚ•÷­TW_ؖˆĀ"»^‡·p,›Å ǰć—T$µ­~xuŹ#="8\vøū®w…µ)Z³D" Ÿ=sÖōČćÄĻž9[ŠÖŚ& =)”––JÉŠģ÷½Ģ–œ&Ą÷Ę(<ć я8L `KćϱĒh¢ļ±„¬¤Ūl6ė©S§čžŽŚŠg qĆÖw“wн½½ĢsV³•nnn¦Ļ;G×ŌŌŠDæ¤Ū;Ūicæ‘9ŅÓÓc%ļiBƬ½£ŻŚŃÕĮŌćēÄēš<x]ĢqĶ„š é4×7Ō3mooĄŒ ĪĀøuėÖ OĄĆ–ĘŸćĒŽsF®ął0]>¢/Œ#ƒū¾é×·^ܰvCi¤ā ž(;w-æ n¶’äšįĆńØĘ”-d•jüŻĄP]xā‰'ŲRä@ŻzZĶ3a¬Šä0}üä­{ĘHa2™˜”x23UzFīÖt ˜DŠQbśķõāgaT)Tu¼ O$į,ŒƧ £liüAĻižé gaIEŽHFOå„”gjĆYŗtä».b-ÓśĄ5gn“ <÷X;[^mŲųŅʙ2qdbķōź{”¹®Ł‚Ńf%"‰3 Ē‘jQSŻT˜RA–%žP8¤ĄkID6_Ч•Kä–P0„{ŗC” ųŸč·!ƒœ ’”@$šų(ŸZ.“)?„ ÄA҇½!o‚Ån‘/š»HTTTtåB&!Sej‡³0nß¾żųŗÖ­ˆÕH\£Ål6ƒÅb^£ēaŚš§Frmš‡‡³0’Ń)ä>-ÉĆ3b8KWƛšŽx"÷®.<‚¶<<£€ū0-Ū§z–&›Żżżżv¶Č3Įp¶¦·lŁriƏ6Ģģa”‡2`M·¶¶šæ’Ü÷µ›~¼©}Õ]«ņ( pn=™|Cčé=… =Žōg¬š†…Ģkpž>$ ĘĪĢ’§°-Ö_wŽAēö„įź™sĀ K˜cHŻŻŻęM›6i™†“ĪĀČäyaĆā©:µ““ ļśŠJŠ—-Yv%/Ļ„ĀyÜ„(*޹ۧ(ø‰’¹ēž^£ga E^~ż˜'’pF©Xjdyx"gat{Ü39Ŗ—“ņqLf&-rŽōĻø÷Œr©iŹåG!ZĒK^‚gš¬HāüUšDĪæ 4±Žd<łżæ’žżßž½£FLˆõļłĻ—’ÓŠoķ7—)£1©ūŽv@åÅJ¶Å䄳0*䊦HF”ˆ4C§ææßqįāēéÓ§ū=d>tą8ŻNČÉĖ ī?“Ž>¢?v옵ź|•³³³3fćéų>±\!Æčīīvtõty-ZŌńżgæÕg«Ł“īžŒŪ^­Ūø~ć,™,v'½ń£`v{‹Õ"ī7ōėM6SŲēõ„%ĀKæeęā…‹ĆŁ9ŁbœĘ¹Łj:ÜśżžPOOØ²Ŗ·°ź… LĆČ š„p^v$§$‡Č÷ ‰ÖV‰īžnŹh4VžWČåv‰.5^ņwwt‹tÉŗVbj‰؝1{FoJbJšB”H„ŅÉ«Œ#œ…‘I~žüś{Ę: ł<>{SKSŠķpŪČ0S(’‰jȏ“’œ–¬ĪĶĪ '&&Ŗ"ČžOśSw^N^–D!«Åj3oNR‚*A_YQ©ŽÓÄ5?žŠćój.ÕŲ«ĻW«g—̆%K–°Æ¬V«»³·Sj3Ųz¼a/ETŒ‚ŌōŌZæ×?§t^iBBB ŪtŚ0±‘čŒÅ#ŃķN»ń“ŸhÓ²ŅˆŽ—›˜X¤‚w,^°āÕń¾WzūŪŪ«7®Ūøšļļ’½_¢”tiā4Ł>Ÿņŗ¼ ^ŹŪ¾īłus:;:ĖūRķ%ż?‘ƾtĀšø<ŠÖŁÖߣŻ)Sįd‰LŅŲÕÖU¼äĪ%&¹DžĢ6›ōßšūsĘ-Æm©Żšā†Ł#ĘP8DŁśmāó—ĻcV½,,K‹O‰Æ {ùé¹é’Ō”T‰R”œ0ļķ·ß¾°vŻŚł¼ūĮå„“„¾YBIÆ¹× AŠ‘›„ć‡Ļž°Ū½õö[°~ķś »YPē$j ¢‰"B·ĻM‡]a­Ēļ­FŪQ\Z¬“ÄÅMOū‹.Bé‚RHˆO`k®0¦œü@wH%cŸ9 ½#ūŒŠ×ß“£7¬ ŪĆĪš,¢?YÕÉjČÉŹIŗ]ˆāŃpš«ƒŻ.‡+kéā„…Ś$"I „Aįp:B5µ5“ŒŸ|ņIoGWGB¤‚5Čłūõ&½Ųćō$Éćåķ&{i¦.’3“!C—2yģNŸ*`vžlP&\Ÿw‘{ĻøeKż†Jˆ„Č֌?x)8 Mt8܍Ų¢B)ÉɧŻV÷ā¬Ģ,›Z­ŽKÖ$+E’Ų^–Äi'‹Żā1MAƒÉ öł‰.ą§“"¹3Ó¦,Zø4ZĶ“ 邿oÉģP)ÆCČY·æµżŲŗµėīF–,žü~XŪŽ3gĪØb…]ƒS4eÓ$j”¹9¹Iź5%‘H&ŌŚƒ”ĆīÓw“u¤©ä*“?ä7Xl–9w-½«S«Õf^N<Õ2‹•óUē!oV$*®żFbĄŌmÜ“qV¤"JŒ—Ė`¶˜]£!.3=³Ęō§)D yJZJ|žŒü›®¶pS|XL[sc³‚ ļFŅÓÜw~|b¼G—¬‹+,(“+ä 5ۜē6TUTAń¬bˆS]??ĻY·½±­źÅµ/.’J'Ēj~,CŸ”æ¼²—`©®Ŗ†‚¢‚Ń[ÓÆnyµeĆK äā©õ#M…X;“ź "Œ%Dć®ʑøµŠÓO÷x“Įó»ß’Īł»ßż.Xqŗ"YoŠŪsgä¦R Ö<ūl«ŖŖ`ęĢ™7d%ć,Œ›·lnßō£My±ų‰ō ƒŃ v:ĘöŽö ¹JŽ åN»39+7KV:»T€C1W”ĀÆS¹574ÓĶmĶaµFŻ" U®€+%'#Ē ŒWfč4:üB'¼'ķļļwķżbo]vV¶Ŗµ£µdĮ¼‚eK— ^Ūņüč'?b[Å.•••0sÖLˆSŽr†Łv°~Ćāh®³²²:¬Ö‹Õ“„*i£Żl/&ĆT¹®”łsę µ©Ś°B¦F2‹?ą˜ĶfqK{Kg_g_ž\)ņ0aÕĪ/ÆOHLŠI$¢’FĘąszœ2Ō9kėkćRÓRÓ¬V+<¼ęa8węœń©o?„c›Å,cv”xė­·=’Āók$≦ż^ōtęŽ¾^Źj¶f(攵‡#W¬ö‘žIš‘‘”w¶ń½uŚŚŚĄh1:\.—7D…„a:œ¢Óźš%RI~IQ‰_¦]ļ75 Šz „ŸĻ§ĮP0=@n¶ElƒĆtŃĢ"ˆWų5Wą,ŒÆl~„{ć¦Y¤×akĘł±ŠÜgī7‡ś }TH28,Ž"mŠö„Żj_±xŃb:%%õQõsEAOO¤„„įVŸÅb‘ćr¦:IķS’®Œ|ō`gg'võīJ‡b4:ōöö2em²·(ŠYYYA2ďJśCįm³Ų*ht“†„:E¢¢>ēeegy‰µ®P«Õņ‰Žģ-˜˜™cXdRü®ßPŹ„7joo7“ŃC+W\™.!Bv;Ż‚^coo{K»Š"ˆż6»mĪ¢E‹Ś’4I™qńqŅńīu?Śł‘yÅņŚņŠr ½kߣ=šŽ?ųW‡æŖ~ę{Ļ,“8,¶Ÿˆ{ą‘ÄJ•Ž{÷=XóČčģčģĻĢĢL¹\{”¤#ĖĪČ¦ĖŹĖØæųćq½@\Dp»Żž¾¾>Į„šKŅÄÄÄóÆgD.1¤iŅÄ9¹9ŚuB˜\󔚱­®&ĀX8aÜüźęĪ?ژ3tm‡‰O?żāćÆu¹ļ¾’.9pų¹“ēę*āM¹¹IO=ņ” !)aĀtrS@Łń2 ?*ŌÕÕõēdę¤čŅtŠP×`~žłēµf›ŁłŹŸ_Q.¹c‰(+' (,ĖīX¦Įגž p»ÄŖ«ąbĶE»×ćõ-[¶l¶›’Ѿ.ūˆrÖd0-øwÕ½v™X6ęļī9„s,YéYĢēŒŒ£öŒŖQ ć͜kq( črt½w/ø;W@ģWģˆEW­ؒTÕ!whfJdJ™$7#׫ÕiäĀäįųZ’ļę»–Ż„-;VR™“vÕ½«fcĻųłžĻ}?ö°\©P¶~¾÷ó¬5¬‘Ę'ÄĆĪ;é+VŹ+ĖįįG†ŗŚ:X¹b%ģŁæ‡žÖ£ßw“æz—Ēå#Ö±ōÜÖ~{æH!Pƒ”`Šćń¤.Xø2Ņ3hÜ#DT„qy\irŗ§hR¾ĖVM88LĪ.„xå(uĘķŪ‰0¾@„qČVÕį„‘+ĖĘåtłV£”¦Ŗ&‡‡Yž —Ć„Q8ĆLUK —±JG5}‚Ć&“ p? *ż·‡Łü„T*N§SJzsę?¶%:ób$źę bx0›„Ę2”Œ3ÓD„ś>½¹©”I«P*ōAAŠa5Z‹ęΛے’œ’/!7 ūŠČAŒhīh>>węÜlՄƒ=cII ļ­¹ĀH†é62Lē¦Ē"Œ·‚ōŠŌŚ"™ØĀŌk*%=g9–A˜‘“-ĢĢČd[ĘV»ÕŃŚŌš†Z6§ŅšÅ‘Ž˜RÉU‰¹…¹–ͶŒ±Ņ3ęĻŹ‡DÕ(·l}cė… ė6ĢjĄDJ‡ƒt04¢­†ŚŗZePTØUj' ’2²3ĢI IŚŌŌT/±˜#ŗ.$Żlæ¹_bµZ-ŻŻŚø¤øZ«É:›Ü(†üÜ|:{FvéåiŅ£Gp¶st0=c;éK¢Ų3¦øØŠći0#éŪ7¼“!očŚōD ćĶĄ€{a,& ō[śŪ»zŗ¤ ²•P"¤ˆkČPhÓjµI¬īžźÖą9É0OŪmvļ…‹$*•ŖÅl1ē…!Ü-“Ė 2 ²4)Z„ć¤ĪMŲ36wa,Šī0=³h&(ćG¹UõõķÆŸY’Āś;Q‡L,ć­ĄĶTĶ ×ė>·ĘˆĮ`09'#§‰gåääČDB‘°[ßmw8FŅĆ„‡ØĻļõ''jĶŗ0?'?IŖˆ¼>7`Ļčt‘a:9zĆōĶ6daĄ‰7¶æq,HŁŅ5ČK—••±„ɹī0ééĀģ|ļļļūśśBdōE[ƒm15!Ę}¾īü)¶**+h¢·²„kpžLõūüŗ©F™M’F°xńāģ„Ė–¦¤„„ %bŒ’9y†ÜŃ"ˆ¢’÷&Žńœ…Q,»ų ģS™Tęg£Ī'“ސ-]ƒ³tżA-%ˆĶבÄķrƁĢUÕUpźō)ó޽{™ Yf“'÷į³Ļ>ö‹e¤biT÷I`r«1 #īAĢ;A;8żŠŃŃ”={ś,„č|\Ķ“ÅäuŲŽE‹±-'&»)ŗnf8Ls’rF”Ä<ō©įxā±' Æ0Db½źžU°jå*J¤āžš‡ā}_īÓƶœŸ0'#§-E"uĆłzrFĒ3›XšlizǬœd¤f„NŸ:Ķ ÓŖx•ųoū›8=-ńc_ČOŲÓŪ“Å–¢é1Mń  IĶ…mol«˜JS;¢č‡}h/éķ́`€­ŚŽÜ¤ÓéÜ­m­lĶÄSUQE;ܶt Ī=#cĄŠSĖ€ĮØ?ōšŹŅŅRŃxūRĘ*’ć'’Cūąš•łyłlM Ŗ‚8|£#1ēÜvšÜóĻ­™Čµéo¾ł=“ŁRdšł|aņtBBBD­3Tq~ųa¶4<‡ĘĄól)2ąĻ×‚K£‘¤¾¾žéŸž‰-]ć(13ć‡D'FaäĀ–×¶œ÷ūül鑦<ČM~ø|–éņy«ŖŖh—ÓŖ®Įy˜&=`"-ŠŽ|Z[{ŌŌŌ0 żf«™9Ę»ĻEĄćę–f°X- 7ź™»ßj±BcS#Ó®ßŲĻžå ½ś^&Ą(b³Ł˜vĪ"nȐŻf›ĆʄvĘŽDß§‡>CÓĘl¹Ņ6Rģ’r?c(8~ŹŽ•¹ń}?Ż÷)ģ?p„žXŁ1°Łm°gļŲżŁns{w»Ż`04źūõę#‡ĄkƽD ąćO?6aū ē/°gŽ>t˜Z8†yF©TjĀŌ`AĶå:Āfļē{”pF!l’Ūö¾żŸļB^^ģŁ·GYPPčßøk×.ųǟžc…Óé “Ķžõ᯻°]’&‰= @m]-ÕŽŚNĶFCooÆk’žż½ ±>Ūūģśl—ŪŌ7ÕW’į;tøģ°łģ™³Ÿ~ü©æ”¶!šÖŪožėŸŸė7ōƧ»?ķfN! z#ķ"©ī]qÆāÆÆžr3sq;ÄÕśĆ_¶=žŲćōc>¦ SįPŸ±Ob0“8üiS“p’źū™Ģ]ˆX;›½°³Ą‰ļ”pĘp ,ļµibŃ1włŠĒ’üÅ’¤fĶš7¶4^]¶’Éd…JIꤐP&4īŪ·Ž8F”^ {®ī+_ś“O=©’r’—!bXŪ©/¾ų:ŗÆō‚HCCC’wÜw,ŗ#Õn·ĒĶ+—‘Ÿ F“7H±ÕieņæBJ,Ób„˜6X śdm2¬¼o„čhŁQģ)#jńHäX³f ܵģ.ŒĄ+LOKļ««Æ3£äƒ>÷Üuŗ`łżæĄfµA{G»†ŅĮ72• $¢+—§IŃ0ēĮči1‘: É2ĪĀ(ąO3¾“Žś^=<šĄĢ—5ų±éĒ›”§Ov_ _įņŗōk.‚ņe‰EbjÖ¬Y™IŁÄ:dzM ¢DzˆōŒœ ‰Ń`ĢKÕ„:ѽwų 0gīœōÆæłŚ²{÷nĢ»ā:_s¾WWņsņq»ƒłŅ„K©Ė:{Jąp:šę¤å„ŗ{ŗs¤2©Ó/[¶ĢŌ„ļŠØĪ‚ŗšĘĒžó\cąN¼ŪE<ĘMRxĢ6A·°«e‰Dø Ūa8»^7[įFž¼ŁŲŪ!ķń=šÜx>r,ĀePl‡ēF°-žŸg”ąo>Ģ ĖyžńķoœZænżŻų †t£žg<~ā8Üs÷=Ć®S"'OžÄMīl)2 ē3>"‘‘k0(Ć«WÆfKƃ›Š***ŲRdĄ]’' —³UåuŪįøŁVUīĆōęĶ >’ųÓĒŽ»å0=˜L&ŗ±±‘-M}¼>/Ī$ģb‹Q”Ŗ²ŠQ‡†Āy˜–ÉeFv„7†‹^Ź3 £­ÉL\\gaōü:Œ 1žLGgŻØC”2CæaĀĀ“ ‘ŗ1­Mcܜ×½8h"˱茧OŸŠü] 6>X±|UĒųÜ`Åwp=‚偞rpżpÆ#’ķ.;cŌ,Y¹Dē±³‚e7ļÉŌe~‹­šp˜ˆE%7øŽqF&Åļ ėļš!k,ˆń Æs„@·‘{ąŖ† –×!CĖČĶŚ ƒŚaB"‡Ė%3Kؚ© k5M5UwĢ»#j.źøUµ°¤pōI‰Ø„n=q,EBĄ°yW*ņ³ŗĮeŒ;“nøņ­Ś ŖĆ¼ĪŻ=ŻŠŃŽĮ䡞›2/=ƕ-E”£įfP8 £\&ļžØµé‰ē’õ÷’ æśåƘ©—iéO ę(ėŒ7Ł0ĄY½>o^(4uöMšēWžÜóņ_öNµ„K7…ōŒ©)©¶«Lƒ‰ĪX¹~ķśÅé\ūžūļCBĀõzÅdEÆ×ƦM›ŲRō@±©½é伒y÷°U,“ųĘD–#r®ļµéŪ1]Öj'\Æ©Æ9Ę£BUłצœ8²ėrƒĄ`MCłÓ_žÄ„kĘHł¤—¶’Ž~’mųĖęæ0õ˜[¤ęr ģśx|ōńGśsēĻU‡ ū¾Üg>vģüŪ’’oĢņāžų ¶oo‹īnĶh’Ŗņ0MŌóį¶=sʰ(,ˊ zJ£7vSSÓmėÖ­3üÆ’÷1¹ pŚĢØ—ßłĪw’~öӟĮ³O?‹n_F¬WÅ«ąĢé3ę§æū4üĆS’¦ļÓ3ž Ę£öž{¼øūī»Įmw3™™&ÕöŅqFoҧ³‡Ń ˜a$³0AmH4zĘår9»{»ƒ˜JćvUœJA Ø.¹\~ÕŻ;-+ńŗ).,†ņ³åĘå÷.‡ŚŚZ½.EĒŌ——€<^Žzuśäi C“{XZHS C*¾¢ėĻ.fڧ&G× Œ¤Cņ‡üׇžhnb„pF‰Tb.-+WBį85-ՈŽ1·{l~esĀĖx9›ō`W½bó³ó)Œksģų1K庵ϭÅ)Š“3˜ś“§NĀS=•łńĒ{pbžĮūŌ‘zįŅ;–ŗšõ³Jf1ēQŹ•!l_WWĒ”§#‰ŖD {ˆ‰‡óH¼¢:Žž×·½~|,Œ±ßH×^®ķc‹œą ˜ń'V «ÓŹ–®Į¹« ŠķĶ&+9!ÜĘøóšy*<ČMĖ~Ŗč“Ŗ‰¾#”otNę<ĻȤų}qƂ”‘øĪ3Z¬æ^Æ·Ļž5›s,Lµ†§‘·Ŗbŗœœ¶&2`jüü(Fq`ĮyĘʶĘS„³Jļf«&&ÅońĢĢs¦_ŁüJ›Ć0m2ŅĻ_¼1vn”™ŽĪµ5Ń¦+Ź+h—{ ›ų• eĖXā3J%R§@:\č)ži‘:Zpć€ĢYż~ĘXÖ¦żA¼ (˜z‹Ū“ ”(w øŻwø­Ŗœ…‘Xⁱ %ŗ¦[Ŗ”:Ų"O‰¶3꘎zlakT@ŌĶü5x&’ncwtsĘ!Ø͜…‘XĶŹa£rD&–¹iń0WEp‰ņÕ­ÆĀ¶mŪwüié ńł ŠŃ0Żga”Ieśį6Ńp%HUT€ŗŽ’,Ź ·1¹&hėhCēa¶vź“”Ł ·ƒHj ÷ Y[·^~ń„ēČD£Ū…N݆nżüŁó™ J\8qāĘgK‘ĮewÉf‚¼Ü<¶&2 ąc\”hƒóŒu-ugĪYøŒ­špp’ŒŁ3@­¼’Vł*(Œ\Ųöʶ3ĆŽę:Ļh³Ūœ•U•7æürąųƒĖė.ž`‹Q7ń;]cH×F9Š#a:,ŽĄxŠ±ßˆa9˜™ŻŻŻĢ1&6Ē’ų@żŪ`x8v =€½ī@nb[ĄĻ$7Ēc\¦s9]ĢėńÜäufŽy»ŻĪ¾rjA>ėčˆqb8wDĪ…ę'*wą…‹įĢ'Ÿ|RĮšˆ°øT‹éēŽżą]żG»>B½‘޹{gõ‘£GąĄį2|S'Ϝ4“÷c_=u‰¢Ÿ;0@ß«³0JåR½X8z&D…TGæ9*ōf ė7ĄŅ„K”ßŌu>Ģh6f_øpØ0%mnmŽĒIä4‰HŃ„@SKS÷¢E‹ą”Õii:ńõ kłŁrĒ`«Ķ`4Ø:ˆŽ¶9 õ ³³ņ³ A‘–š‘źl¼ÜčĖHĖČsŚžÕĖW+Ė/”‹ķ»–}éԁ|ŃŽ…[U‡“%Ά„c™ŚĮå@­VK „¦»ÕćĻżŽłū;’œrÕ6-åŠsm¼*>œ“–,--efV…fęĻĢ>[q>üąCģ=V,_‘øäŽ%ńšµ;03/3¼ę5ŠÜŲ¬ŹĖÉ3 ē¹Ėć2?ōĄCފź ϊ»Wøź›ė”ā|…§ ƀ¢üµkJA:śh‡7ĮŃføåĄ‘0ĮĄč“}Ģńī»ļŽ(Āę`„ j¾CF£1Ų××G»\.#£…ĀW"™õ÷÷Ó‡ƒ’fį%C>sž£GbPF™t¹]>¢’Ņx¼~¶ĻĶ Eōz=s®ń‚÷g¼ÕĘę( +ĶĮ÷"QÆĄ`OD SRRÄiiiĢ^Œż3°ē999āćć1(i& Ēwé¼R¦G]µjNö2óR*„J†Ćžc Ž$©c6 aP$55•9×T„ŒRQķīń{Fr(œē7æŗ¹}ĆKņ’ė72qg“Ś­ī½{öŹ^xįΊ'éqŃAƒ-E"½?æę‡zˆ-Eœahīl>1·xnDƒ…Ž œg,˜Y ń£Ü7żę›oōFŸ”Čb³øŽyēĶ3N|°Š‰gĢ1½Ż÷ĢįŗV® —÷ƒ' qPoŌs^‹DŒŠsg(#™Ś1‰E£ŸŚį…1vPĒ©mģat@Åpq‘Ć35ĄÕ0ö0:©n«*ga Ƃ±¤ųÅ}Ó8»Äy¢ˆÓķā”0ĮaھŃ0åŽ3Š@„Ėg£õS2TĒ”0¢l4™ˆćÆzs< įĖ’żrč_~’/ž±g“8Uœ“=Œ 7KńĖyŅūĶ·ŽüfķŚµ«†žh\'½‡sĻž=ņēŸžó]‰ĮB‡“o>?.Ł03ģæōŅKl)zषĶnŪ–šölՄSYU 3KfBœ2Ž­aĮƒ c͐e·ŪĒ“6=ŁįצƁ›ų‰Ŗ®Įy˜ĖÄαĽ&ĘēµéįŒ‰†Ę&;ż¾/÷¹0ćžg»?ƒż{÷›;z;ąbåE¦Ķ×Ǿf"€~¾ēsxłO/;0ƒ֑;Ń@zٶmøŲĄ“E¾ųü ž?t䐹³»ŽŪń“ü|’ūńœ-?Ū‹_ŅĮ/Ā©3§ĢD ą›£ß0ĻMZČ/ —Ė£ŗū Õ£1ķ›öūüi˜@h“ ō ½¬ŃšśųÅO~’ńĒ’§ėšjsųšaxō‘G1DzņÄ©5ßśö·`né\ķŁ³g­ę+É锹®™ ŽŅÕŪå*„MĒŹŽaQks[³ØCßQe·Ł{ķžkŽŪŹc¾ÖöVEÅŁŠv‰L‚©ƒ”×ŌĖųéhķY£Åh6ōŠ‡É€?©!?ƒD ‰z*ü.‡ĀYѹv,įM†ćĢŁ3ąt:™Ģ©ƒ&§ÉŁŽŚŽš¼lSĢLĻ8„^8AčvøēįÖĢn„‰×˜ÆJŗģЁ†)F#Ō›ōu„óKU”`(įÉ'žīŁ·ēŗŲÉK-)ųćžQō؃Ał…ņ8Ķ“µ÷˽č'Ł‡Ļ dģˆØxE¼³„®øgS5™é·÷Ēdź Ńo ģń-©®Ŗn_4Q6& nčźź‚ÜÜ\¶fxˆ`ÄóēĻæz‚ŽĪ^ģŻ€$%%]}<žųć²§žzJŻ××')((`Śfefő!ŅDģ åš‡ÖĄ”/H,2‘×g]Ŗ¹$ й¹0æ0„¼¼–ß¹\š‘–aKˆKˆŸ7ožL§¦$¦ČSu©³µZ-óHRbXģ–žŌ“Ō¤{–Ż£\¾|9ōū RĀŽŽ^łŹ»V†æ8ņ…,;5;.A“qłāe ½(³“pø¤:·¢„„>K4AƒS!UœR©T³ŁŖ 3?$ė’Ń•­aAˆ ›_%Ģ¢Łl¶¼vn—ā7J}}=żŃG1įv;F Ž€¹“ķĄ=Æ©TjĖ0MŽėć'†Ó%#ÉĢ™3į{ßūókrZ@~…XHJ4œć̈œk7nژ'—^yė<# Ż·wŸä…^øzÜ.?éÅ ­­-EœóZ¼h1[ŠčU¾pįB¶=pž±©½éļ’yŃs®Å¬ŖÅ% ˆ’q…‘ øf,ε&³)@†éėĘäćĒG=’Ž}{Ł£é3L×Å@LoĒbzccöptąˆƒDxį%öĄåŁ)ZDćō[ŗw“s”ĮŁcøµiŌ'ZgŹXÖŪ'%ųuGŁC`ĢkӘČrĆŚ ‹1"Ć`øźŒv‡ŻłłžĻÆ[›ĘUņ³å(čWīŲį®dšķr»/Ļ1ŠŃį¹nõÉšc„ŗśŗą—æų啺i†ž3YMŸg„e=ÉVM8••P2»„Ł‘y(Œ\ųėęævyƒ^¶t ĪS;v›#7d}žÅēģŃō7d5·7`‹Q”¢rŒkÓR™Ō0– Y#yƉD@M3‘ŒĈ¹šy,ĆĀb)!œD"ĒXō;2œ«J…ó®Ä҃ F7Ņ„Cī½$MRtÓµ”5Œ(qŸgÜŗ¹yӋ› 1ś×`øźŒx'465ė­MvģŽ”’Ż’÷»čnݜ@pž±ĒŠs° · jƜüœ‰µCōĆ”pÕc•7ŽzĆÄN PgµJ‰™Ž\ó sōܱs³E2''ĒŠŠŲ`^ævżģ-[¶`vƒŖł³ę/ „f©HŖ¢(Jž——§IDņÖŗÖDY(ŗ…!aVGoG߯~ž«Lę¤į…‘“Ā€ĮŲß?xę°ö¹µZ„BiøźŚŚZĮÓĻ> ›G›—(š†¼PTX¤ńńń Ö\Ū ét:½) )Žļ?ó}øóĪ;S]>e^(ö!LU(Ģj"Ąč ©©©i/\|’¹ļƒT(ÕŚĢ6U\\œ@(ģ:įg&…0fdfŲL|}äkp8øš©KÅT(Ļćč6v»žžöÓP^QBZ(ƞhé’„L;D!S(Zz[~Ÿvī܉Į*嘓H@ ċę.ŖŹĶŹÅ4`wŚ]ßł‡ļĄūæĄ`WA !gµYIŚ$ϊ+č 'xė“<£‡éXdpv"|ō¾}ūhŅSa`=&ŗģDķsłč]»vŃ—#ä÷ūi¬onm¦kėk™ś½{÷Ņ=½=tOOm6›™’»?ŁĶ„dé·ō3ǁ@€¾\w™‰å\q¾‚ÖėõĢkķ; „˜ć~sČ 7˜Éu„›ZšBä_?sa‰•L±Ī”7`0ēöž …‚É7 x‘1+Œ_|ńddd°„ÉMuu5¼ųā‹l‰ēfĬ0¢^ˆįö¦ø½F"™†9gFHĢ #ĻōcZÆMóļ0ņÄ ¼0ņÄ’7óóß„ ō_IEND®B`‚tK׌G-ŚĢ抋šß,h}yß Ęjė™ķķnT+ &ŒõįŽ{ļŸ h9”īšœøEW[ķOŠ2ČŪ0_Ćč4} Ą0ŒöĆ€at0& £ƒ±1££aš34M«ƒ®³fͻ޲`źóŒ3ĪHöņ‘»ž!Š Ģ)Ć(‹¬r»xńbłĪ²,‚"¦ŹóÖ?ėF`½ŠĮQ¤—.]*FJJåKE¦9 JUŽÕ ĘRXVŗEĀ€Ń‘L™2Eā.b ‹D ‚ņ”‚AšmVĀkK–¤˜f׋X>X„6FG‚Iō\Š 5ֆ„…Oƒ‰/aV);ać1AĘ«eŒĢšk”ŽŃۘ1cļŗVš³ĄX SļFcƒ€†léié²Ą1§WoŌcœfš÷ʅ™8żqæ[œŌ°ąCųĄaéŪßžvōė_’::÷Üs“£ÅC€“øuˆEUš—š Īr.6hJ-ļ³ŽwŽģ2‚+ś—bw`?†Š§ŚļE|7ž~śéd«'¾|Ģ›·Ö0ŖB?—X¼Õė²7ą­7mŚ4ńŃąŚxŪį͇ Īoų 0(Ęļ¾øp‹w#K£q>¶ł“΁Ѿ8Ś -<’į:ų*ą©W h”Oµß‹ųdĮøB™XĄšā¾O|Üq­Åu',ÓåøäU—EI(ŌT~ÜxqcF„E ēN8ÕŠ‡¦ŅÓ·&FĪRÄą8że\žIiCHpMāp&†£õ¤÷Ŗ«®JīŽµ|ƒ{pm_üŠf‚0S‡$„"ń|éd“X .®CY=˜0¼øļcb PŃ­Ö8õ¾s=Ÿ›bĒč:•žJ«ĀRAD#.‚©4éT\X€ŃvZ~žKŠĘ.X7‘uńÉG(œƒĮM3½(k…õä½-Q|łž»ž!Š Łż;£XjyŸõ¾óf—w  ÕiŌ€i†śä„ūŹÖz¬¢Ā£Ś6 4Ā™Uėw·h1”YĢ’Ó± ņÖ?†ŃČ[’lĄ0:†ŃĮ˜0ŒĘƚ†5!C¦Å˜ē&t6S_Ģ…7k% Ā[‡Ö*0ZlC²ņŒyo¬Ł˜ĒK c™ŠØpŁŲ»m}ņ¾#ė“ųŸcŠ‚Į ZSu˜éŽ’żćŽa!‡aY˜h0>ų ų”óĮō3 ‚Npę @…¦āćɆ·Ų¢E‹Ä4—Ųü,•ÅoĢu£= X•ذŹÓ4ė‡{×ōĀhQčA³­¼Ś…'žx"Ł:”g¬ģ޽[¶V–ٲe‹læų⋲€*+ó°ŗĪš5kdšøVāÖ^V¦aEœ7Žx£ YiķŚµņß"½[{ē­CĖZ¢ž–µ 6é8~6å¬kē»q]Ą’o]·ÆQč,ÄĆ£MW™i÷1€jżN¢åš >š`ńN£ņŽ”.žzź©čņĖ/OöŠwP­ŲY€ * 6‚ūŸFŠĪ"ØBW°Tżłēwž8Ę ÖÓ§o8Õ\xį…ÉŽ!Ŗŗ¬ßóXĆOīüDAHш§Ø«Ļ<óŒœĒ‚™³fĶŖl޼Y~‹[ Qƒg̘! jNŸ>]ĪćXīBŸz֚߶m›l+¾ÅAćž·D}厜OZā–¶²sēNQ·ŁF žłē圭[·Vā>öaj…’“.p»ķN5µSē=’.ÕžkŌGŽü,L „ĒG;ś€ėāØ³,ΉjH«‚ZLąÅóĻ??š0a‚|3Ą…Ö@̶,Ē w”OęÓG%~ąÄns EĄ••k©ßt\±Å-•’ѕĄI…–ŽVš øæźzśØćųšć–šG›A`€Ž4¹ŚH»CPެ`ųūßtÓM²Ķ !ļVÉZĢÕØ\£ +V/ ė…ŹI9śäōݹ5^؜ōĖ)ØŹ,**©„!|]2”Ću_€ń¢ŪPé-'~āŒl#N:é$ńˆĆ†ŹŗŽPȳ@„Ūč$ō‡ä«»ų…uŠ„å»eąėųšu‰Ūč$²Ž‰uŠ„é]€bŌ=«ļ “Ś•5ŪŚ„¼įgķėŖ” ƒxDwi‡H4E‚&‡ę䃙‘™Žō9s£­¾Aī18@T›Äy¬ėĒöqt!\óźÕ«ÅÉeĒŽrn-„¦õŠo§¬’ō\jH7.O_Æ^|–€\7Myiś4 6ī,ꐗWVgĮŚœ[Xh1Nptģ±ĒŠ;vLÕ±ʬY³d‡Z¦ˆp­4hlć'Å!–†LóqmC ŒyPÅqŸåŚXb…ČrĪ@ėĢ>Ŗ:†+X ¢QŠ*£–s # įƇĖuźC žĆ=0†6l˜¤ēœ|”PF50ØcįÓz)L`Śé[jiĮ‚b¢ˆé-ր,%EØ+ęˆ1„ }ōQYīA€)ī 7ܐ\!LܚŠ—PÉÉ֕c+×bßŌ _v‚‰\Œ!0?Ļxīćt[H‡Z RIk:{- 07F̟?_lxaWP…ņŠ0ŖĮŹĖ”®e&€"ØÖPb!P‰ū+ā³Ž[B]€“zŻJ–€ŚĄį(uŒ¼4½ „ ewÕÜ"”Õ֕ip«„åö”I0cĘ Y\²‘0óĄą~?ü°h>ŠFŹ\‡Žč»“ģ,€a哷ž™!at0& £ƒ1`Œ €&Āš fŅ”‹ļ÷<[+Ąp±AĄ&Bž…l’±‡Ąh ŪŒ†¶mŪ&ö ½ŪŒ™Œ¾…Ķ“!YyVKXp `©Č¢ L5ņMxµcŽ9F‹|Ų{ź›˜h01Ö,Ē:3i*÷‰'ž(­?‘Ó¦M‹J̧©šXVr¢a„ˆ%$öģc†]VŒ#GŽ”ėĪ;70`€l+üŽ©“Ѿä­6Š`JJ?œ śę†4zžöŪł8p T`*?-=Āóa ųżä“O–ß1bE_Q’]ÜėņĮ?” vĄh3J×°Ī£•}b7­žZ8ˆ?~£ ;>Ŗ’7{e ß=ŃšĻ Ÿ\p€"‚sņ4ż£9äÕJųߗ€UpŻx ˜łĄĮēŚkƕmVŃmt<7®ĄI(4FĢ}Ts“Ziv½×]«Ą‘‹Pč>«N·-Äh>y¢Ŗ9±Ŗ~õ7n”•Ųfžø„“ßqzūķ·+Ū·oĒĘ\øpa’|—Ž852€›¶V\héŅ„Ž4ݱ0ź֜÷“gĻždĻh6MwĀ5×ē*«ńˆ D ƒĻ=®¹,ŗŹŽc ‹vĢ›7OĻŠ–œV“V)k©S§v’Ž{1Ó[>?{܁Õ=8—_@M'}G}“ōÉiįˆ ‰īx“Ęyāp/ķ‡ó|­¶(&yĒ;I?׊+Ds¢ˆąFķ¶0äćä—Ń|(÷yŹUa€‚ķóe%“Ä`­{|ąYˆŹH—ŠŹŅ^ōåyäń×U‚łf ‹ ЧOŒĄHøĘ`ÜÕFØpb‰*€Ņx¤…mĄĀœüN:I/Ā‚kꉀŸ?AN€~}«©ĶL'ś<É·K/½TĘpÜāvJė“Ė—/oxibÉ%’Eͬ—v‰W=k6šnŽMśżX µČ[ĘJ“x]³e „–IÖ %³h¼£ł“ģ,€a哷ž™!at0& £ƒ1`Léc¬ņLóArņōe˜ßg^Ś®µŗĪĄSO=ÕšåĮ™ęĦęĢ™#Ӝ>HÓ¢ S«Ų'ä…%øY‘ˆéM¬ YI)dƀķEČźĻh}rĮ!Š 4 Qm0MŽéŒ¬’µŅ4`–%`śba•låkJ¬!dķ§Ģ;7Ł2Ś‘¼õ¦a]ŒapEŦ#ĀcceW4ŲŠc T ¦ ‘𤇵ūp½Åš $ŒŠ(˜Ćpˆōņ;Ę/qž%Wh¤ĖHŅB+ĪjFų’³'=<‹a@a]€‡zH,÷Ņč°¼DČŅAXŒ3Fņ«Éōśwß}w·µ¢Ń~øŻÜŗ@AHŃ.Ą®]»ä›Urų°Ÿå€R/ś?VÜĮÉĒÅ׈+æX!ʕI&ݽ{·X¶į€„³R\ń+±– —bõĘw^Ė7÷™“ Ą½Ó¤Ÿ]»±"ib!UŅIzHē¤I“ä÷”.ϕƺķMŽzSz‡ZP,Ęų¦…ćĆ>–{s? \å{už?““Öī5]Ÿv¶9†ƒvģ¬ĻĒ•h&øąöļß_ZœŠZœć›ßŻėÖśAūPŠ48ƽÓēįpäB^pœĮ9Ņ„Æé$=¤Gō5ÜOŚ2Ró\īy|ŒĪ¤ōYśÕ8Ō 3Ļh4żvTęDʁ2ĘŖA…UoDŗ”,dzĪ5›f,#-ź…® j?Ā„±ƒ„+"čØŃņĪ˜)°aōņÖ?32ŒĘ4ć0ĢZ«€ńāAD˜Š, fK$“ž%2üXĄ(„¬÷čžVöū^½zµ_ ƒ1'ļū0ńjō x{ģ11ģĀP ##B‰”! M°O(tŽŹh-Lt8ØŚTPbžńyõÕWåøoö™=Ć"=† Ū@+„Lj(ŒĻQ™ŗä·z§xõ^|ˆ9i”]€"Čkˆ`4—;vˆŃ“¢ļ‘(ĪiÜw¬Ū”ˆĮq„—’°MH¶X°Tb!"ї1FˆŖž°o+ńÅŹW6yóĒĘ:LŠ1zRūƒI7`‚|ÓM7ÉöüłóÅtŗ,°—øå–[ŗĒ¬|e“7Lt8iŠŖXłŹ¦eĄ]wŻ%+Č }ćʍKöŗüģC‡ DżčG?’ķ;īøCĢh • G%*ZÖżńd¼ęšk’½.›Š‚W­«)ķ,ˆ—ZŽeŠæńo§4ū¹$ B}uŚ»wÆōć&śžŗāū8ŖŠwä›ć8éÄZ~÷‘¾Ÿ»O?ŌÅē Dߕūč¹ōO9–vPāxśzõ‚ó“^£7ńHK=żč4¾w”hU|i×cŒ¤ßŪ† d„©NĮ—?µpÄ’Å$² W0*L †ū¬ūĮ>·U¦‰8‡büźéOŖĖ-#ĘŲ¢?^œd&Nœ(ĪBjĒī;y{ō>ųœ~śé"łqt£žp?^8ćü˜¢bõį8 +-7Z¦“ø1 øērGšPšB8‘^Ņ—^­WĮå—sœxH'ē¢0²NüŅDś˜#ē™H;ŚU­éĮU{½>ß<»¶¢\›w «š¾ŻO­’©öķūšy?…{>ļ…2BŗÉ#ׇ„Ł ņ'1Īe»/ŪąĀĪJŠõRX –@‡…³R˜ĀAķäwü’™ĪašŸVßĮŅ‹Xż¼HŌV7aÅ–¶fU „ĪuUi Ąe—]&3ˆūļ āh7„mü¦Yē*%BIW("}Ī!S™C¤@Ū?Ļ<‚…ēäY˜6l˜w… X[ŠN;ķ“dÆK wØŗ¤›8ü¤…4³š鼞ś256_103ce971a6496d51*’’’’’’’’’’’’‹e3256_3307e94ba2d71460* ’’’’yś’’’’’’’’’’’’’’’’’’’’’’’’듳«C¾²˜‹ * BŠāĄ±jß>jżočŪ‡žĘ“$ĻėžO Ō|ö)”/…€.ä±Ęž@ČńŒ}Ž]ŗ{WqęBHÉ †O<ækW Ņ÷Ó}TA|ę]šĢ׈µ łvI?SVH0bÄU²W”wŌ®čó0՘V÷­ P„ŽsĻ=р’½ā u¼ķ¶Ū’½HŒYB«ŌŠ;V¶'L˜sĪ9²Ż(Š$®»ī:Ѳ"ļŠb”(æūŻļ °¤¤Ė”÷²‚¦¢Ż1 jƒ€ŁŲ4 ŃT0Fšł ÆO—…q#F[’Un„„%/c¹Æ‘·ž™/€ŃŅ0ūūß’>Ł3ŠĘ4£p¦L™"įĶj©įŸüä'2’O‹ļF„f’g?ū™,ęrūķ·'GĆ0ĘĮģQ£Wn¬ `“ Ļ%S¾µą–ģŅ€.YCƒ}.Ų4€›’NĆŗF[‚ķ…ŗübģ¤Ū|°}`æ–ŹoäĆ4£pźŃŠÄ4Ó ĆØ†ŃĮXĄØ |°ÆEéeÕ"õcp»Ųė3•W¬×HšP°.@Žś‡(‚¼¶ČF{°fĶq—įś-,X° Ł*æ\<łä“ÉV×zø7w"yóŁŗFĆĄ}—‘}¾qļeuęGyD\±ń’Ľ™oÜ{Ę`Ą‚źžĢ3ĻȔ•4 T}¾ĆuZ·u-Ęø±‡-āpŒŠ®×Ā—l–-'ÖA=~ū8…é½ųƛīgT”Kč=Öč{ NÅ “ €»õ¦M›ä˜KČuYĖEÜŖWvīÜ)у}ōQ‰B“dɒJ¬ ˆ;8׍µ‰&\n M'•ɼĻjƒ€FābˆĆф` µĪœ;tčŠdļhŗ2rY*£“ŹdŽg-]TGi‹„Č?nPŠŁ³g£Ź0zżĆžP¶ Ź9pą@Łn$Œ¢=:óžDuIu#• Öv—\rI²×…+(&„× Įģ€/’«żÆ·„ī ¾2IÄ'”Ę-'ķFna‡(‚ ¢X4č-|P#·mŪ&‘[Ü j%}?w? ĘčwŽ‘ČA¤LJŌTQŽė9½Aӗ'(Øęīt‹`īܹÉÖ!Ü.@;ā+“zŒ÷šĘw~»7ķ…iS§Nśõė—ģ‚€˜W_}uōĄHkĄ-›‘Ž£Ž:J€”ā!$źŖ£,$Ačm‚erüųćO~銈śŹ=p0!ŽD“zū¤…cDšōŃārŖ%N(ؾ¤“łfžĻźøõ¦X" 9Ȇž=œō¢šwÄņ£…€ÄĘ1bÄaN3Eą‹Tļ:yÄó·#¾ø‹Dgŗłę›%/™‰pc$¦ĖT»@¹bp•˜•õR˜+'a؈hK |IPP‚vRˆū÷ļŸ+lSZåŃ}Ö8īøćsGE`ØųC† ‘)'*9‚ O:pL! 0YBEgŗŠŒe;”Ķņ†Óō!č³ś gś™čÖŠÆ&j-)“t EC_]—žīĖhóŽīgŸ}vņKĻüļe’“7¤UwŸf—fMŸv|+ÓĻY/_ /¢y¬3.éüļJצM›vX¼ö¢`€Ź ‰Ķ2R݇{.]‘fĘӀœY÷GĶw½č¦OŸŽ0³V“±2‚·¶‹/J²Ćȑ#“½Ī t`Fėb–€†ŃĮ˜0ŒĘ€at0& £ƒ1`Kż?ū~„žÉ–³­IEND®B`‚ŅóĖęš÷µäj½‚w¾¶ŸŸ#ś…Ru¾œ MhČWć“d|l”iGš(ēć·}_,eee“U` SAĄ…„„8ī›pQx,2²ϼm—”Ž‘æzėwųnjžKKAZś&¦mĄ'vW]ö}±šEA‡ĻÄÓFXTee%öļßO“COOŚŚŚhņķąĮƒ“ęŠŌŌ„RISšŹČČĄŽ;hrV^^ŽŠ8Ā (O€€æ@˜O1æ®fgg”Óéh Œ”äDŠ"ięēē177G“w"‘ÉÉÉ4¹Óh4Šj’ „ŠŠPl޼™¦%Ŗ)LfMŽÅĒÅ#į™šŲ~aū‡O‘‘‘HII”ɝpąŁĆ®l6ĘĘĘŲ_ėč#Ž„¦¦"""‚&ßüŗØ­­å>T*ģ„łz3żßjjj<¶õTźdut+Ļjk{<‹E.—s'֕“Rź±½§Ā¶uÅ×ń,/uuŽū\ąv@ńŲ×®Åjµ¢««‹n¹BģĄJśžk“ÉD˜A‡&öĮWŪ@Ļ"ö˜˜“EӒ¼¼ī¹ĒM&“a||œ[ćXŽ=AGޔɻC‡9õ kjj ĒēźsŖQtõ(`\…Ų°õčø)njJ‡WœI ˜^µxįŪ‰P¶7įēæ~ Å„ńbźw`ųV^ßó ÷:ž*((p;®åŲE×ø8ĻēėiĘĪõćććiZb0™™‰ķŪ—žN ŗJ‚_¾öš–čõzī³±eĖśČ›Żå°YDz°nŻ:ī1vAvk6Ņ\}Ž””HˆzĪ@žSUDŠĪ•żü×äƬ‘OJĪī6)“ŖĖ׉큉Ōׯ ę9éš!¦¹ar¹ÅūÜĘ×€åīmr©¾‡&w~ĶGķ÷Iå™\ņym+)’|FŚzčßJÖnµu’YZ÷Äץ=Ķ$É+($ŠŽ6¦ŗHÉi1)“Ōy_R4“Ė ķÄd±qm§zŪIa~9™TM Å9äKå÷ų£šÕē’ø®˜ “¤ŗ¦“&g¾Öīéļi…”Ō68Žģ¹zāÕwnӚ;_ūĖכu%€É¼@kž=©‹€’ø:–ÖÜ­tprj’”–÷’ü¾‹€Ģ¶ÜO ,®\÷!!.É)//v»÷Å>އ-ž~d±ū»Ų&lMøÓ6®Å¾ŽgyńÕē’±ļ—ÅžZķŌß®e%Ų{kŽžĆŪŲ·Ÿ7) nžHģ½ÓIII4»ē{tt”&ļbbb°k×.šÜõöörk |Ų»wÆŪ½\»v F£‘&ļŅŅҰm›ó_Ķõõõq7š)::»wļ¦I°Z‹ÅÆ{+vī܉„ēÄų?žA'Åy§éIEND®B`‚M3 ų!摐'ēHł#ēĀ£Ū…ŽŒ:ė‹°gg~ü“véąŪ~Gf}|wļÜ ™W¾}šõÅŹ£Ÿ/7|B÷Żė’j{¾R_#ņOR_ ņß^ śēW§Č§H.G"R`‚}‰<į$łķ§¢Vż!XȂ  EžÅ8H™Š„ 4ŽŌȊ…ˆ `i ų6‚FŹCb""¹ā”rŁv ‚Œ@į 0 $!KrąW2B e®Bä!RųØ”'ø=ĮW‰Epä{ݩΓ‰„ł&•€²Õ"–hȗ‚Ōpb—Xp"¢©¬iˆŸur¢[;F°c”@6ź&:|rų©#)jjS-ņud’¦€z Ҧ€słą^†š")!Fbł\’ŠĢjBƒ³j)`«{ö¶H”•žź¬Xƒņė ŚY£¼­ģ:ˆ¢³›ˆ!RHī€}MkN؇`*I©ĻĘ’K”•.:ø„ ńj–L"hķ mī‹Š·‚ō*%œ‰4 Ą’M » fˆ¢¼E 88ŖqĘoģ1ĒŃ£ ŪźėČī@ƒh éĄK!E2ÓõīQóėNõļ¾ßūšĄ/|ńČƼńĢ'ßüŌN»7¼æ\°”+/õć@,²ÄĆÓµŲ_Co~łčŸÆ~śģÆļ~ūšæ/üčć=ųż…ē’žś÷Ļ’’ž ž:9 š€C ČĄ:Pl`(Į Rš‚ŌKę6ČĮęD ™iĀu!š‘J\õQV‘ŌuB­¹šČZˆ½a=Kl/=­ŁŠ w8°†Ģ°5ü ā=Lp‡HdC~ȍ ’a)ān’HÅQ1YSā-5D€HцU cĀÄm8ń`Ŗ‰¢ Ó(Ę6¾if‰F!7qC56G‡nĢćÉhDśń³ńc’žHČBz°7‚Ō£"÷x+.ņ‘†#AÉJZҌ>¼¤&7)IžĆ“œ „(EŹr”r”ØLerJUŗņ•·É$,gIĖnɲ–øĢ„Io©Ė^ś2­G0IĢJĒ,¦2õ˜L.ó™Š< £IĶh6S‹ÕĢf1ÆŁDmzӗÜÄä7ĒYĖpjÜäL§ōx©Īv†tŲ€§;ē yZƞōĢētŲ©Ļ~ęŸŌØ?*(~ō <h'1±C:”3¹jDC3QNLsEØFU”Šh”Ń™æ‚¢H¹øŃ’rŌ XėfHŁČR:šō„BiųĀ”œRÕ±„0ĶéHCGaĪ”¤;}£N‡Š’ÓFö”¦?u)IŌ¦*uš«”c ‹ŹŌ :õŖ)-ČG±9U R5ŖX kWy ւŻJŒć Ūź%²ŗµŒ/:«¢Wc™,[ŁÓ^R¤²½ õP,Œ„X;V>–™Œ–$0äjbŁpš%"&ČŠ¾,+ŲĀĀDŒ¬*"˜•UšV…ĘVļ &§uée”ŖŃ(„„—‹UfŒm;Ė[Cüķ]c¬k^ļxŚā*Ŗ`t[ӖQÄ.×a„`*ŹYC€V Ep.–Ŗ»•jføÄµ*!®ęWćš6µĻ-S¤t„-†x%D ą+#©mn~į4_ÖwęÖ4’IX`AČe™š6M°‚Ģą;ųĮް„'Lį [ųĀœŃ‹L½ūŁå@æūś—Fu mńl\}©ģr¹«W¢Pą•ęW±8ąš÷ĘčuĘjaėZ/-ważź|‡µŪB(LFE€T‘»ėŁėmŃ«ķź«‹oLŌŲW稅H,×HFŁĘnye*“ģĀ"ĄbAĮMvŚģ›Žļ†ˇųmy©V+3cĒkVŪür'µÅ­VųĖØA,€gµ@ ŻĖfūvн}*"Ni:‹ÕĪĖX­8m°Ņ&w“®“„±ŠiehŚ‹žŠ.§ü=‹7HfņØ[źdœŗ6sžōŒ…8ė*oøŃøfõaįü×^“ś×¢Žt²u åbŪ©µ&±¹ŗl^æšŁĻnj“qėxꌌ»~r¶‰ŗmcLĆFQ"į“īqkDŁīŽ7SŹyŪ›*ō&F¾ļĶoƒģ[’ī·Ą½ļ|'—äĮ>Ƃ3üį2Ixõ Nń­9¼āO‰Ä}±ńŒ{œBēEČ?Nr"·ä(×ųÅSĪrŒŒ\/o¹ĢU»ņ™Ūü!1ĒEĪoĪss×¼ē@÷÷σNt"½čHēĒĪm±ō¤;’M‡śÓ§nŲ“Sżź‡ć%֋nĖ5W\§((ĀŽõ²Cųė ū办µ›żķ”ÉØŪ!ڈ¹Ćżīd{Śó® »’Q潈ś,ŗķóąN[“!ł"øĆė,õøńMOJy€}!§ŽäĻŋ›Ą8‡¼¤×yY¾­,µąeAųz~ذ׈ēßLz«;žŚ˜O¼éMŠŌėūņØ]čė±ĶūŽĢŽÕĀzq|Hžó”šż0V‹Ö’~ų‹?}éŪ¬żŻ“?ŠĻ½ó½xRŖéś¶G¾Ž£žģoßŃÅo1?7OžŒ<ŸłųĻ?ӁūC5­ŽŃVpcVŅ(1$±DV~ ų#RĘxŸG Ā#"żp|ž•Š!n#"h32^t%|ą‡ĘA^‹Phx"ƒŠNRÄ·jPŅWBrdź7q’Z÷‚Z#3’ ŽÕ2ņ*ZRbžÕ~ī'&€ē‚/8 ä%f’`ß†Šį8–s/”&‚ānż·vµе„Ö‚ņ×l½§ õ61BZØsü2fŅc@&&‚(Œb­"30xmrö„ųVŠ vā(`{‘!”‚[I³@śą„ÉĒ}†š €Øˆ„ˆV°fdGŅ_)x'FĀ, 3‰l“/{a'bfy ®Acč[pć"Ø'øh­rˆ­’ˆ‚ų0H؇엿EˆŽe#WzÓ׆ˆbĶ]+Ø/õā[rhGŲ}ˆ7)1&zĪ(#?ˆ B!vČ/gx=O8Ą’sµŒč€ĖĒ!Õų×8ˆČ²$"& Š£8†Ā(v"$ŽXȒYiƒ² Rc=†lXŽd(7ņ#P ’Č(xx%³2…Ō‚=ŽŽ!ø÷§…3Ę3Æb‚˜ Ō ;ę^øeķ8ˆ>ÖnĀeųz4ȇ“W”(+;Ā-­ö-‰ń7&Š€÷0ŽÕ…‰“22“P“W8Ł 0°Ā€žb’…€‡ŁH² v…‰g Ų|š±%RŠ*I¹”2ā.6é”99Yę·BFĘVjŲ‘9Mp:£s6¼¢_#9bœUfĄ”:~ł9øc¦A—É9ĄŃ!咏’Xb‚ p$X‘ō€V³cS¹34‡Ž"B'XĀ‚Y.j³wČ4ŽI!8€xš`Ćg’ä;6å<æcʘYŸ)Ža²‡Ł™ŗ)†µ¹x‚)‡6Rc5x•p4>ós>US$?օM[søfC˜$ō“œģ³œliÖ¹es8Ȃ)i•ųā4Śd-‰?6%@}%ߣįI_'Ę0—B~²$õł†qøŸK.śV@6…A džé)Ęhfw‚! ƂåIŸ‘YŽŃ`֖6ņ–äø7X„9(+†¢X„]ŹI؀æx‹}8 "3’R& 4h3)‘ ț’X{>‰¢Ōø¢.Ņ¢`YV'wRžM³˜ā£‚Iˆ•Å6]BŽ68‚ZH/¤i›L3W8Ŗ¢Hƒ=\£Ż8£””о9|<ƒ(y”µš‘Æ€gh£g/ęV»µdÓ{{—“§GB–)˜)Ŗ–6ūؓ;Ł›Ō"Ą˜kvŹ”¤˜ž?bB5Чo³eVh*£Ó%dKi؍cŠ5 §€Z£8—Ŗƒ ™62›[R~Śi_“7|{ˆ(% ¦Ę™~kčzŠ×i.YœĘ·©²"¢PJ§FGČ«Y«²WR ¬ĆŖ+Š`«/j=—¬”•…~:Øi_”]«ź“Ź×« ‚‹ÉŚyõ§­ŪŠ{Õzž¾z¦čĀčQ橖6źrŗ:¢Žų}įśŒóZ¬Äś®×ź®0·®4‡}ąZ„āzÆśź­Ń ¬aŖ•ļG°ņJ„ś§®°Óś°éz«Į“Öj¦MX£ »…¹šÆ»Æqź‘žš^ķ:²{k¢KÆ ‹²hjy +°'«¬Į±åJ««±;+;³ÜŖUK³õŠÆńJ“+²ƒW²ė°9‹«“)k°.ė± kµ‘ŖW«“ö«kCxĒ^ƒtH¶fėPˆD¶źv¶l ”­ŃniŪ¶r{9•£¶ā`č÷µX··Č|ū· ē·€;øRW„·„{ø¶ˆ³ˆ»øX$«Œūø«ø;¹H%¹”{¹*帘{µv`2·–”wd³¶“¹.ŠQGŗ”ŗēgŗ-ŗēō¬[y®«°lā!øµ+·ėmnö1»‘²»+Ń»×¼†[uĀ{Ä{O²«»É»ŗā(x‚):*œI»ka¼1õ¼Ź½p ˆ]Æ:$Ķk¹Ü»°’ęÆųG¢†ˆŖ‘™ “Nڊy˜½Ī{¾Ē‹x~#”O0+Ep'xø J9+%Y;“wŗ)-N -ū˿ț¾Š–+=xˆ‡ŗ‰§²Ņ öHcGbWy™“`”½6KĮ"±¼lb›)Š’»&I.2²%Ć2›^Š“cĀاĀ#ĮĀ7r'‹3…Ę„Ÿ˜ ó‰Ä1¢%ą»–¹k¾> Æ#˜„‘“ÖāŸHЉJ#æN¦0 c,MćÄ¢ÅQ ~GĆ(ØęĮRŠr‡{a֘VäāRą’’ĒpeE ŪĒԌżJĘeü>śfĒŗE©Ėōx<Čģ`=äŠ|‰<¼2«¹Ž¼±OūS“l»•Üæ—ü«P«k›¬r˜*ȟ¼ˆS«É±KÉ„lɧ,Ž©ģ]£ŒvĘĆ+łŹvŹą6ĖŻŪŹžŒĖJĖ]ÅĖ&QĖ Ģ‘ū.ķęĒ•ĮĘPlŹČ™½ōĢ®Ķõ`ĖWAĶælĶŖKŚ\µÜœŲlß\Įį,ĪÓÜÉą|Īö0ĪUQĪFÅΰģĶźlĪņ|ĶéģĖė|Ļ4ZNõĻüÜ͹Ļ„ŻŠųLĻślĻøżĻ½ŠżLK-“-Ķ­pŠ\Ѧ”Ļ]ͽ.•й^WWĢ,¢»0|Ē"]Ņ'ͳ yĢ…³Z)Ä<“›y( ±ÓŻ£ĆźWÓ-+­8½µR—Ń<L>Mӫ̲k8Ō]» īĮG]¹™Ģa@MµB-Ó![Ō’;=Յ;ÓIuÕEū®N-­:½Ķ^ŻÓĀÜ[bż²W[Ö»“FÖŹÖV Ó«(ȑ׋½ «Ćł1+| ™R±Œ<×t»ŗüdČŃÄ$i(ćK¾†żŌA] Ь;{“·Õ&œŲK½Ųs¤ėė!2‚+°bńū(ZZæ”xØ9ܱØx“ųKhöĖ•«ų\ kō[ۮ͵½Ł0ķŁŅ¶Ö‹gY#LĄū(‰… ĄĄĄLŁ)ģ“±Ķ°ŌŻ Ņķ.B@śÜ LŚÜżĄYÕ@‹”]-ܾkŽl}Y@əœ!"āĮõõ#Ȓ›$¼ČQJ„;SŖ­Āß8Ā\łß (Ą©÷-ąĒĀÆĖzĮ­Ž:k×ce5.\ŚuC2<*4|Ē$Ć8œææ]®F£šn’± 3Lš6ĢįŖ™ÓĻzÖūģą@tʂQ¶}1ZBģ¢uņXdvÄūi&J¼4Ž}‡Aćh¾uŸ`CYųŅ I̟`ÓŅ–9MŃ0®Öģ]Üį[ÅMpŏ‘ÅȲŪ]‰bĘNZ³R āŠ@ęŪ¢‰HSžˆŁ’MāÅw¢ę ޳/ķŲUĪ®}ȗކ…śĘ.ĒčHdzyĒ’Ē}¶Ē…|~ęŗq©ˆ~؞Z苚6}–č£Xē.¦ žēʇüӟ­«”Śp½ÕrŽž®ē“Éa=źėź|xźIźh½źĢKܦ×ÖX›Õ¬nÖ\}ėøPµ~׊­ŁhžėqĶąx>ģ™VģėgnźZ ķw®źĪ~g֎åĒžįŌ®ģØĪģŲžķ¦¶ķ».ķ6ģ’JŁ$Ūģ:µŅåš^ŅoåēķķJŻķÓŽŌÕ°ó^ö^Łg^Gdœ]ŲČŽpKļ¶Ęv· _ć {Żv’ŽŹ£Vš›>Ļ˾IĄAńž³†ń-ŹįĪń“ ģéžu–&ņ'Š%ÆIߣXMåtĘņL­ņ/I1ŸŁnķņTfó÷NņęnL-Ÿó½Nó?æ,2č"čšņČQ¦ˆ°×}Ń*É!5ā&‹ņœ“ó€eīļŪC„ۈ.ič¬3/šuE؃ ™=žYGX…>īWnI\1ŗžõš^gа‹H[Ćeš‹ ˆ– ³½2p³hŲó(‰”4™x=œx'žčų”ˆŚ_Ö©¼ń0_ō‘½ļ)É+ŸęŪÅVPög_­ńH,ēˆĄÓbŖß˜ś–^&õˆ,xH'ĖŻšøäķŽł:_ō£9óhŸB?”ŖšØ,Ūß²ā•Jié¢*–ƒčOš7³ņ•Ģ%u8*g•Œ‡$üŚ~=÷Dļ‚ÕZōĄ’ĢĆoä”?œfßó7š+²éµI!aĀ™"r.š_ĆĢ/"„ł‡»‰š€!08Hpˆ˜ØøČŲčųx(9Iiy‰™©¹ÉŁéł *:Ś) iŚČ µ‰ŖŁJ +Ė:[k{‹›«»ĖŪ‹łš8`”8@š„XŌtJČÜLčƒhĮ1¢X4 P$% št­8ņä]#-~ 0>lŽH”ž>~8ŽīĖźœÆæĻßļ’0 Ą <ˆ0”Ā… >J†Æ `÷*ZDDń¢Ę;zü(+#½t‡Š‘4Įą”%‘ÅąIo,¤MŠ t/db¢Źėp¬FO(Š—B½žA·­PƒI·m;{ž zģ#ŗ™Š:2Z+źŌ¬[»f}UŲęDÜĪŚ}Żv5īŻ¼{‡tT[¬pßŖ‰?Ž\#ŁąÄ“©¤¤;yÆčŅ«[ēŃčšŅ×=Rļ>¼ōļæn‹W~>½śŌäŸo_Æ«=üłōĖŹ‡n¾~|żüūo¼ßH{śēXՀuį‡ą, 6aƒZUJ„¤Lha†x jZųį†"ž¢€Ž#zā‰*˜"Fł­ČŒ2BXb…3^Ņā:’Ųį‹;.ųcšÕ(𐧉¤† ń³Ņ’N> %CINŁ]”&RI!–ZnÉe—^~ ¤–9‚If™fž‰ęncś·fšn¾ gœrņŅ&uΉgžzīÉg%\ŽŁg ‚Jؑ€Ņwh”Š.Źh£ż%:¤£’NJi„*Bšŗ¦–nŹi§ž~¤iz”~Jj©¦žʨ⩊j«®¾ź*«ąÉ k­¶ŽŚ(­×éŠkƾž 'ÆÕ8‚•Ę2äÕ&Å>™ģ"Ė m“5ė,”Ō‹m¶¢;(Üīg#,W} [£«mŗŒ¢k€ģŚ"‘īH–¼źŽ‹ÆSŗ^¼æIƹŪęKpĮónÉļ¬(ž{šõ2lpÄ’æė[ĀU.Ėø?>œ±ÄēKqoøaĪȱÉƬmČŲyŪoÉž,cŹ3³ŒóÆ.« 3#Å0#ÅĶmL0E—t4š1v4Ó³ÕāļC•°#/Y@ĀŠp„$,” OˆĀŖp…ś˜āz¶9ĘqOšx f”LĪnPĆ[0Īwæßżp$åų›čw”©1LtųŌžŹõ‰ŒpŠv“‚s,pøĶ%d`-gŗ÷d‰AP“1šĢo‰ĄśšĒB=‘=0$† ćŅ mōÅ1‰PZē ČŹķnn|£"DR›įmć1‡ŸzJ×7ĀÅq’‚šchŖ‡œØ5B6åKßʐČCRr”x²$h0yM6"”śrQĄŲČ ¶’”“t“)?ƒŹvł0U°<$ėXĖ`Śņ…QŒ¦9”!ń˜Āl&™né™\G•ēźåˆ~YLgj³LŠģŒ4+¶K`ņ“Öä6Ļ)&b†3“ėlg7“Ls¢sžHz'[¾)²v2ӕ:¦>é Ššd©³,!Š¢ō•‚*ԁ …R@*${®E¢­ØEćDŃ“dō¢ķč—6jŠt¤)WLJŅ”ŖtE(-ĪJ_ S\µ4+3©MoŠØāt§<TMįŁÓ  UQ?IQ‡ŠŌ¤^xR§JmŖS¹ÉŌ§JuŖT:Ŗw؊լÖ3ŖZķŖW7dՎ„õ«d-k6fÖ“ŖõˆZ«[ßśH®Āu®tĶg[?įæ…ŠšZŽČė’ųzæźu°ül"‹,J –°VŗÖbbÄŗJj¬’§1géĪ~2Heńdē"ģ%Y'’Źu‰<"-2…x©Ķެ³©ōdĒBėÓŃbÖ:ŗķ8¦Śj¢®“·å,ls%ŪÜ®J”–å§@w»Śrz¶·Éżķ¢(‹ž³ŠŠøŅż¬f‘«[ÖźŅŗÆuīŗ‚‹Żįš–—Éd©pÉ«ŻiŗÖ·Ž•#xÓ»ŻŁŹÓø02m×+^ęf·½ī½k8FˆĖF&„Nšį™ĀĶĄ`GPཐo™¬Bå&1vą/øĮŽpŗŠæūĢ“õ:WiĒZģqŃ? —ö`³~ó7|Wš×OVžŖļ,åDŒœ‚5É#df2Œ­ķq׊šČkĢ\Ļß)§M¹;lģ7!ūZ¶°„āE“iŚ9k®¶ŅłÜčN÷¼$^µŸČč.cÉ9=ł?=¼Iml}Q‰ä:”²E(«}e÷Šnõ Ėičn/nŒÕˆ˜@nŁé(Bņ*ć’p@Z@–«n3£ćĪ’”˜@ļģĄ”É9lgVsÜŁ˜ūTčœdĀ‹'µać=o·±.w4Ń}:Åõbaįʇ ĄfL@µ™9ą…’xOł«šd'ļ#uņ¤{]ŲQde,įŹ|ƒ„ ŒQ™Ź§‘tšś§=žś9­¾ū(WX±©uļƒ·^Z܅M[ļWõį‡*Ćē{±óåų½?’7Ž ų'yłē{±$uõ—&žlļ7,U&€ X~H2†·_8w‘€yR_w_h~ųuųLčiHś÷xuĶ•‚Ż"‚’g‚B‰‡‚źśē×yĖ÷‚—EXƒö‡VBŲ€:ų€<čh’“GH‚.8„uƒŸ•pĘņ uUHpЁ…Ė …N’>]…Ćtch†gųƒU…†kˆ†-x7l‡Cč†_‡uXsč v؇©‡‡·‡öX mˆ_ˆB*F†Eų‡į‚O˜!}ųbįSøˆsՈAV„$‰“ųV•—(~™Ø‰kʼničK˜X†”Č_£ø~Ē•§ˆŠŽ„Аø‚®øUÆųh±h óV{%7 Ģ–"ĘŸH‹¶ZøX ” Ąf<eŠŠHŒķeŒęChvh}k—·df“`:WC„ę¤!9„Ę ¼–hÉ֌éōŒ©č‡A §–” ‡ cD1 Z$}‡ H€“Œæ/Qr DQяGGtēˆ%²˜Ž:³Žšg÷vśĘ<—A8š¬EŠé>'}z˜†FIx ˜ˆ’踐kÅlś€nŌ“.1ŽG17łFl2WC(A~”B“¦7:GŽ7ˆI¢˜’e„1ŻKt•OŠq ö35Aó•9Y>fóą=GyQ ø”BՔģ•fŚČPq Öp37Äm6ÄIz#zTEīĄŚH9i„ję(–A’”§U–L K•ęƒ«ØŁ:Ę@!B99k=!?yGqīC)”H‹`ŠwhY6‹¬ˆ’…IVgÉī~3xM„Y_d‰š;„š‹0{ ؘę˜ä䌳ŁUµI˜MØ$°©›½é›Yœ4ˆƒHœ©5ŒĒéTÉŁ{¹éœ‰É›§ X%FH„ø›ÆłdœŁ)UŪ ‚ģgą‰ā9žK耯łšß©„ ©žČŁPOĀ…†ØWĶéį™ Ļ‚ŸN‚mžŁ†% ’©BƒX   Ŗג  : Ź „Ÿ”‚ŠƒŲZĻ Ÿ2Ȟ,Ÿ1(€č”–č‚xč! ك+Ś:²éhQ‰ƒŁYј_&:¢īłx,Z)0ڐÉ!£Ó©£võ”˜õ£ĀIŠÓ‰e„‡–®™£CŚ)<ź”@(ŸÜ©‚FŠx!ŗœø™¤Yښ6š)[AŹ„ń•ž]Z£"z„ę餉¹„LśO( ¦“užķ¹”üI§9ø¦HT¤hJ£Rz¤F§ź)Pŗ¤U’:„%ˆ§Vj¦{š„}:‚^j¦Śusś)„ ƒxØ ·’—Ah4Ē4@ó©Ģ@ZD{Fµ|‚1d—a¼Ų¤h©’ bZĆŖłVb³JScź€u™*–Ć&Vq*ZōĆuĄzJ. @vÓī³ $ ō3evfŃÕKzƄŽ˜vF&¦nډ –MödČčRÖśŖmĀIĄ×ZY‚ś¤^7”*¤eZ­„:$į6·—vS ŸCÆW…D…¢öfĘPƒ×«~Š«H螣ć9 ÓgqFšēągch}Wä'®óJ‚„v¦Ę`ćÓĄ•·€<ˆ&špv #’ ˜šŚ®Ė®ŁŗTŖjŌvµW³Ó ä6ķ£|‘ˆD5«§1jsć|9©yŖ\")ń>ų8 µĮe‹¹9¤µh»o¢¶›«Žŗ˜! qņ»AŪ`(ab91·;7ąV¹±›™uĒ®|{ŖéźŖdš…˜nys6ż¦r ą¬;Ü0“Y’ę’X—~ačmXGo8'¾vņ¼R¾LfA黓†`bA!s3“»ø¾žĘ’³½‹Y“JĮé ókbėƒs9ńM` ęęP^”c;¹ 4”<”¤¼Ž Į±pvZl1¦d«ÆœŌąø¤)¬ ܄" Ӑc·aNk„Ł!vž'»aģš7C•#Ńq¬'¶ ˜‡¹Ś¹9ü}6ü~—ÉŠv8qĀ V *HƒmĖ‘¹›MĘŹ :ņ°¬äĮ4šžšdŻė¦‰‹ĒE{ö(Ē;£PFhģ—˜‡ MnY}MA±l)2f«@6ŠŁį—O`ū8cwx Ēč ļƾŌūĒ-Q}1qy1›:d°jÜ¢‚+iœ‚“|wįģ`|+¼ˆ¹ĘŒHS{®V¼į˜…0¬kń³4­KŖO&¼4:ęG¼4™)?üZ š3rܧ²Ä÷Ź_¬ĆŖCF«ØĢ꫆TšØ)8—«Lķ'ĘÖŚ¦Țćz yĶ…#|œ°ńš©7Š©8ų®ż‡„nz›ÆŠ£N„ó,Ī–ąÄ/=,AĀĖ«^–<Ķö ŠŚlš­°ß ©»Š¼É=ŗ\ņz§Ī£¬¦Ża ͹<Ģ5Ń£Šu*Ń kØķuŒŗĆŽŚĪõ|¢ŻĻ ŅėŒ›#½Ć‹Ļ®›Šq5Ó ½Ń8 Ķ.MĶū¤åœÓ©zѝŃ<ŻŠHØ=„ ÓŻVĮ qbH…QB÷iŸSmÕAĮ`č…[½$MÕN]ĶóiÖ)eŅ1}ÖkNHiMĻl ׌äÖ:×uķLs=Ńv­×q„×"½×ŻD}M¬€MŲ#Ų”\Ų‰]R²©Ų=1ŒķŲ‘.‡½·’mŁźBŁT|Ł›ż*=™Ķœ ŚbŁ”MŚ«3Ś„ŚƒzŚ©ĶŚ;ŗŚ­ ŪĄ%бMŪ3‹ĮµŪ•śŚ¹ĶŪW¶Ū½ ÜĮņŪĮMÜgĆāŁ]ÜÉķŪ³­ÜĶŻŠ·ķÜэeŻ Ī Öüp°ź%½Š”×m,Ł­ŻOŽŻķŻƒp”ä-ŅVÜ“FmŃŪ¬Łö…ŌI=Ųź ĒķŽ6ķ£• ĻEMŅ«ģŠōŲöżĢ!]ßPōŁź××ņŻŌ’]ÉCķ×¾®¹P0ų$ŌśżŽß~¦;M×ʶ <ßjMŃN¤5-ąlzā’ …">į³šחt‡į)®į%Ķā Žžķć.ć  R@ƒ’ƒćA­ć-.¹šą'żā*ĶĪCžø°P`›‘äåaAć °ē £Źt‡Ö©pqtĀĄÉ{\Ø&ŠŖ «J ¾ę–«ć;bµeŽ7¬NåoH |sLĪĻįätŪ07ą0l³P4Ézä^[?ŁK‡MH­DM Ef r~©nŖdŻźdõšēņŒĪ*Žēŗ Ā05Šįƒ®©S;›Œåąs}ǰ@ėY³wĘŪK¢Ģć»k®Ÿcą-Ó¤īā>c`ĒgĶFuĮ!±ęŻģKq0k’*-Ķ«^ź~ž 5.{OĪ?­w6Ņv ›< šŽ.»³žHr±ōezŪ„×ž‚Ā’# “_Ė“ĪēP¾JĀóµiĖÄō(ŠÄ‘9“ ķˆhļčļ5÷·GŗxąŁ®äŽŠ®Łš`Ż·I;§ø»’ćžI‘5µĢ<¼öjGĞ*÷ė5ńo“+»Ė>£^%ē»-4ļ«ėŗ$¹Hź°śöł‘«nÅ{ß-2å­ōKĻōMoˆ±[ńU\~Նw@k A“åŲw>\&[#éyH?tLÓlģśbjąŲ׎Ąr8ēæ0'¾3÷“5“ lź$ś|y ń¤wźźüĶ3\~GYHNCnŻP4ü‹€÷É`¹IČĘ£u0œĘ€æö>s*,ÄkÜ÷4œv7›_ķˁō0¾÷ŗž Œ§ö¾O…ĪĢVČ0q½‡¶«G1O‡ś)ļ ¾mCröĻkģžA!üBqyԊś›Cˆ”7jYvo|÷0īšł~śĮł Wž¶ų’uGÖÓœœÆäĄĮüŪ™FSCä_ķ–ČėMĪŹx··\łĀŚųŗļ˜Qņ¢™‹MR#O5……E„ˆO…š›œžŸœŸ¢ ‹„£ØŖ«¬­®Æ°±²³“µ¶·ø¹ŗ»¼½¾¤¹ORRžĮ’æÉ¼Č²ĢŹĻ¹ĪĄ„™ÆŅšŁŠÜŻ”«Ū†×ŲąŽę®ŁįEʰįēļšńņóōõö÷›ī²O ßųęéS50 4}īÖµ+UŠ Ć|å@ińa·t ŖQ“ȱ£Ē Crl«5“‰|F2ÕŹƒ{…kłŽ@šÖ\ęrĪ@ƒ Jf2, š³č“ZM‹ÉTT©>sFӊµĘŖ]ÊKėUVM*K*ŪXeź|kī¦\Ŗt­öŌu6Æßæ€Ļ}öÄD_§g›ÅĖw°`_vĮ:~ü5ėć˘3kVŁ-ĀęB‰?CD„xō^ŃnoU-ørcŌ°PcĖŽYzöiø—rėŽĶ»·ļߥƒ Žˆ ńć3‘+_μ¹sąąžūŽ.½ŗu磮ė¶Ķ½»÷zµæƒO¾¼łóčÓ«G¼žVųöšć˟Oæ¾č÷ußńŪßĻææ’’‚ąThą&Ø -śu׹‚F(į„ö mVØį†vč!>Źā‡$–hā‰(²2"l+¦čā‹0ĘØ`‹÷Éhć8ęX"ŸńØć@)¤_>jVäH&©ä’‰™“LF)å”T&]%eUf©å–\>tek]†)ę˜dŽ…ą—e¦©ęš$¢i!›pĘ)'—nžUēœxę©g{węÕēž€*(‹3j蔈šąŸ‰6źč£@1Ź–¤Vjé„÷PJ–¦˜vźé§æp*–Ø –jź©^)ŠźŖ¬¶Ś©]Įźź¬“B*«T·ÖŖė®€ęZ”Ƽ+¬šĄUģ°Č&›å±A1«ģ³Šé,mŃVkm­ÓÖtŚuėmp#øĀ­·į‚2ī·č¦«.ŗå–r®vķŗ»ī¼ōŖÆ&ļ^wÆ'łÖėļæ’ī»IæÕ Ģ ĮźāP㢠öˆŽ™¾—dz©jŚk“™8Ĕֵ’š™ oFŅ{Ć8±e¤-( ɬķ˜ń-¶˜-ĢodäĆ$qĖ!§\óx9?•bÉ([é±Ć §vsŖAs¶³ĻEWœ“ĪK"ŃUwģĶĢ=šČ8GMõŠ<+żņ€+sńÕg›­õE{Żõ“ag=6ŪPŪ½¶ÜBė}·ĖVƦŒĢqųõŅ*Ŗ}1Ły Ž6€i7½øĘĻóŃ`Omł'›ė–Ič¹Eš„’ņ挱GRČ!O~ÉėÕķ‰BmŻ6KŸkBīņģ÷ß±rI$Ćм'RÄ+ń“ī‹ńØH‘ŗ*dü%ģ8O=yX;žöīįÆž’É ĆUx‡sŅł8°³®I Ļ/æē×č@ & DēL  °ĪFI\Fd×;ėĶB{ššG°w=®ČāŠČ'(`Üa.‘[ßPA€ńyĀ$³ŪžłT9›s ¬"®Į»f†k"‰ß&Ō·Cū©Žąak ;!OvAó`Ö 1ŌøNxu•°€" v|`_· Ҭløā? ±EåcķӄĮ€ļ!Ѽ#P.ö}3”"’ĻiŸPR¼7Č"‚”‹Ä#1G-l6å« K@1ÅC,RdZę@ę6M °~ćĄ*÷7ŒčŽ0+ Pƒ‹8åątljPŠŅš *ēČ.—„ŌH ŒAĢā”qseęüšiĢB,‚ŽšXf™Ł> ¬Q)öÓfd'c˜„Ą³%:»¹½&³”#äDŹE…©ތ%!ęA B™Ģ€ ¹“É3īņ”|āyy’†D‡¦¼¢"a;>žS¢||)jæId1Œ%tÄšˆŃKjRžØż~ĻMX"|R ÄBYĆJ„ ‚1ēę»GØEŠū „ņ.ŃJCüĆup„Gó¹ŠŁC Ž0%ŹiŠ×E Ŗ…|§{ЈTCHŅŖŽx©šYŸ`¤ļ‘Żś?¬×Ć)>ŸW<ަśų’ÄŅżp'ž˜]9£¢(ĀĒś`‘źS¢Ū)9­ŹRŠZUžRĆ÷=BōVef‰ĖX6B›æ{ÜōżĪQG€™”°D ±yŗ©"¢‰O #y'kģšæ¦>õä6ń= ø—سCDX'ŚkP?BŌ®¢”WśgÉ]zŚ ¤ö3ķ„bŗŚ’±°™#&ÓŅFŪ;Ļī3oh­³Óö¶ byĖ܁qhVļ›očŽoŌQŚÓ7‘v»›?†”ēƒÓż!x×Ķm•Ąélšč’²ÉtwžÜ&{ūąūIųIī!‡/\Ļ Ī8üŲ ¦qŸœć ÷øæ‡­nTcœä"29Ä+ń~zćųĶmóʍēž9½Ó[r<œēP'šR·gĪm—ļ\ą.bņĖAn„³œęEgśÖ£~Č7żüé>Ē÷Ų±Ī8§Sķ†ćŗÕõ½)·[}é)æįŌ½°¾+–ļßbˆßOųt'š‡/¼ā t%~ń|n­āx–ōż}5æ–ę7*ŗŪ–ó }„<ß`ћžō‚"żHPĻśÖĖIõ½ėgO{ķ½öøĻ½dļŽėž÷Ą—LśŁƒOüāŸČ÷A¾ń—Ļ|j æłŠžÅł&żź[?īĻæ¾ö·ĻĀģs’ūąĻĻķĆOžņ£Fł™2æś×ōŪĆżģæüįžłłŪ’žut÷>ž÷Ļ’_Oæ’€5~X€2ßr/(y hQæB€Ć1š's„÷˜Ų5ht‘‚:E˜Äś'‚(HjӁv·z'˜‚0mX‚ų‚1xƒāĮ2`§w5ˆ8ųƒ2˜5NŅ<Ż“|&’čƒ@˜„9H‚ō@aé׃ԧ„Rø„+ˆ ßÓ>DUvō-H4 D¤p$‰PG$G…Sø†Ā„Ÿ€K…`ĘŠ07]IIJł‘æ–j 7”‡xŚŠ€ č“6“kY—k8ū֔v™ ˜. 6} —‚™€ZÉ!į˜śr—I·—ņ ’R–lI•¢‘@§v’Ęā˜.8uły…łvŸ¹d˜9™:Ö{² ‰–cYqB·˜£!š{§š)—r™š/ōš*Sš›¼¹ƒG›­i›ė᛺™›Yé%³•9GœĢ)™*xœ_i™Uə2B™hg#(ŁĒ^Ų¦Gų„«ąg P„ÆÅ<žń<=›ĄZ£"œ¤™nąY™Ć‰pÜł|ž”Z44q«‰ˆ­Ŗa=öŒĄA’ĘŸo÷FĻYĘyŸ"L©ćIx5 Ą •‰ōHu†iōH‘K;”²³…n•Gķ£<åR X¾f¢Źł āpžõrŽ›PxEžż9—1Ń>õTGģdoDXßÄ ā“N–Eśc‹łe¤•€„NDڤ1ź  #[Jr>Ŗg’Y9:Ÿ0Ÿ«$q¤1˜—P ]5ņU Ė>®%:ti]Õ_ 1ˆœČ ĀdQ•VTu§v–|jZ؆:yŸŠ wÜB—cšČGĶ% Ļ%£F©¤q$d¼˜l– ń%Z³‹¬Fsz _Æ3<Ķ6Q²Y%źP©wg©ĪōØ¢ŽŖH]Ɵa*žØˆAŽä„`aśÕ^™ąK¬Įu‰Ö.¦`Ί¬Y:%įąō ¦õE«µ 3E?tm Eū³f–en†]Q;d^’ƒeńøeM@@^† ¤A(4SäŗY¹,„ą­ )«×Š­’MõD5j–4 וĒzH{T`‰ WÆVG±†lŲŌ9ģ <ø¦k%ŹŁŖTr˜Ŗ Jv«į ¢»«Š ®:ŗ$ŪąQ¬i­ŃY²8Z j¦žŹ #ŪsH’ 8«+[œ4{™ČŁ›Ėł±<뜐:“öY“L9å–“ß*“LŪuæé•Žj#:³[®Yµ¢é“X µ&#µ9Ū}^»(¶zٳd“&{¶K6/#qØtūĖRy\K“p»·ˆ²³eĒ·€'~+–[øÆ—µ†›øŅŠøŠŪøJ2øGēø’&‹w“{¹śf*¶˜»¹Q«¹œū¹x³¶ ;ŗ9R¹_7…ˆi¹£uۺıŗ¤{©+Œ[{£»O›–‹X»2Kµø{°¢›„¼k£]ū»łź¹8¼J{¦Ū‘Ķ;t»Ū¶ä¼Ę˲b½$;½-[½²¶{½ŠØ¼S»“Ü«”ŗū½ŅźłµćėŸČk€ą›^?ūÆė ¤ŌūƒļūN £ZųŹ•ó»5Œ«÷‹j a‡łd Ž@­wöæļ𼊩„ücD‰`4N’0ØāĒĄ'پźWŽŽ…[Ē ’µŖŽąž_JPĖŃ„|u‹ƒĮ4§L’z‰…  œ+L¼Å›‚/|¾Ÿ ÷:ƵE…8œĆį+¾1ŲĆw²š 0‹‘ Šj•·Fģ¶øH ƒJœHLĢuLÅ]YÅ?z»7˜Å»ĆĀ_,ĘE Ęa¬¾Xģ i¼«-\­j|ĘhÜƶۯ»Ćn<Ē]ģÅHʄ{ÄĢėĒ|Ąņȑ»¼S,Ēsœ”MK ©ėŗ„¹ ‘,&Uɒ\ØƒČ–+ȋüʵ€ÉĪ»`ŁĒŒÜ»aĮɧkŹōĀxK™Ė»AČLĖOÉŹxģɾØĖp¬½5»Ę{r9Ł{•ø “¼œ wmM¦Ō£­Šāu ƒDĮ¶ļÄ>I½Ļ0t‰­S{īŃī|ĖżĆĄÕ®ĀŌaJ0F$ÕÜŻl°Ū³ČčŹÄ®ü8ݵēLĢŲ-¶įp:Ȇh—Ü„ZóóD×5XŗńÖ›Ēu}Ķq°ęS ėæ­ēhżŲEÉŪųÜŃÕ#t(;sŲ,įœ²¶ģ”Q· Ł„ćN­9Ł®·“g«fģĶŁ4ÓL’šĢz0¬Ó->J:ĢĀž{3^Ź5^ĶTķÜ>{;Ž•^ŽĀ÷ā6—ćŌ-½Mß-ßB§äļĶäóP]ævŻ,×å1ŽzCŽäVž¹m*ņŹĄꃩćd>šEŽČlī½ŁŚęp¾åqēt^Ēå[ēx~Åwžē|N>†Üē€žvŪ脮~^舞<_žčŒ.׋Žč®čƒé”B‡^阾kžéœnéÜé nšŸź¤¼“^źØ®é—žź¬Næ§Žź°­„{ė“.ź^ėøŽ½oÉfnɬ ŹĶqɽހģĢAʹޜNŽy?ŽĖRīČ9ģŹ~ėŠīč7ŽŽüLåŅž™=īĢ×^­Ļž×¾ķ Śķˆä/™ķĆLīńIķā~äߞįŽŪćĪģ.ļ®īōlļÓžźśžā ½Õ„ļŹž^ī’ųĪ B$Qś=XÄ׹#ń·Ó9Ū£ßiė`Ö­å­EŖķēØvŲŸš÷īīf©?+tO»G0Ņ­}Å?ß}ӷ׈ 2=Ä„U&~å$oē³KšØD°õA‘Ęb `jėXDŽńK-ąÄ» ¤Õ%*ՆNtĪÕ?šV{_€ÅѽJZ¤Ņ%4Ö¬ŌOMŸœÄ›õé.„l}Oæ}õ0WąĶ¾õ]oņń,D½6PI”õ«ƒŠH튣­öm#ņ“Ų{ŹŲ`åŲ0×ów÷å< £žQ&DDbó/ÖQ “öɅ؝€cžĮŸpZ«½Ŗ:ß#½1Ūķ0ģ²?ūŃ“_ū¶ūjŗŪęž]ļõ„F_Ü ŸcŪ%śdg«äĒRL`6Z Ńŗźó”?³³^m(ÆBÅh åņżŁEüżnŲl䄯ŽWÜńłĄßčż@ļęŠå?…ƽ–:¦6iqåk‘I¼v扊ą€PŌ!€ųTøČŲčų)9IYi¹(š˜)9¢xYøł):JZjzŠšŖŗŹŚźś +;K[k{;Š»Ė;Ŗ[śŪ+œkĢ8€CjŒ9ÜÜk¼\8Øģ\m}­½ĶŻķżżė >~)^<ś„ØŽA~^i^$å+iī>ł”L}ļ’0 Ą ā²gBb [-\(JĆĀņ½šH1£Ę;zģˆńcÅT!ExK¢Ik]•\ 3¦Ģ™4k:zió"ɜ‘PźģÉóVK‡A‹=Š4i7œJķTźÓe½¦?1J5«Ö­\»Žō*ėźÉ¦Q‰bėōkU“lŪŗ}kP,\P$ף½‹7ÆŽ½|ūśż«®ąĮ >Œ8±bĄšė 9²äÉĆäεL9³ę͜;{>ŠłmčϤK›>:µ³ŃmY«~ ;¶ģŁÆ]e£µM;·īݼ{#Åķøļįċ?NN8Wåț;=ś)ęZ©KæŽ=»öįÖ©vß>¼ųń”æC%>½śõµi›g?¾üłß’¦?æžż1ķƒę`€čŽFH`‚ .ø‚ƒA9Č`„N„9YHa†nč†5yČaˆ"ŽHˆ3™HbŠ*®ČŠż±˜ŚŽį5%2ΈcŽˆŌc÷Ķę¢¹fOO ‰¤MFš“d’õ„DI“¦Héd•«P ’•œåGXj &=@†™— eIfš}¹›jrcęT¹łfĢ’Œi'\qžÅy¾égCžŁĢžˆCA;‰4(”`6Z¤ŽībØ&śš3¤“&©©@nJK„j=R Sˆ5°# ",B" Tó)Ø0Öś®¶®ÅJ‘‘Č@ „¬j*ó0Ą£³J1ĻxRŁ®ŅŅźŽ“[‰jU$R,;k¦ bźķņź!ó°dmŗ¼čz»ź:+cłÉ¢‹J1® ²Ī·H!Ąø….FĄ»Ÿ›»ÓõŽTĆO'H¼HÆ`Į,+²O!“sH‡(Ā,µÓ‘ĢóXxö¬DĖ šlZr:2M óØ\H©…š+€'  qĒ;½½°Čßhż®ŠŚBQ—szŒuÖՖ½¦É1„Ųh¶v×gĒ—ŚŻ'Łt§ĖõR{ׯ°Yx·©÷ßŅö §įOŽ«Ūy_­ø­ˆo3ł“^ójéؐG¾iåŁˆu£Ž¢Ž6’nś#”“Īz룧~ØŻ‚óIųꦬž#윫ē96bõN{šŖØō™ÆŒ_éxķp>ūī¼Ļ½üÉ#/|™Ó÷Äz”®oOÆķF7ļį Æ¢Ą,OŁJ°Į²`śJ£kŃĘEȰŠqlÄ4"@`ŹŖĪ(‘SJa®˜©l¢{pąHą°e»\‘ؘś'$b)I5‚s–j\‡ī®$Æ_+|‘„ {)Cq=Ķ_dįž?’ Š€Fz¤§@ŠŠ„*t” mØC[EÕüīœEÄ.·(aV1,(u©N.Ķ—Ą“dĆ(»Q=ĀŠjK”ʬŲćģóąÆPšŅj^’'ƒ…:’шČgQ2eĄ×©¾øHF‚@e0ŌX³ĘŚc¶Ī©±NŠ14% }ŗŠJHTÕŖ:ÕĆśS,^ŒĄAÕ(šMŠ‚ō—i iØLŗˆ^RóŖ¤2Y}ÖĢ™#‡^÷ZVčš4ZåSź"5N®c…ؚųłÓuX`’k„¬ ķ2MS–d% Ņ–6iBu ‰ÄK¼&šgĶ)żd«ZĚvKƽ)+g{ĒŚŹVéøKR?‡×!––a,¬6#j[ąŅv•D ŹlĮĪ,v‰ü“np©»Ü ÷·»aočŻāl÷>µ®&ŪĖWķž×‚!靮l&zžó”×gĶ‘ūźŪ!įź×µ-såėÜż˜7Vė]W] aĮ®®pŽ^›½Ū7aī°‡QÓ`J}xÄ$6/xKŒāGĄ*n±‹ÄāĖxĘ+ ńAhŒćŸ(Ę:ī±bc”üxČDŽ‹Œä$krĆJn²“‘{ā'KyŹw2•ÆŒeģ29Ė\īrc%źå0‹­° ņ˜Ļ<)3—Ķln³š«Üę8‹łĶ•D6- ÖlÜYt`ݳ…’|˜<;ĀϹ“”ķAzFŠ•3œ]ߨ»ńå-™!8ZF=S·Ž&’%¤3½ä­Qštžć¦/MjA:ŗŽp™įK>|Œŗ¼šĮČ%ÅDL·śŃV/{“3ė[šÕäÆ‘Æ ė]§ŌRMvؽqėqŗŲø^µÆ•ĶąO«TŅĄŽ/³«kķo;Sį.7¶_Żkq_CJŃVŖmģŽ÷Ėē&Ī·¬īt®£Ykl”ģ"čyk#ó$¶9Ž˜ÄŪLŪŌ©¾„-ż†lG6ŚÜõNͽé ītBK\čŒ%[ÉK9IŠ1¼ęĄäČĮbė`Ē[ƒ¶=z튧[Śō¦¤Š@ÉXF5ć‰ÓVh ®zRc ¤š(ßMoa7"^ ą$K‘p!G<°­ŗĢDusq‡,š0rMē:ŽĘ+ŃwįDÕsQOß"“‹‚`ęĻh˜”¤ż& DeŹć¬/“¦AÉųĄ ~š„/¼įõ‚’MmWŗ•“%) ŃøóšBł/ć¹ŅqOnUlŸ„%6Ći=ĆyŽ §±¾Ÿ4 ó«£ū¾Éž8ŲÕzvĻs›TŸŗ8X €E½Ō.Uó*Ņ©Ż÷€MLøųs+{Õ³~ęČŽ¹>%ٲĒĒ>õ=Åźō#½ųMfÕeåŠśm’łĖ BcĘBÕÉ'oz¶/\łĖo’ēÅ.…ŖY Œb—üģåhł•/°Ķ*Ķ„/Sė—Ėp3äŌLć4!gu~—|ģ×Ģ÷^‘75Ppõ'€„ē‡õ{ŃpLĒr.Ps}Äi‘'@Ń05å"sjTgų€īrÕ'k‘PyӖu z… j!8n 8·‚ƒĆ¶eįGƒ#CPؗo;8)÷+3Xmw~ąW„`é7݆q@ˆ`:øŖfu3x…X(ƒłĒX5Ų…N(Pø†ādDˆ}ex„«‡„i؄oØÖc…(†w‡tx„9Økhø…jh`{ˆ?}Hr؅†(ˆ„AˆZF†‡˜‡‰8‰«ÖnAųˆ/‰īv†¾h’a‡rx‡„Ų§ˆŚ3aŸŠ‹³˜X™˜t“ˆ‹Īc‹Å–‹½h8»ˆ¾(ŒeŒ•8ŒĒČ3ʼnČȌ£ŒžŲŒ”±u‹Q{‹€;¬č:ÕČe£ĻxŃų„*džßēfŠēnń_įcqʍŒXŽ‘qŽpč^g¶Ž`ŲŽzŽšx r6ŌWęxŠc¶MŲ‹Ø‡č(‚źHŽÉ]ųłØYȐuäLa/­Utēht ‡‡h6r8‘ŽńbĮU}÷v¦ŌZؒ„ ¹#€ŁuŠ-ųb€Č`FFWt½7|n„üP…õ-=)b’‹0y% 80+‰Y432„,©2M, WINKć“1“•Ē’,)ŁlHY‡JéŽL °-M`NuW½“(ĻgCä+š45bvń½ŌKOõ4>Ygć(‘hY>4wńõŅ—•ć2—OS)čF5W†šM‹ĀI4™˜ÅF€DR’ch˜é(’?ˆš0ūrY§‚)Zõ*5@SšŁrqIø›Į¢eɏ26š€Xš¦Iš/h‚ßō”Kó-ØbC‚€?éH“Z.3NOd—03«„w’ˆ9ö›œbR8J&h*«rzO3«‚‚‰ }Œ°*ģéQJD³13Ğ7F3֝sų™?=hŒj6ł©ššū™łĆ6’¹ģˆcš}*œĄ ‰Ź 4ę ^”ü9œH”÷é›o/™”Aӛ㹠śbŗ!Ź$#JšŹ¢-†¢ųØ¢/B¼(£ŗ” ¢3šSŒ.Z£?£É£5&a£ŲPŠŸ;Z¤ņ–C C*„ģW„ödTś¤„¢é¤[Ŗi ā„… ¦ŽˆWś<’dzIJś:Ÿp3Voʦę}…:§3§„Q§):E„ §‹±§f£¦Š£ڈ’ŲV89%¦ö¹Œ‰ 2Zz‹4 *7šn˜ˆ7*¢Š2ĮČ©‘ ¢ŪU©Žf˜j?†:$Ś©Ęų©‚š”&ś6A*…„ ©ćµØŖŚ§øś¢|Ŗ¶«ś©©aŖ…X ± «"䩵z0’j£21Ŗzx©ŹjG·ŚŖŖ¤«² 4Ģś~>4Æ÷oŽDy“KYŁNėšV¬Č'[G5©pL*«ńpPz¬ÖD^UÆĪŲ«B“FāBI…D‚ϹTķä Låƒčś ,“›ZrŠ¢\ļZÆĄš¢H'ylŅŚG–7„§¹+ŚzÆk¤,Ƨq6(®jX¾$ž™°äD–¶gƒ0›DSG±-ˆL·“ HØ,ˆ­é°u°„ŗ7’Ės…D4šÆ×H0T+C+u²[5* @`9 \‰H%:³Å 9ÓBVٜ¹B #¦3Ȁ]»±ÕRYnå¶8 ·o+·894 åxŽ'žluQŖi²v±°Ą0· ·Ń€ÆÅ øneXš'C€,ž RА+¹‘K¹“ 0)a¹•K¹ā`.‹p/LŲ.™+ŗš ¹¤Ė5P“ŗØ«ŗ­ĖŗÆ»ŗ±ėŗ² »³k»µ‹»“«»·»»¹Ė»æė»Įۻà ¼©+ļ␱õ€¼«K2Z:6“ŗ#½ÕK½×k¼Ś““I {";W8$œ“Ó1½åk½å \5¾ `¾’Ų‹(.æ“)˜PQ¹’k¹öŪDRæ‘k¹ö0ķ 1šÉ(ūĖ,,ŗ“[Yp«ĄnµĄ7ÉĄģĄÜĄ Į,ĮŒĮ¬ĮĢĮÜĮģĮ! Ā#·’öĮ\µ %ģ¶yźĀ/,:ūjEu’„)y;²tTtµfxUøTkƒŪ÷W«”=»~HtR@GZ¦j¢¼¤gÄĻ+ĆL»“’"ó°M+TawE‹²Bkė é»2C'3’w®E¬±`ĢƹLS—Mœ&‰{­ś:Ø WˆRyĖ{{Ū*.s+‹°l¬²~ø6Ø5Ÿ«UŸ2žUl«öJ‡psPÜ.u“Xu,7w¬FJl7†ˆŠtžiˆŌźÄņÄŖÉ8Ŭ°“v‘Ę<›~Ė+±ŃŠt :Ź”jÉX•¬R¬ÉDź¬łŹ² ¬¶„¼Éf&©\ØŽłÉ4ĢįHŹs¬Ø†¼Ė¢źĖ'ĖĶ,£ĻL&ĘÜ3D[­šó«-xĶįģµŚ\ĢѬ˯JĪČŖĖ Šė,̼¼©„ģŻŒĢ\ŗĘN8ĪQ,{ęü(č ŖÓ Ć3ņw1Œ==Š­#®ˆŠ‰¹ĶŖų‹_Z¦]!MŃņ§Š±³EęĶ}ĪõģdķŃZĀĶ!mŃ#M!%Żd^"ŅN¢ŅJĘŅ-$/d1-Ó>BÓHfÓ7}+]Ó'ĶÓ ’Ó ŌAM ¢‚—W¶ÓF"†R# Ā0]ŌL qņԈ@ÉR½ĖTĶ \rÕźÕ?½Õ\=•õPrWae~µŌd­^÷×+āda=˜©“ÖlĶnM=pÕ)Eum×½a!ĖąÅx×rj=ÕżĪĻ&Lb¼rŃĖ×%ä׊uxķF¹ÜĆtŲ”m„Œ=ȎŖŁcĶŁƒhٟµ”­Ī£ Ų„=©XZM“­Śg٦m ŹĢ²Ūw½n>=×|QŪ¹m†ņ“©®Śø ÜŁ¶n-ܾ½ŁĒ-¬ĮĶÜ¢ķÜ&bˆ-ŻÓ͇խSæŻ·M«ŪŻÜŻŻŠŻ×į-ŽKŚą}ŻēżÜ²ØŽ©ĶŽŚ-ßÅ`m‡ń½ŽŒŻšmߥœŽÆmŽūŻyżMß1ąĘż…NŽīŽóß®ąŽĶß ^ßĪą^Ž÷MįäŃ‰p ±į żujŪ‹MąN£_ģ£ā…Ķ®źą&ž8(Ļ©ŗāĖÕśß.¾Ū2ÉĻ'žćĆŻ6.ǧjØ6ö¬¾ą>¾¢8žĻi3ćv¬ßFΉ@މB^ĶhÓćN^ÉHž£½¼ä™ÜäVNnXŽĪĶ0Ƨä,>į^>ĻĆ-ĻMB± ]ę4Žįh~ć0¤SĆ9«—‰ 1›E§2õi”©ņžątÖ)+p¶ćC[ćr~”tžróE[)|Ė”*ÉPy1sœ‚@Ca¹•c¹ZÅR•ĖĀoŽz#Ž_-ĪčžņfūL9“3›÷/¦ņFņißņź9C—ÆRDg*ø×¹™żęL’Žź©® ˆ™h}aŚŅx‹Ņęõ/+$Cš)ķ6c¦bTĻ2¶Č.:¬®čqNģ÷8ŌĄŚę§1µ©šģ ×ÉēžŠ čĘgLG». YM¬”7Uī®ĢĮœ¾q0’Y5śJÜN52D,I±ĢIč³U(ˆ3†ŻŚ§ ē]¾ļž Ę'ęS·—)ų,zÄ/••*X]žßņIēņžQÓøMSž”y‚Ąåł¾č_‰&čŲ”!Æ.ć ]ńĆNó惓üĶKPźąøOóT>ó?ļŻļ:®ęmńLOÜDOńĮ^±_,õ>Oõæ¶ń‰nõJĀ›ß>õ]Oę4{õYõIOŒĘKoöÓźōažqo9n’öĄŁ:Š āŁD÷‡¢¾÷4ā¦wŚ”g—ų†p‰oų€:ōG};„ļ_÷¬ā1ły9޾” łiöü”ļŌ¼āÄ#ąj­¶¦>ižõ>Kłb?ś_o–ĻĖØ’ųņ³}? Æ?÷“Ośßżłhūœū˜Mūģś¾ü±\ä¦O¢iIü’ū<ßłeŸ²¶ūOæłĖöņŒßÜ ÓÆõBĶūŲļū²/ŁļüŹüó!žQOž’ÓLQū&°Jõ­ź0’…æÜV R„…†‡…ˆ†Š‹…R“Ž—˜™š›œž‹›”Ÿ™£—¦ˆ™O¤Æ°±œØš“²·ø¹ŗ»¼¼¶¢ŽO8±æ½ĘĒČÉŹ ĖĶĪÉųŽ®„#ŌÖŚ„Ō…ŻĻ¹Ń‡Å«¤ÅŃ#ŪēāļĪä‰ĒņėŪŽ#šū˜ņåü DF€Ų„"ƒ^łČ°įĄ…#ŽĆeėIµBŠXܶ‘PG%öóTĢ…#§ °芰D'²&€…;Õ»D%L™--°|Ņ“¦Me9o]Ź“)”bģP:JÕ`Õ«ĄnŁ G-ŪE’o_¹~„ ź=)i [„Š `į$V~8éeUĖÖå ™'אb÷īÄOI +^œva©Œ#“•¼˜„å˘3gVyłdČp{ΜŖ¹“åKĀ`™>}é±ÉĮ'±Š@r³ÕšéįfķČuķĮl²d;Żīćȓ+_μ¹óēŠ£KgŽ ®ńéŲ³kßν;湋‹—¶(ø±b­™'MņR¹é#²@Éż˜Ž÷…ÖŲĪKōUB ]ZÕ~ä!Øą‚§Tb F(į„ĻT4V!²yCh:Uj8œ• 3ӠƎ;łPČ߈»üWž‰Öx"|*2Rć¶#Ÿd8öčćó”×!&üFWB܄5$Ss „ :RCmīŌ`"%ų ä^µčÕ„”T¢ćļ‘id‰m©&<%ÖŽšpĘ9ž…"fك }{żõęfŸ$.W‡ßPrʧØGKr„ ƒĄ4[L‘Fņcš‰fŗ¢#O¾©é§ 2g“ÓŠ("˜†藎ÕéØ#©®«Ŗ“¾Zˆ`<ÖŖĒė®Žź©ZHžśÆVŁJHÅ.Źė¬Ä6[‘©æ6+ķ“Zł*ģa°R „±Õ²:-³ŚŅ ī°į–k®²hF«‹:ēz[Š—ļj;n»‰Ī$½ųšk/c¤nŗj¾6²ø.·ŗī 0|šĀ*lXæ-¢‹o^ž\«Ć טpĘ_l­ĄŲž»0ŽøųmĒņĀ‹ņŹrzēņĖ,‘ä]?0×lsv:Ķ\ĖĶ<÷ĢĖĖź ōŠDmōŃH'­ōŅL7ķōÓPG-õŌTWmõÕXgK­õÖ\wķõ×`‡-öŲd—möŁh§­öŚl·ķöŪpĒ-÷Üt×m÷Żxē­÷Ž|÷ķ÷߀.ųą„nųįˆ'®ųāŒ7īųćG.łä”W:nłå˜g®łęœwīłē ‡.śč¤—nśéا®śź¬·īśė°Ē.ūģ“×nūķøē®ūī¼÷īūļĄ/üšÄoüńČ'ÆüņĢ7ļüóŠG/żōŌWożõŲ;orafce-VERSION_4_14_4/doc/orafce_documentation/gif/VARCHAR2.gif000066400000000000000000000037021501757153000237610ustar00rootroot00000000000000GIF89aap!ł8,a‡3f™Ģ’++3+f+™+Ģ+’UU3UfU™UĢU’€€3€f€™€Ģ€’ŖŖ3ŖfŖ™ŖĢŖ’ÕÕ3ÕfՙÕĢÕ’’’3’f’™’Ģ’’3333f3™3Ģ3’3+3+33+f3+™3+Ģ3+’3U3U33Uf3U™3UĢ3U’3€3€33€f3€™3€Ģ3€’3Ŗ3Ŗ33Ŗf3Ŗ™3ŖĢ3Ŗ’3Õ3Õ33Õf3ՙ3ÕĢ3Õ’3’3’33’f3’™3’Ģ3’’ff3fff™fĢf’f+f+3f+ff+™f+Ģf+’fUfU3fUffU™fUĢfU’f€f€3f€ff€™f€Ģf€’fŖfŖ3fŖffŖ™fŖĢfŖ’fÕfÕ3fÕffՙfÕĢfÕ’f’f’3f’ff’™f’Ģf’’™™3™f™™™Ģ™’™+™+3™+f™+™™+Ģ™+’™U™U3™Uf™U™™UĢ™U’™€™€3™€f™€™™€Ģ™€’™Ŗ™Ŗ3™Ŗf™Ŗ™™ŖĢ™Ŗ’™Õ™Õ3™Õf™Õ™™Õ̙Ւ™’™’3™’f™’™™’Ģ™’’ĢĢ3ĢfĢ™ĢĢĢ’Ģ+Ģ+3Ģ+fĢ+™Ģ+ĢĢ+’ĢUĢU3ĢUfĢU™ĢUĢĢU’̀̀3Ģ€fĢ€™Ģ€ĢĢ€’ĢŖĢŖ3ĢŖfĢŖ™ĢŖĢĢŖ’ĢÕĢÕ3ĢÕfĢՙĢÕĢĢÕ’Ģ’Ģ’3Ģ’fĢ’™Ģ’ĢĢ’’’’3’f’™’Ģ’’’+’+3’+f’+™’+Ģ’+’’U’U3’Uf’U™’UĢ’U’’€’€3’€f’€™’€Ģ’€’’Ŗ’Ŗ3’Ŗf’Ŗ™’ŖĢ’Ŗ’’Õ’Õ3’Õf’ՙ’ÕĢ’Õ’’’’’3’’f’’™’’Ģ’’’’÷ H° Įƒ*\Ȱ”Ƈ#JœH±¢Å‹3jÜȱ£Ē CŠI²¤É“(SŖ\ɲ„Ė—0cʜI³¦Ķ›8sźÜɳ§ĻŸ@ƒ J“ØŃ£H“*]Ź“©Ó§P£JJµŖÕ«X³jŻŹµ«×Æ`ÊK¶¬Ł³hÓŖ]˶­Ū·p欝K·®Ż»xóźŻĖ·Æßæ€Ę@ø°įƈŽ‘p°āǐ#+fŒŠ±äˆ)Ī ącg„Ÿ[†68zcéĶuOgT-õI×®-ĘFżv6EŲ/q{“M›-o‰ŗE'ü‘xo“Ęg¹Üōq»É6W9}õóŌž‡ēÖ¾ū:ŻŁ™ÄēŽPŒ²‘Õjļ]nģz7&¦ßm=Čł™ŠÜ’nļ^!šLņ‘g1ńķ3 aī1„WŃ|ū¬°pÅ]kŽ>™P€Ź_&“Č–aA’Ham )#žŠ¹†1ūą ‹RÖ”‰ )4‰~ģ­Ųf…µ(”|5¦Lˆ™ķcž@bų`’ ‘ˆ$‘„ Éq®)“`q' äå>ŹIf188aŒ> &Dj‰— ­ &œaīC eœ"1õ (l&”bŅÉ© E #iYIf‘dRFąEšł¦rŠ&Åhc§s=Fźę¦‰vzŌ§‘¾ˆg©ĀĮj¦Ø64ŖŖ2±Jj”±ņŹQr·ā “®AX’’±k¦*ģPÄZ'ėJȆŹP°Ėö:mvĻR—'¦µVėS³E+’øŻ.D­·ŚJ‡%–Ć­ėīeķ¾+Y¹čźt.…÷ÖkR¾ķń«/z’n0Mž^W°QČ«šĀ cfĄ«‹JÖĮEGqo3;1Ä”±PeqĒ2P#“ģńĘ&sLņÉ?Įü­ĖēKĢĆFÉÜSŹ*ט‘21 ¶jcRīŸĒj"F“PVĻhOd£Ē‡IMXŃĪ*«2µb ĪŲ$)‡/ƒ†«£eņ™Ś”!!4£Į=‹@F=Ū5:8u±4G|+”ˆaĪ -Š šW`ˆ%@ć@7db·:@“#N™ÜRėéŖ£|sڳĻ©-4™®d„=܈”£MĀX™Ļ~¦ 8¹ö)x'·ž÷ŠiB’jz¤%Jś#źLfé—s'V‡śMßa¹Ēpjø}œ\×X—^±BŅ#~øaƒ‡ØfnYgv›/Ŗą»Śś9č æÆ)­æšBę9­ŁŒŽņv&ÉA Š0œ“29…&DŻ[MĆ&HĮ Zš‚¤’BĄÖ…„H™(šōFs… ”‰[g&!Bʐšux\G8ųÆ É [ČÓļ–@beBD:Źu¦‡ zŸŚ ĮĶO$™0ó¼GęĊ;Šõ÷½–=‘$Ü+YłňÕ#hIšæX،Y I¦Å9ņŽŒlTI×ԈĒ<¦dw 8Ė  Y5?ņˆL¤"ÉČF:ņ‘Œ¤$'IÉJZņ’˜Ģ¤&7ÉÉNzņ“  „(GIŹRšņ”ØL„*WÉŹVŗņ•°ŒåO;orafce-VERSION_4_14_4/doc/sql_migration/000077500000000000000000000000001501757153000200335ustar00rootroot00000000000000orafce-VERSION_4_14_4/doc/sql_migration/gif/000077500000000000000000000000001501757153000206005ustar00rootroot00000000000000orafce-VERSION_4_14_4/doc/sql_migration/gif/Inventory_Management_Database.gif000066400000000000000000000241031501757153000272040ustar00rootroot00000000000000GIF89aŖū÷3f™Ģ’++3+f+™+Ģ+’UU3UfU™UĢU’€€3€f€™€Ģ€’ŖŖ3ŖfŖ™ŖĢŖ’ÕÕ3ÕfՙÕĢÕ’’’3’f’™’Ģ’’3333f3™3Ģ3’3+3+33+f3+™3+Ģ3+’3U3U33Uf3U™3UĢ3U’3€3€33€f3€™3€Ģ3€’3Ŗ3Ŗ33Ŗf3Ŗ™3ŖĢ3Ŗ’3Õ3Õ33Õf3ՙ3ÕĢ3Õ’3’3’33’f3’™3’Ģ3’’ff3fff™fĢf’f+f+3f+ff+™f+Ģf+’fUfU3fUffU™fUĢfU’f€f€3f€ff€™f€Ģf€’fŖfŖ3fŖffŖ™fŖĢfŖ’fÕfÕ3fÕffՙfÕĢfÕ’f’f’3f’ff’™f’Ģf’’™™3™f™™™Ģ™’™+™+3™+f™+™™+Ģ™+’™U™U3™Uf™U™™UĢ™U’™€™€3™€f™€™™€Ģ™€’™Ŗ™Ŗ3™Ŗf™Ŗ™™ŖĢ™Ŗ’™Õ™Õ3™Õf™Õ™™Õ̙Ւ™’™’3™’f™’™™’Ģ™’’ĢĢ3ĢfĢ™ĢĢĢ’Ģ+Ģ+3Ģ+fĢ+™Ģ+ĢĢ+’ĢUĢU3ĢUfĢU™ĢUĢĢU’̀̀3Ģ€fĢ€™Ģ€ĢĢ€’ĢŖĢŖ3ĢŖfĢŖ™ĢŖĢĢŖ’ĢÕĢÕ3ĢÕfĢՙĢÕĢĢÕ’Ģ’Ģ’3Ģ’fĢ’™Ģ’ĢĢ’’’’3’f’™’Ģ’’’+’+3’+f’+™’+Ģ’+’’U’U3’Uf’U™’UĢ’U’’€’€3’€f’€™’€Ģ’€’’Ŗ’Ŗ3’Ŗf’Ŗ™’ŖĢ’Ŗ’’Õ’Õ3’Õf’ՙ’ÕĢ’Õ’’’’’3’’f’’™’’Ģ’’’!łü,Ŗū«÷ H° Įƒ*\Ȱ”Ƈ#JœH±¢Å‹3jÜȱ£Ē CŠI²¤É“(SŖ\ɲ„Ė—0cʜI³¦Ķ›8sźÜɳ§ĻŸ@ƒ J“ØŃ£H“*]Ź“©Ó§P£JJµŖÕ«X³jŻŹµ«×Æ`ÊK¶¬Ł³hÓŖ]˶­Ū·p欝K·®Ż»xóźŻĖ·Æßæ€ Lø°įƈ+^Ģø±ćǐ#KžL¹²åĖ’˜3kŽĢ3€Ļ C‹Mŗ“éÓØS«^Ķŗµė×°cĖžM»¶ķŪøsėŠ9+ﵿÓ¼·o¶ĆĻ&W^ÜųÕåf”“•>½¹óŖŌĒf»ā<ŃJ~6~<ČīĶT’żõ¤ī½Ęē:ę÷S©fż÷Dż§•€XxPéCŹ>ęEØĀgq@˜ƒ"ī£ $Ƃ) F…łĢ^Fó!8>„T8Ļ ²“@xóL€‹8h!@4ī(P>,€‘”†!Ņ„GīĆĪg>Éį‰ąORZU%UWę—dA,±O0ą§ß}łTń`y*xÉĪF’’ŽxģØ ÄF)nIP0ssć—sźc&’ä©Pį>Šx¹ ÕØ&›ūŠ¢ęŒc²€Ÿ>V„ ¢Ši”SN•„§ÖaÄA”†ēē™GŽš§D˜Ŗ¤ņ€ė)śtM-jT'”é™X &čć`A«¶zä©ū¬Ś& „&[…±Ė–™«@Č* ѧā„mTŪ>…ķ¬šØį°ęÅz"†OFž¹÷'¬)¶Ņ ø ZńŒŸ° «Ѥ›ųå³ąg jä)ō:h. ‰NXp²š0§ŁBÕ­·”^4ź@ÖśyĒ>ąŽ§ ‹orÉnZ*†—ņ>“qæoč ,&PKÉ)kX’iAś™Ūl™ĘāGļ@2ņøóDW,SŅM1½¶/ Tč>»„©įŸĮģ!Œ@.ŪnÉbĀČŃ®-ičž æ >IN]4ČÆ†ēöŒČfŽŪkŹż(Æ 9­“KŸF½-ƒ¦”“ąAA-)B:šē—Ÿż°³ž 0āɓŅ”¤,īØ!|_T'~ŠĶN“W>bZ¤˜‹÷x"咓īļ“6KL:Å3åwGŠ|¬ŅļHĻåćĶ£CGĘÕ|ļ'¾øAó\˜”«¦‚ÉgF, Ąœūč"ʐNś˜ :†NŃįÓSo=Ś593÷޳,{HŻĘŚÄĪNŪ˜»Ó•Dōž55 z¾ÓHŌ„$6E*sˆŖQ¤H%ÉQT‹  Ę–<;„'M äџŌC N0<<ž“’1:OLTܰ'BLʆW{.„ˆ U«RˆCZ՗6;k\7œ”™~HDŒ<Æ(OJ]øĀŒ -=q[˜yō±… ėAŅŚĒ"l÷10@  ?rE,.‹P’ŅPĒF3™‘`žć` Ė2E*~Dzź{`Ļb·ˆ\…Į‹Uųį4ŌCń*ˆa(0’‘®9äÕīŠ¬‘ō1q{ō#(3µ…ł k>ś"ūG( ¼Nj{[XĖ:"8S¢ BbS„*Ć8·&ŠŽ…jłäY b2q‹Ō’/"=5Źv–Šæö1Gj"ņA“’Z;gZ„}Ž|„y(g9’Ī‘‹×t’ėžŲ‘]Į˜QJ „'Z¶/&Ā,Œ<'²Ļ‹įlH>}2Pžlk3"K„PČri“i×ūH$®/ŽÆzčņa‘.š#Q4t²Ó_įÄw½cI†¾<؍Īxæ@ŁÖ_W¢Œ"4{^ ‘˜fQ3šO§BŸG!$.Q„p,r‘éf!¹Hاš)é¾#$“Iµˆ¤óžHwU!JM{ÖN£‘B .jY½¬Q…ā¤$šQĢUAC" ›:_ˆ±Tµ_•U}cWˆL˜H½p;³ųeŪéce ŁĶ^Ł(öŠ]G»qт-|÷–"+Ä'*šd¬‚‹RJ’„–@~ģV£JÄÉēŠŁĢ<;²×Ż·ŹāOmͤ®‚ Ē^LyL–$=±,­tÖ1‹&KµŹb#Ō õÓK¼.™9iÖ¬“x$;ūsoŲSĻž-x¢4Ī餣ØæTĮH® ­0aEʬįoŒ*4Œå,©&*ŠÜLsę¶zŃé}®‰‹9G$Z ”Å[\ėś9äŌó"Iē=5ŅH—• Ų:ö1—½‘Įz™Ł8$­N”͘Gš›ŌIY:=J¤Ł~>”vÖ ›t˜+ßģ¤y¢Ū5©uÖ5“(½³¼™ §”a‘š¦½Ģ‰Šbą‘v±ė²nDįׯHõ‰ .å1"Õ£xK÷żŖMu„0'A’¹ŖH“ų|éó)”Ģč-“{ĘāžoWšQYKŸ‚÷Ą§ˆń”­|ŖŃųö)’ ;W"Uyv·!œØóz#£>ōkk¤,[ ˜ņń‰¬£Ėć8W4M±IŻå”bߌ% 8nÉ.{{V²Č•d-{®ĀŖÕŸ…H–Žw6a6gvݔ۬–VĶ>–eÉüå^Œ`±+Y `¶™“Åč—ĒGγŠdßÅ]yXbe.$xčĆĻēL X/ČąÅ•F„Kd®w$fĒ$ÕźV¹Zī'Ļ’ĖK‘h ąŲ悧m$2ŒPoļfõx¶%ĒMŽ7¬ćƒjAFćqhĮ‚ģ3Ņa¢ÄŽ)3ńƒäQŃBō!æ”`~5~«3™ųĘæIp&N-šržX<^ Œ6Z÷ōP(†b5”+‹š1ČŅHɆc®%»vY’y*RfsF+hÖIBxĻĀ\6åvėshё£Ō\'"0ˆ’7’Z™¢$7R7žÓ"€BzyVj©ä~«F“0A¤ƒgPrpćp;“lć20Ā6z#Z°¤$3i%–ęOW•§ų§‚41Ķę'aŠbōr?ŌBŖcYŅs“kAZ©S; ø’JųkŪōnDgŸ†G·eŸQNū 9<‚‡¹ó˜TkLg¤g'Ų…ņį…TŅ]“÷,Y!|Ц@9 q wiłŃoT“u’—(öP‰"šxy7ŃlńdЉ=al}‚^TĮG˜%˜,r įq‰ņl”ˆW“O·a61S1ŒæčŠ9±…6ĮŒ_ųfŌ ńs s=2Q²+Š"¼FuŒ8|ÕĘSC‚=Ā‚sß³sžäsƒ¢r„˜>ߨ…ŹØWŽŲĆ"y&4tx $w0'jrgGŒ¤ōWL.“„ˆ’*pB½†XųA yāY`ę 6ōįX–Cé’A·×ZP6æ—[|āŻR€EÄ#ē„Ca}½~2);#‚&ŲuɅ¹3X_¤€½ö/T€īR„ a_g’ö0ŌØ‡ˆz‰$Ü'«gbĆ6»{³t“Ķˆ‚|äSļw}’7Óh@Fā׊Õv}ä8,ūąƒČā’Igģ± k)Zéo\Y‘_R06ŲMø¤e¬Õ&cĀm‘—•¤”g¬““V8,-© IA”Ö>ĘØ—{‰O}©Ń8² ōę‡iˆ9¹ę.‚ų9‹(bŒ‰ń‡•¢M©D¹Ņs-Öm(åaœø^¹•99 "1—Šč‰–X:‘HŒ6ł›žœĒ-éUƒt ÅNJpČɜķń™”ĒÅ§K³ā9žäYžęyžč™žź¹žģi“ąŁĪȗļé›óIhPŸų™ŸMA   śłŸ:11 z 9‘  ‘ Ś Ś Q :”J  Z”ŗ”ŗ"Ź” ¢1 ¤‘”"z¢(ZŹ@ Ź  +Ŗ ž™¢2:£õŸ3z£½ 6Š£<Ś)ʰ£=¤ĪQ£BZ¤Ŗ£Fš¤ś£JڤZ£“€Q:„RZ„Tz„Vš„Xŗ„ZŚ„\ś„^¦`ś„&ꤔfŖŠ0¦bŗ¦jڦlś¦nڦ1 gZ§ó‰tj§zś›“§{ś§‰§€:ØŹ(؄zØł×§ˆŗØbg،śØ.䨐:©R”z©×q””᧘ک›1žŖ›”©Ą©¢zŖ”1 ŸŖ¬ZzŸ­«‘1 ²ŠØķy«øš«ŗŗ«¼Ś«¾ś«ĄŠŠ¤žįœĻY\Į’4¬Ž ÄŗÉj¬vѬ€­ĻA­V¢¬ÖŖ‹IŅŚŻźF9čpˉhˆń­+ń­’=ˊ£GmÉH®‡a®Ćp'e{āø'vWęŲ=9×kźø"'…rØÓˆĻŠlõŹ8 "+&R‚Eņ Ā!¼F‹š˜­r!ƆƒTØ[‡U–†MՊĄw½ęwšõ®)ر2˜ „ą%äjČV!iąńX5IŸÆėŖkĘu4ūFØwˆbŒčzšÄL;˳I(‹dg*lv}ŻÅ*4ėmH+øÅu؈¬:k­§N„·.4Ö?ų'Ö(e$aóZK]«[ķ7`[„@’łmŒ-ļ¢a㚲嚓Œ³“>kz­öm«dM›TdŒäCU6(Ū•Čę·¶·“gI˜•®`›bs¦2 X±9k+r”jQ€6˜=IÄJ Ū½DŠš»¶ŗaW‚‰J:¦6®u¹į6X›µ÷—«®‹;ŗ%ø“3M’I‡āk¹©›i«»šZfˆ°ą82¼¤Ćn¤•šœ³šåެKݚlžŪ½4q“֙Äégꋃ¾ouŠŃ»ŖhłrÉ+ņ[‡ƒæü’³N‹{õŪŗ©%½i`Ųš{ų&o¹ƒZ <Ļ[¾» Ģ%Vp Ął&`°9‹Ų‡œŒė#L*ćęĮ©“ ģ€)üĮDŌtĢb{¢t Ü7 ü—sĀv,»V3˜oÄh˜—"ūėI"±±!03¢n ‰3‚ƒEC삔›»@ĢT‘ÅњĿ²Ć{BÅÉr²ēĘ09BÆņyRÅ8Ģ»€^»% U<†ƒ1©{ūqű‘wģĄC֓iü|Ī"“šĖ;Ģ|L‰€pĖ›QĢI”X*ˆĆĒ„€pGä.‘Œf ģĘ Å]A±š§«ē}łĖ–‡lO8Å8³zĶG±¢‹¦Ü¼ ĮkaÓ#W&am®.Ł(qD&–…›’¼·ŠČȵLvJÄIu쀮YEā› Čua„_n¹%ļHĀ~ŁŃüøY&K„×C8†8ß “CFŽš<\œüJÜĆÆ³±{6Ä+kÅϜ\Œ°/hA„©„ąįŗŲ š±ĪA…ņĪ‚g—FЉi0£ĘĆmlī›»’Ł›ćÖ5÷#,,×Ü;@~MK©mæ)QĻ)Ä='ė ‘Ō.)7;\`ŒY¶Ci„&Ū©ÕŠó 39Ig“BM¼UD²ÜŠņŪū0Ū_ 2?7Ąž ĶIĘÅ^Ü(s"C‘c\!Š}Ū½–Ū”mČS]Öürx:“9,“ŠD¹€Ņ18t Ft4éŚCć•ÉwÄHLJ“˜G8¹©Gą6“„j–ÉšżČœYĀ¢RTY^čŽWCČ?’›,ī| žĶN}"ä"øE¦~ƤŲ0G‹ÅkßCČ$¤C’æ„fĮ¬Ōé=ņ Åń31ŌĒE;„/-"ŽĖ~ŻĮvźńńķ’źg}„™yq)ĢZ­·%į”(^h—Y7ōż·ƒńā€-’FĀżNNÕ¬Hoƒ=ÓĢ’ž÷ܜƒf„WÉ?Žq>-øŽ!ŲZĖÜŽąz(Y[p©¾aNK/½Šłm4“x\w˜ø”+Aų:uĻ|ćŃ,Øę“ÓKkTpϦ’é¢å^ŖŪožø˜Ż±4= >ƒ|ø9#čj¢ŪMīą%ĮŽĻGŌ€€s†Čus ėš‡¼F(v’ØŠ±&ȱ-5­1`sL¾xŚŃlč7¤ ’ÓÅU0†®#†-ą›ŽŅŌ‚!ĶģŠž¹—Ó ±¼½BDۢеv"XmŌŹū\E¾!¹žšqģŒsә†ļ¼L=ĖęNQ{Ķ ĶżŽģ <ŹI°¢’‰ŃĒŹWšükƅlߏŹéÕļēńÕ%żėÖĮP/ÜM‘‹Ą¶Ś¾Kσ¢U„)å&ÓVšņėwKžM#B÷åą^ö¾Ä²ČՕЈ+ó6Ś›=_±RU…ư4¼]Å11ßĮ:ŅÖ¤}rõŠó Ē;&ļźÆīÉ“tA„ŁiŻŁ˜-tĆŁƒ’tE’ŅōVŽ…ń)®uDė€(uŪÜŃp:ɽÜÓD\3ŁĖäM 1Ī-j^\xÉ@޼m-ĮąYŠÜ\¢ÜwæU^|eRüĆąMѵ(é Į[Ś­Y€é݃Ņ÷į]”æ'1{KŻĮÕ0žöĘeéąŗ0¾Ł›-÷Åß4Iļ^ŃõĒ~}(¹›£,C* Ž]ĄßČ>YįxŒŒž ŅÅTG$į¦rēw,É÷DÉYų‘“Āß³$ūä—|ÕxbԈćg¬ćHŹ“ńXųpīfLÕĒ„ośŹ%Ö>ö&&”@€PūņQą>†ūōU9ÅRœy,"VŒ˜oFCƒĆŽaXĪdžHžD™RåJ–-]¾li&Iv ¢ķ«xs_”Pq²Š©(NĒ„ļääˆtŸŠ†Š ˆ–ó`Ń CŽœY2ėV®]½~õ*¬A:²{čĻ›łŖŌWčŌCør1"Õg%bC„ūv«5š`Ā…ÅrŌŲö­Ć-§>^ŪņM}T†öŻW3Z^³$ŻÖuYō^‡V:3ü‹ņpaÖ­g®ž™Æl錑ęÓėȼ¤Ł"Ī­éĮĖ@srF™š+’l×Ķ?gȜ+rĶ™m~ŽL@ÄŹ¬G;č]sNŸūhŌ,ĻbC]CK‡ß0Jܔ©ˆ·I7ūöŸÜ Of-õ.ZožN©­›AĻ&ŽŗūnĄ}$Ōē?¶üŽ”öT“ÆĆęąk 9óŒFBó€Č ÷Ī‹p=ŽhA‘30“ˆ0¬NC÷¶ŃCL©Ē™˜2ļ)‚IčÓ Ŗ"ŒøkņI¶ŌÓ©2)•ź0!är%醋2€½vIrI,"Ÿ׏.!ĄŠ#²RLĻĀ$š¦3‚ ͽ²”xźÆäyš§œRbdX€Fc8'D–ć÷<žg³yg°z–” ›ŲįOV<"CgDŠŹ ‡B+@³ˆģŲg.Ž5é`𠻦U@/-ņŠŠō°2’/éŖ­žk¶Auūm˜āīhØø Źg-ä>CNø”$$–4cEJVī¶Yė{1 Md·HĒM­¹ŗˆ¦–‚PCūfĆ=¤{s;÷<ŲĀv„„øˆ(“‹M¦&ū—!{³,ߊå£[žš éƒFÕē¬X-ߝ.ÄŹZ'ögtä“_žłŃÓ§±ßÅqF‹ÓؼwŃ/l5o>]ėŌo²ŹL×=ņ} F lł];üųåXłšé/³“ÅŃAe v“3 UDj ”…UęGæ±tC»Xˆ·ó˜¤i@YŸq"s )| ü §eæęŃķ!NZȄ\”Ø*Sī¼¹”’ģĆ'Mq'7²ac%,¦Mį+øõBRÓŌf AOé0‡ązbæHø<üłźGė_ęœv¹f:ąqØE€‘QXSDž }č”ÄdьŃjĪ» ³µĖ©ģ[e|ć§ņ*4Ī®žū# ÷ȳA²¢*J"¹HF6Ņ‘„d$%9IJVŅ’—Äd&5¹INvŅ“Ÿe(E9JR–ņ’‡DåInJV¶Ņ•Æ„e*‰€IÄŅ–·Ä”e.uI°$d—æf0…9LÆd¢(b f2•¹Lfڲ—Eif4„9Mj†Ļ˜‰Df5µ¹MnvVĻL¤7Å9Nr–s,×Td6͹Nv¶Ó€†;å9OzrõØg>õ¹Ļ`@üh@ŠŹ@Ō Ečēž™P†6Ō”:óēC%:QŠŖ ÅhFQvŌ£åŁBA:R’–ōž%EiJ5 O•¶”Ō„éKe:S}ž”¦7Åi;9šSžöŌžńōiP…ŚL›ÕØGÅ„2Š0 4@ KĶR„:UTփ‘Q„jVµŖÅ¦&r•[kXé§Č˜ŠÕ¬g}›މV¶¶ÕgE)«[å:WX©UtÅk^»“S½ö•Ŗ¦l`;XĀÖ°‡ElbOé×Āķņ¢o{,dĖX7ę2²V»,f'KŁ1Zv³ŗĢģĪB’+ÖŃBō³¬ĮLRŲDŖÕ©“{ķVcK°ŁÖÆ9ĘņW÷X‚ŪƁ–³Åem„84Õ1Ū r¦7åęå «²#ŖŒeŌU®=ūŪćm×»0yZ†–µeēĖHyƒįƒ *'‰<4¢ļälšÆz½£Żąr·»żõmVR;ŽĶų 9R1°iĪēŌe2ĮyĖd’ą;Šī»žżŠp‡ąŲ k%™ŠB 2 +}D[BL¤īV±ŒxDa†¼0†”xŚ[VkĄ¹ŻĢ’T ÓÉĄ©‹”õRu.¼ōŽ1–1Œd–„÷ĘH韃—B"G@.*ƕ„‚9ĆVó[o™<““)2…[‘#ÜMµėŚŠ3nN™õ\Ü5+jĶ ²ū”Öh%„ŗīĀPöØB`"!F°RŻŹ.¹+¦>õŖEM©P[ Ō—ĮĆ’ OĒŚÓ)"v…]’ē£Ś/¼ BɳÓņ?’”VaŃ.öKźŃYŚĖŗÆ‚ŹĒ&Bxēdę^K¶· \1{EŚ·÷MžwmśŹ$'sϽƒœõŅiIżŽā„Üš¼Uøą"ß[śf!żŌ‡Z¬9ų‡EÓ!ĖхĮP Eƍüßvw%ā.q\–ž&ņź zz‘c¤ń(p/ßÖĆĆz9źlÄE€$Ä/®õX¼µŪ‰Ó|NŃ« ŽŽróG/ŠĪšzłJä”l„Ō¼é÷^ Ń-(G7ŗč˜fłÜœsć#œ2UøƒĆĆk³‡†ė|YÓ)ˆS²},āra€ ŲÉŽXsåģ¢6…¢wōĶ!9:Ė|Wžões±äš>|’hnķ|“Øģ„qrkBd ź©‚ :“ åœŪŅ`‘æ‘/?ļ81ž$JŠžRÆl–0’[ Œ; „ac׹ś$šNԟ\X©5Ūéńēō©×s®KU*.¼!™~čLwV·j~ÉóÆŪ“¤ų3«Š u£ż9§¹HÉFąœ~Ö³—®ėX·uĒ‘¾(’¼Žµ¬ėsĘĻ‹Ł\cŚ‚$„X£aFį ]³T[Łbs ]“µb‹¹?ņ ‘FK¤«³­ē @Ŗ03Ś ŒŅɽÜ+ˆŁ‹’[õ®”!Š¢Y™éjœ?C ł#£g³ j£ŒrĆ @·¹šh Ű b ·”AļA;šXŒņ ±©<.Ó6­ė³WźėA uū EHš]8/‰q’ÆØ(Ā HšńĆ“ń‹.<“ŗ«'cÉģˆ ī°8ŗX»ćó Óø ķ”·K Ürø„Č·8 ±ÅčƘų%”4°h£@Ä; å#Ėøø;l‹%q‹Č1ˆF<9ų“—)l§ÖQ!ˆĆB@>”Ė8+2?ŸCĄŽ‰ įi{aO«…½H ©p1 “°Es„ž©‰åZ 5Q;_d’½@±5‘²K;©{Aõ«'ĘiCŅĆ¶ć …ƒž8„ıɞˆŲ1Č[°ņ` æ9Ž+Œ‹Ć„µżkœÅ|1 ŒĢTóC;Z˜LÓ,ĢĆä?Ѽ’LÆʱX³$³5’¬9E×Ü5č5„ĪĖh˜ķAd‹äĮĢ”JĀk½ƒ o»Į1t IČsc‹ŹpÆŚĀS0𰳉عAĒ#½Å;CŗŹµ¤ «ĢZ ĪĶ „ėäĮéłĮ ōć(C³É “ÆśZB½ŃśD·‰(TĻŚÄE˜°žü Ó[šĖ8†Č¶ór8.Ķ›ĄP ]ρsĪē¤`;ÅB}Ō=t‹’„Ä»©Cš˜ø| ĖQ-Ņp8¾ ŽpĢD̹E|HGŻjP…K>;‰±QK<8}č‚¶«#I‹ćAģ11bĻōó8ž2ņ’о“ƒ ÓĶ Ū@+MĆ%D”ØŽR™Ń‹c 8Œ»ź1EzEÉÉĪą¾Qč“ W a„[ÜEœČ»øčS2F µŠ:ķćƒ<5©S7eQ9Ō@åCćŪ½™):[ŗckŪ*¹”x’uŁŻĆ¶ ®d4Æt3 ×6Ś!+Ś 6õ¾ÕLI ¬PK'²;» ĀEæ¹„Ū›Ä͙袙 # ”Ė+ŻĀ Ł1}‰Ė퐬ŌÜøLµ§üĢżKĢ„`@ģB@œ(ĪŪ4 p æÕJȝWq…„ĪłĪļĄH‡Š,PóˆXōŒB£”ÓmUfÄŻ³4GVźIL1( E%]DßiĪå8lŽČ]PčmŽyT|eQģˆE–•ŗķiˆUe7ļż^ēuHųŒĖ֑dˆE°ŁŌL“u\-xU\*Œ_šÕ]F­€ŌŹX” „d»‰\­Ć5:ąĀ}ŽTā]cü” [ŗZüÕHˆÉ:┵ŪĪÅ –ßšÅąšq\¹Ż]¶ął}įå]>GęT‹ŗą–aČĶaQŁa‚ bēT¬"6ā#Fā$Vā%fāp‚į'†ā(–ā)¦ā*¶ā+Ę4ā,Öā-ęā.öā/ć0ć1&ć26ć3Fć4Vć5fć6vć7†ć8–ć9¦ć:¶ć;Ęc© ;orafce-VERSION_4_14_4/doc/sql_migration/gif/STRPOSB.gif000066400000000000000000000042351501757153000224270ustar00rootroot00000000000000GIF89a0Tp!ł5,0T‡3f™Ģ’++3+f+™+Ģ+’UU3UfU™UĢU’€€3€f€™€Ģ€’ŖŖ3ŖfŖ™ŖĢŖ’ÕÕ3ÕfՙÕĢÕ’’’3’f’™’Ģ’’3333f3™3Ģ3’3+3+33+f3+™3+Ģ3+’3U3U33Uf3U™3UĢ3U’3€3€33€f3€™3€Ģ3€’3Ŗ3Ŗ33Ŗf3Ŗ™3ŖĢ3Ŗ’3Õ3Õ33Õf3ՙ3ÕĢ3Õ’3’3’33’f3’™3’Ģ3’’ff3fff™fĢf’f+f+3f+ff+™f+Ģf+’fUfU3fUffU™fUĢfU’f€f€3f€ff€™f€Ģf€’fŖfŖ3fŖffŖ™fŖĢfŖ’fÕfÕ3fÕffՙfÕĢfÕ’f’f’3f’ff’™f’Ģf’’™™3™f™™™Ģ™’™+™+3™+f™+™™+Ģ™+’™U™U3™Uf™U™™UĢ™U’™€™€3™€f™€™™€Ģ™€’™Ŗ™Ŗ3™Ŗf™Ŗ™™ŖĢ™Ŗ’™Õ™Õ3™Õf™Õ™™Õ̙Ւ™’™’3™’f™’™™’Ģ™’’ĢĢ3ĢfĢ™ĢĢĢ’Ģ+Ģ+3Ģ+fĢ+™Ģ+ĢĢ+’ĢUĢU3ĢUfĢU™ĢUĢĢU’̀̀3Ģ€fĢ€™Ģ€ĢĢ€’ĢŖĢŖ3ĢŖfĢŖ™ĢŖĢĢŖ’ĢÕĢÕ3ĢÕfĢՙĢÕĢĢÕ’Ģ’Ģ’3Ģ’fĢ’™Ģ’ĢĢ’’’’3’f’™’Ģ’’’+’+3’+f’+™’+Ģ’+’’U’U3’Uf’U™’UĢ’U’’€’€3’€f’€™’€Ģ’€’’Ŗ’Ŗ3’Ŗf’Ŗ™’ŖĢ’Ŗ’’Õ’Õ3’Õf’ՙ’ÕĢ’Õ’’’’’3’’f’’™’’Ģ’’’¬÷ H° Įƒ*\Ȱ”Ƈ#JœH±¢Å‹3jÜȱ£Ē CŠI²¤É“(SŖ\ɲ„Ė—0cʜI³¦Ķ›8sźÜɳ§ĻŸ@ƒ J“ØŃ£H“*]Ź“©Ó§P£JJµŖÕ«X³jŻŹµ«×Æ`ÊK¶¬Ł³hÓŖ]˶­Ū·p欝K·®Ż»xóźŻĖ·Æßæ€ Lø°įƈ+^Ģø±ćǐ#KžL¹²å˘’3kŽĢ¹³ēĻ C‹Mŗ“éÓØS«^Ķŗµė×°cĖžM»¶ķŪ cŲĶ»·ļߥƒ N¼øqą€ź>μ¹óēŠ“ß\½ŗõėĘ„;¤ŽŻw ­Ä†Ų=øv†ćÅ£/’ūüĮō^ᣒ(æj}®÷ęæøß`šóyōßVH!Ȕ‚S1Č yŽEąƒ –ƒōx!D6¤`‡QM˜”B 6…”€‚ubG’%"Š$n!‹)~µ"G-J 1ŖČįˆX•hā0zčāŽ8.$äR7n“äPņ&Š æķS„@¾”1P&¼er ”Xöę%HMj”ćC7$¤åQ/ņØóDi¤ ˜D•™Ń“ƒgHż@Œ@™|'Мŗåw† “‚2ūL"ؕ“`łē>ī“h=0 ¤‘E"É1CœFµ™d *g¦”†” i‚Å`Ąžd¢ŗ“Zy`A¬Āwƒ—ņKŠ Ä$ʬnršŪ˜3zźßn™@³[ ʌ:Žn‘²)ķJ’H­µÜ@Ģ 7 K*®*Įjé į: Z²Ū©A7ø:hz‰6Š(æ™f[¹ūä»j”¤Ž®B™ˆAk… ‰į%¦ū ń'—Ż0 ŠeŖ“ $ń>[L)«UZ'‘ ;žs®’«ÓsīĘ,|¾iē۟ēÄń¾6‡ŁŸ,#@Ē'ŠœkĢč$+›ŌĒf†lÓ-»ŻjoJīR ļƉįēÆ9!8§¦‰ŗö¾W»CÆū*Óļț~ėõĖŃ"„«cߥ¬ĄHQ ®®żĶčx‚+;¶ĒE_räqŁō@_ŸzįM-Ī[¦w_±–†ź¹ÆY# r߉‘0ėo"¤rĆū źŖ2ÆÆlõ걤21h\OØ7D]*åaŖŗŽ A¶ļĶLāēlLP ÷ŗ@˜v{4ęŹP<ōyļl×ȝ”bo{A“Š ¹ł‡÷~šÖ“ąN©ń1 ’?æŅFóŸ³ b6b®V씓Ńxs³zš@õZZ—¾4rMLĪQ²^Ö…ü­\–@ 2į?ņ±É8ō)Žšv“¦˜s½aÖ«2H¢ĖUČ9Ė”ßL2„ō…pyĢóĻ‘tČ"ɇX"ā¶sŖ/mźŻ@6H¶ Öč‰ĶŠž¤ˆ9%Ś"\2°¤'#śĒ‹_\b|¬/#^%l\’į%’.Õń°jeœ£Ļō„Ē4®‘ˆÅk£ÆhD•EdIŁrÕėg#$ź‰ofl$•!F$¢N’‘<ü2)‘æum‘åOĀf%4j±]1Ü lČE,å‘yœ;¤FźA„őqŠ‹œÜR%QyŹWö²urĢ„+qÉĖÉÉr#a„E”ŁRÖĪ”c&!…ذhb’—ĖōČßf–Ąnz“9–¤‡¾IĪr‡Ō9×IĪp¦“#Į’²Ļ½ō3ŸĒĢ"_ž™‚Tšā¼głšbЃ¢³Š}iØ]Ģ銕30­ØF7NŹŃŽzō£ ©HGJŅ’šō¤(M©JWŹŅ–ŗō„0©LgJӚŚō¦8Ķ©NwŹÓžśō§@ ŖP‡JŌ¢õØHMŖR—ŹŌ¦:õ©Pjf;orafce-VERSION_4_14_4/doc/sql_migration/gif/Staff_Management_Database.gif000066400000000000000000000207051501757153000262560ustar00rootroot00000000000000GIF89a÷Č÷3f™Ģ’++3+f+™+Ģ+’UU3UfU™UĢU’€€3€f€™€Ģ€’ŖŖ3ŖfŖ™ŖĢŖ’ÕÕ3ÕfՙÕĢÕ’’’3’f’™’Ģ’’3333f3™3Ģ3’3+3+33+f3+™3+Ģ3+’3U3U33Uf3U™3UĢ3U’3€3€33€f3€™3€Ģ3€’3Ŗ3Ŗ33Ŗf3Ŗ™3ŖĢ3Ŗ’3Õ3Õ33Õf3ՙ3ÕĢ3Õ’3’3’33’f3’™3’Ģ3’’ff3fff™fĢf’f+f+3f+ff+™f+Ģf+’fUfU3fUffU™fUĢfU’f€f€3f€ff€™f€Ģf€’fŖfŖ3fŖffŖ™fŖĢfŖ’fÕfÕ3fÕffՙfÕĢfÕ’f’f’3f’ff’™f’Ģf’’™™3™f™™™Ģ™’™+™+3™+f™+™™+Ģ™+’™U™U3™Uf™U™™UĢ™U’™€™€3™€f™€™™€Ģ™€’™Ŗ™Ŗ3™Ŗf™Ŗ™™ŖĢ™Ŗ’™Õ™Õ3™Õf™Õ™™Õ̙Ւ™’™’3™’f™’™™’Ģ™’’ĢĢ3ĢfĢ™ĢĢĢ’Ģ+Ģ+3Ģ+fĢ+™Ģ+ĢĢ+’ĢUĢU3ĢUfĢU™ĢUĢĢU’̀̀3Ģ€fĢ€™Ģ€ĢĢ€’ĢŖĢŖ3ĢŖfĢŖ™ĢŖĢĢŖ’ĢÕĢÕ3ĢÕfĢՙĢÕĢĢÕ’Ģ’Ģ’3Ģ’fĢ’™Ģ’ĢĢ’’’’3’f’™’Ģ’’’+’+3’+f’+™’+Ģ’+’’U’U3’Uf’U™’UĢ’U’’€’€3’€f’€™’€Ģ’€’’Ŗ’Ŗ3’Ŗf’Ŗ™’ŖĢ’Ŗ’’Õ’Õ3’Õf’ՙ’ÕĢ’Õ’’’’’3’’f’’™’’Ģ’’’!łü,÷Čš÷ H° Įƒ*\Ȱ”Ƈ#JœH±¢Å‹3jÜȱ£Ē CŠI²¤É“(SŖ\ɲ„Ė—0cʜI³¦Ķ›8sźÜɳ§ĻŸ@ƒ J“ØŃ£H“*]Ź“©Ó§P£JJµŖÕ«X³jŻŹµ«×Æ`ÊK¶¬Ł³hÓŖ]˶­Ū·p欝K·®Ż»xóźŻk€ßæ€ Lø°įƈ+^Ģø±ćǐ#KžL¹²å˘3kŽĢ¹³gĮ|Eś„  néŠūNĻU-—5jŽ£W›~ķnķ··_cŒŻz6źÜm³®›"ļøÄÕ&—MŚŖ¾*” ²Ķ’xńŽĒmū½mwØÓOYæ¾1;n”Ļ3© ś¾yėżĘyæ“_ģīŌGČo‚ź(}§]sĶSß}łĮ@šż5_zėµ'Pƒņ ¤ģaBŻ>üłW>…Ų'”AĻEwa†N$ y ™ē֊åCņ“<Ķ…óķC uš-˜Ÿō‰Ē!!GL)ĮÜvõøĻArHEŽ;F##6ā(P•2ńž œĀ_‘ū9ä å^^˜¢DJ²x‹Kž¤å“o ^>*<8å>2ę8€ś(’£Iq®•(X‰ņéē|$O˜wZФ§°ƒę>»Pg)‡†īCˆ— =’—iŠį'ēEt‡R¤xŠ!<® žš&žY¦`@H“x+tRz"­Vźśé±Ō³ žĶņŹß”©yĒ.6NČ€p®ŗŪ¢^Q„”bčexšHģålŗ’øgĮĖU¢érøīŸ'ö¹bbØo³ 4č.īZj©Š­³é<,Ł­·µŖč«Źzŗé õā hÅÜŖ$oYkEļ Ńi©¦ ė (CMĖezš§@ZPk®Ÿ~ś0ÄʅŒ•Ļ ńk)|œRo‰ÅŒ&;#"ś+}ļ|–ņŁžŠZJ”½ŗ)¦"K_}0B%ņ·ą•G“n¤ŒQk§’IÅ.ė藩L™qtĆ:¤_E'ł4sÉC2 |oLåŻyĒ!#ݱŚMkćR²'I¶²g"!6ōŻ…¢Ų1Dq’VŗBl*”` ~‘ŗ±ŅĶģŃéSŃ>ŅŻ™“ķQńžĢ2łŽWŪ!„B“™|D©Š,O~ć$¼SÓ3/aź4UošķĮn¢"~L!óŃ˜ģøŸ€†£ĻžZĮ“ qé5Yi¦m.²VLÓe‚ZĶż¬½Ūk»y(•sy#A2”’UĢh+š¬‚ō,)6E¢åPˆ|kÉBpC©J¬Ŗ¤£…5w£/uÜTeŠ vy”dK½K2’՟|–×tO†‰O>ŖčŃņØ\‡ŽS ŗ@“Y#×¼QQpCU]pkŅ=Že²(ŪzÆFp‰cRÆx"L×mŁ’Z³Õ'oÄ1'åG|‡c/§fHŖ7ņgž”oEz8¢BK<µ„F­J¦?žV8Ņ%v‘[ėä;ü9ąŹf†±>I tZ“µ%$-ŁČžóqŖ¾ģ·8™¶]©x¬ęŲ qČeęņ“–›Õ)'KPKĖSōqAĪ,2ˆ|¤Ŗ7-¬ŠņF@Z†’‚[„ˆ±/”¢®0…FZAwXĪĻ¤[G;rš¼’£ÖU=WŅ ®7’ åŸOUķčY-±Õ Ś–]÷“Õ;aŠ_RĖՃ`WØ Œ”¢ŹkŽ£‚ČĶIFȶԁL6›+VÜdZQ©"Bßä;j’”Ķh;iÜFČ1‰Z¤[ŹÕ·!¾¶“Ičn3æ9Łź–ąM$rG®Žõ–ó–£4q·ųp&ūS¶GÕ®Ńńr–– öņ ³T}“Ŗ6-ČØ*^.žM i:3dšcŻBÉń1ęöž ÷Śf®Õć[§q«jøä?ęW>b<µ¤żyfsNˆ·!2“sph÷“„ņpę#`żjå,”•6˜-ŪĪ—"’Y¦óh篇bé%K\¤ųSöŠźˆDT#.«īl·oŌ“\oŃPŅ®Ēē‘ļCņś†ˆj<©7Ś2^sɱ‰:†Sמżtė,¢īŃŃÄēō‰’ļ“Ķ)åbē×TõSb.eźžĢˆtn†ŚŲÜė©uHe˜˜|z_šœ!%ˆ€¾Ź/‹6īÜTō©ŻAå!8’ ¦?j+ūł\č9 ļǵ¦Ø&ł°sKƟéō !oĶ>ź¹Ļø?}’ūrnmńśÜŹą ³7+'{š$}›£l1u_į"»xģ–Ō†ju%y§N…@3Š>r~]A; Č{ÅV󐁕¤ˆ#ŲL!8 .µ”»Å)÷åS«§—Sƕ".wbÉU0²w=ĻÕYŸ>-t]]FZŚåYÜ“a+RJbq:–…Y3e?IX}4Č]jb>eXT}AŲOŗą{"õ*»Xž' ¦„[B†źē‚’ha_Üå1µ-u^ÖF%KTUĖ“k‘‡b‡ĆXrg.ćb$3#(“^ ec`Ć-l•ć2p(» _Œ8c‘÷,5ņ2ąbå×&|cyb'cy§'8V†'‘‰~öB½"C‘G&évL*xN'…€ XHpāŲĆf¶JŅvD×§-7Rt¼F-äĀb&ē(I£%šĶ3gE„o”8r=H¦7&ötę„4f„8FӍIĘ1Zå~ī“ŲSja3ī5c%ń‚ʋg—Œ5Q‰×i4BBx\Ō=Svdj}¶pFpl‘6pQ·lŲxTTIh¶ŲX ©"¤HŠaj’‘ÖC¢‹»”ŗĆGoEJ‚į:–8ĻdŗNż“o‰ž–*ׇēƒ b+ų+Ė}ųBlfŌpžCR>F¹e|ÄFl§Iį“še/•I„ņCĖŲc•ĘŠ%?ņ0F&”$"h$a”ÅĒMFy3ADĀqjō,7t Y&@Č1™yˆjN‡#Bd i‰bIOØ+ŪĮTEāE,Lä{ł–éH1Tƒr/£LĢ„^ ‰‹I–9V‡gMƒøq‹—u߇sr†Œæg3üR( R()g/X)a‰7V¶„¤i!9h+YŲ³_°Yf‘˜*ĮĘ5/U(x÷’Ui/@µNčquŸ)6]SN…ĀO¶ł’Ns™˜™µˆÅ[ ¢ õ7‡KÓggž— ؓHó8öBS”ÕZ‰D-“čmøņ˜§óU2"F˜55ņĒXØå… cƒZeŽO²Š‘?_Õ}ixD¶×Oł~T9qŸgu-RŗÕ]>q| ‘$ˆÕt0ń”oˆčØn Ŗ#nø‚j:A¢·qŖ Čh\‘‚ ŹDXS „PÕ¤ų”s]SY} ‚¾„WÉW˜0õ‰>ŗ¢(‡)•HQś9p£y;JŲZ)b¤ŌÅ 8)UČ]hm †’ā‘] „є¢;“£’•;ģw÷é3ˆø ׄ=o„ˆTc›Ų)ĆWcʉó¢*2v%¢'Ń”Xi»ęz&•&-Z·Cm V FØōa—:R.·Ö_|Ų/±&‘w@č.“˜”xš§„£še­Y7éŒģ) hėČXŹÉ}¹B"HIIóe¢g³yFEęɎ‘ ĖŠSh Ղ6«“ k!€~¦ĀĀXŠ”Ęv’ɦP•©6÷6 Į‘åU_L·rüŲ/9Āi•ƒ,Pųc ™®Dµ®?Ź­-Y«A—Z™#間qg—é•D5zĮŠŸķz±nÕnā‰pÄ2w[iˆŲ¶•§Pl40ōp Õ„R'°ŻU¬.į3pG®Ŗ°0ū(%r©q~̛!|H'š€2ÆISsB™ī8™ūQ3”“wŖ²Ųi±7Ī:$ '5Īŗ_ŸHw²)!¢·\UŠ&ŖsP‹^x—-(+wY֜oĒ1n7AŠły[„0zįöØüN›™cė>i,“ ›4ø¤ü&ŸŽŚ“zĮ²-{­µ)Å8ŖuétŻ×|Ś?6”7ŪØ`Š›y›€Š;HS„aŗŸ ŗJ«d…²)Ū¹OK°OA¢–É<»V\ś6Ŗ*y{i 3”śTbėŗC‘aŖ[p›*«¹[ŗ3»īź­Ģ듟ń¼Š½Ņ;½Ō[½Ö{½Ų›½Ś»½Įŗ×ˆ1ą½ā;¾ä{ü™ 图껾}į˾šæņKüéÄ0æų›æśĖJń¾ūūæĄ1Q恾|ĄœĄ+ž«ĄüĄģ Į|Į|Ģ:ŒüĮy ģĄÄŠĄ!\Ā&¼æŹ€¼'¼Ā,ģÄ`-Ć2<¾Ź°3|Ć8Ģ­/œĆ<ÜĆö˜ $ģĆB<Äŗ‘ĀD|ÄHĢ#œÄLÜÄsaÄNÅRœK<ÅV|Å`ń *ŒÅ\ÜÅ QÅ^ĘbÜP<Ęf|ĘDĘh¼Ęl¬ZÜĘp€Ē4”Ęr\Ēv|e|Ēz¼ĒAĒ|üĒ€¬6ƒq\Ȇœ™0„wȌ Ȃ!ɇœČ€±Č’|Éu „ŒÉœ¼Ē“š–ÜÉ¢ŒĘ~É£|ŹqœČ”ŒŹ¬ÜÅ¦ÜŹ°<æÜ;Ė“\˶|Ėø¬»±¼C{»»æ»ĖܱÅ'!ĢĆ<±’Ą<<,“Ź;A̜*ѤĢ5ͬr̦³+Ej.ł¬›‹»š“U ‘ @Å\h–a³„‘ä¼ ŌĢ,1Vdµu̳DXBąŒÉÓ»2:T)ĻļjĻ&ŠżüΉĖ=©ÕZⓦ’óčClR݌·1gš!jó£„ ""¦š'Nņn÷…†żRˆkū:€rŗ¦#2ŅÕX¦ėQ€XH"­å…”` ö1]HźŸ‡ĖĢż.Õ$›·©Ŗ#ŹĆ£‘ ·$-±įGģp½ņ”¦˜µ„€&āŒh»%Š C_"Š!‰:ž5‹wD`HrB§ØHŒų`ÉRˆ’8‚–db&2÷Rö$‰Hp—ŪŌČ<ĄWX“!īōøÆJ”œĆś;H b ŅČ5˜’G`<8-)ķø))T©į¼D’¬x„b(Ė˜Ų—Ņq.r\„€ę-øz©«ė×w”Ėę¬!ȏz‡Ōł–8L­–u µ 9 »5”g#nŚĪ‘QE’¤Ī¾4¶v#fÄ&½@°Œæ˜idgG·+D6įL:©1wrl1 Ō“=̇Äomā/Œ“Ž“‡½ņ•TŠķŁQ  Ļ`Ī@‚¦—z!w€ŗŃMŸS9’ŅG¦ŒÕM6 {ÖA°ß’Ē1é&|£„ڱ2Ž{R¤]*ēt#Ž×ļMƤH±ō$ČD# ņx^‹ŲØŅŌcżŌi… ¤"فĘÜ—Oų ćÓj$8®³)™ś ī™÷\»4”*CåyBŻ_Ł+Ö®Ńj¼+¾Ļ,Ņ Õ$×Ĝ˜šŽ‡äz`ńtĻ‘^ 0Ą?eF hr0ZbvŃMJ¶ęĪ©bī¬yÉxŲTlŃ9·ĖˆšӎŚvxƌe’šŒźēAC%bµwyéÓǹaeP¹cb ©‚Mg6“VQŪ¹+ęõBöwHäQż!Ń%ØWRo¢ZĀdć5KqKT¹ā}9‹ Ņ:åźj{·bŽå?ŻĒž‘Ó K8ż½+F/›p~kķ*žŽPIä»ä}źügšÅkfī-ēąqøLžøA-iśä‘šZ†U X#ā¦"ņŽXj¢ļīńļštļ³G6’^!Öe…‘Ė!æ)āniėÜNav×,„²ūĪn=&héŖĄb4bœę×ÖžÕ/#όP9źĮņVՑ©*c)?WÕņ`jŪ*A‡Ÿ^Ī8”óĪ©¶MįóĶŌ©ā`chmwć£s哮ŚK¦lėō%—V€vĶ»¼¤’ė׏U¤üņŻ/w7öŹÆĆŽÕVkdi’†®e ¼/bĢ­<“4• ‹t§4KCG÷K²s÷„Ņo»pG 1€õųÖĖq’ĪjŒŲÄržō7~r)ā,“åäNs(WöĀ”Dä>°YO±OĶoK$„µO"éIGä4™Œ7‘āŠØéaF‘lĖ›&Dvs‹ųQęP‘(c¾ąü;įūOĶ: ś?BxÆE > eAßY•‡UķuxØeѾ¦ó£”÷5ńŻZć7ź)|™źįÄwż!©ÓĪĄ1ž¦oīTWź!Ī?Iīæšå1ŗĮNĄ©} D’˜PaB}„€ģÓW%ŌBŠ#N¤ āFŽ=~RäH’%MžD™RåJ–-Иp—Š PT” -籈Ö0ŽAv†ŗ,˜ŹŃófDKS&Ķ… čSĤ@ØH ņĢ'Q¤Ó®/+άIȈͭŹ"e›’lFÆuķŽÅ›Wļ^¾}[Ādh„ė.˜0‚ł`ž ˜F÷т)Lä®ņXTÄt_°oĆfblāŅ‚OĶ[!)qQ ź£ņ†ńĄ×ˆt†XHµh]J=˜OpĮōć4lœ¢mܟCc„ &ŚÅau.cqÜĖav/ØØ±č}֏–.‰ö’¾ŽQ) ļjžøķĘ®‘߆š|ōéÕ_ßGæķėī>šö± ‚°BAMµÖXsĶ Ė¢Å7…€ó+C 7ä°CK2o<Œü ”]"äjӖ[‹“ĒhÓ„'ZØ"(”BmÄŃÜzģh”:Š«Åt*Ц¤‚Ē]܊‹³ ÷Į° ]zr'ŚyH­ånڬ3ŲxTÄdžŒŲńGia2IØhńČ3æ,ČɃf¼h“£Ų3˜ä`Z a‹”žWBc ]Nē4śčy>ÅӟŗŠ.j5±^ēĄŖ“CÓ 2żEĻė`zz×āßŖz:m© śh®–—3Ÿ€‚Ś-tņŌJ»Ė¦ó’" ‹Ņ±#œi÷R†J:Ō J·øŸ’å>˜ą4·4˜8 6Ļa)~,¢ķDł^ņy²=»Ó9}‡wes‚ŹÓäø ŁĶĘ$F &Q’ Ā³ŗf’8JLJŒ©O¼Œ !)Å'эWNJщ»čēĒš¹Ną©åęäXj‰ ›ņ“N©ē ]õYσNš@į7—’ZŠ™ˆL2QĄdŠØ†’ęŹ‡ĶĒ=¶ŹĒ¦čN/Ö„ˆHP„ÕU\Ća†Č®®¼šŲųņ±©„M¹8'gÕ$YAr&qgåkZ»™X Ų7KeeqH»O›m2Įs©Lk÷Zv¢)ŽąV¾É½®„xŚ’Ž\&n`74#GųĮžp„‚­>Ś«?“µYŸ(>@¹—Å-‚¼wéy Ģ@Yäėū=ŃJµ“Hē¼Ē–’¤/}ńÉ/®¦ōE T1ĄuN2bˆ²7؇‡ĪēėZJ“G¤įŠ xės–AW!_Īįz@‹T”IOŌCœØuėĢ—Özw>v””Įn×IŖ“sbČŖlH#'U?‰‰G°1!^uĖ/ĪĻ"Ā^ž÷~IœÅ˜”XP)75xNB'­ÜÕćŻTʬ€T{%{ęi5 k—$91h;žo±@‰g£8)D:Ob„™h<Č:`å£l°õ0|ŁHóŌŃIVŌžū1=uśˆ•#ӆ÷C!ŒkŽÆyę“L Ŗ.IŖc€öęWßś.õC’żėwßūßųÅ?~ņ—ßüēGśÕæ~ö·ßżļ‡üå?<ś×ßž÷Ēžõæž÷ß’’ĄĄ$Ą4ĄDĄTĄdĄtĄ„Ą”Ą ¤Ą “Ą ÄĄ ŌĄ äĄōĄĮĮ$Į4ĮDĮå ;orafce-VERSION_4_14_4/doc/sql_migration/gif/Thumbs.db000066400000000000000000000650001501757153000223520ustar00rootroot00000000000000ŠĻą”±į>ž’ ž’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’ż’’’ž’’’ž’’’ ž’’’ž’’’!"#$%&'()*+,-.ž’’’0123ž’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’Root Entry’’’’’’’’Š]ÕĖQ’Ņ/€256_712dc7f1b4f7f0d(’’’’’’’’Į256_88892e1f72faa1d3*’’’’¬256_f3674027d7ac364d*’’’’’’’’’’’’ £  !ž’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’256_71ebebd8f4b034c9*’’’’’’’’’’’’j’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’©.߮ܞ²ÅŪ‰PNG  IHDRR»C .sRGB®ĪégAMA± üaSIDATx^ķŻ”4IšļlŪ¶mŪ6öģ»=s϶mŪöķķŁ¶mī™ń›™xÆ®ļ›éŖīŖéźīųæÆ15]Y™‘‘‘™’<ȞÕĮ«B޵łv”8ȇ6ߎ§łNČß7>cÆĻ#…(ßĒ7>Ē=¶^NJ›m½Ž 9ÜęŪ„ĄŲėóø!ēŚ|;^tėµ r…Ķ·­šÄ6žĘMC޽łv§Łgóķžgn½ök‡ĢāłÜ%d7;ČYBN¼łv”8OČŃ7ßvĘ=C.råkł¢G%ä›o;ć!‡Ü|»˜„#hōg„\$„{ĆÕyzȕBąo!_¹|ˆæż3ä>!:óB®ņ…ļ‡gė3<6äs!· ń· ydČOCƒ+†øĻ³C4ŅóCšąø~¹pČæ6>ķŁó­®ļ7CŽņ‰w†¼6ä/!?łZČį·Ä}ĘÓ’²ņ™#Ös6ß¶ĀķC”éŸöģyPČłB”'„Ü D=ž"äą!' łGČ-Büżi!Ā¢¶ąhĻ?m|šŽū‡Ø£/m|Śńžr”æqː3†ččōĢo_=äČ!źųˆ!ŚńP!_ 9CČ9BŚb»śŅ‡…LB}œ dŌ!Ą,€ĘŌh*į…!š!’ ńŠß ŃĮī’ÖT‡ÖA)ļ1Bx—”@M|8ä}! >’ŠĀ0:Üdēļ‚Co½&ņąTFŸÕ …xxˆNt™Ų7äÖ!' łnåb°†€N}°Ķ·P.FAłÕłļC\£Ģw”Šļ ŃŸ Q¶!‘õ”ølˆNÆĶx‰Źīš·†0¤Ž3’Fą“!o 9aČ{Cś€2„ŽĮCčŚOB J:öoCčń·CŽĀ(1ō' ¹Mˆ’æTˆĮéÉ[Ÿ‰AĆwüÓ†0Ąg YZĢbT‚ŹŌŃ Q :©ĪüéVߨ„Ń)å›CŒā÷ łUˆF£g3‰£ós c$9yHŽĪ’ĒąžémĢ‚†0V Ļ”¬Źó³“…0@Źž‡Mg§ FFį3!ē ńœC%Ķ~Ņ\÷śACš‹…h #æ:vŽÅ+÷Čņ$tt#,÷ūQ!¼$Žƒķŗk†ØOõ­³Ŗ£†š _ŅÜK[%² Ÿ¢Ż”‹×ƒ„ C =é ŗ¤ “†W¢³óžx)?łEˆß8VHVK‰YB€>Ą]½[ČǶŽć0O¬ß6€{…¤ńc“ŅĶ]C`A0jqė‡B×<“N ‘s‡g…“ķ žcBøģMĆ< ;Õ§Aؙ§ņūFīŻÄR„«„š˜5 Š/€ŃĻ4cĢŻ„ʼ3WJ2Å(lĐĄ¹jČ BøŹwę @Zń.Æåh!ž· ‰.ÜNšæā:n¾\ĆCÄ|¼±µQć¬!\Rńõ·>Ÿ;D‚P8Bńd蹆\G±¶aü“-<«8T.ÅØŖ|Ļ į%IrYĻ"/ņ:1—Zų ĢÜķ¶’ro¹Ąmą÷µ×؈/ŌSæ— ¹\ˆd™ø_ī’™õ®m…Žf}$ģ>"o$ŲmėS»&„‡"g%ŽwoŗFRד·śT‡ŚVĀRNE™=“X_›„a™DŽ’†¼u:ZĢ’čbiq½1«šŅ‰SKb³k©x^üĻXHÄ5=mA 3ņŒéGI+™|ö›a „a(ؐܓ‚På_ŠyYū¾!”fD6ŠPV H  łzˆģ4œ*ä”!\NĻćäIŅ=ā|å{wˆ¼ƒžaäŹ3źšŃņ^¼-IčYøķ #|æ­÷Œc¢ķū†{0DrTŹ'i+±Ėø2:rKŒš*W!»ŲĘāģ!ō‚±ņ’ ®\ĒJ`€RČśVü€q§ļį*!F|S0 §“IÄ\?„!Pnó½]qĆʆ¼2„'bŹĢˆ/žŌŠ<Šč³Ž§œF9eŠ OĀ{1śė¤ŹØĢ}ƒ¢¾:Ä4”‘‘w£ó(³—›© °_Ź”Ī2±ź³Ī5?S„FE³:’ØŒ³Ž¦,yź‡Q÷=O”2ƒā™Œ F^_–hŸ>Į`34źNŪ~*DBPd‘üJ# Ć«O}Sful4gŌ\“³BKE•+ƒMA¹eÖ|4Äō h,Ÿ¹Š:æNh4~}ˆŽhD1ņś®}¦€¬9÷ń1RR`n*Ć#$øye‘!öj„ūHcįŽbJIG3}ć !žŒ“FQF)ēÖ­­ąĶ(«Īft*šŌ‘k¶!Ą 3#cŌ7 “—vóā2éf² Śž!¾gø„B0Ÿ½£Ś'ĘS§5pØ/!RB›S—Œżp½už×“„pArŁsšD…CÕė®c9Š)³Ķųˆ„Œ¬ŹĮŅņĢh# KM)dpu: Ę(°ębĪ&Śä(š9ó'…0 ī#³īŽ\;Š@¹)ŖW@cėąÜzO©)æųSłSƒÓŠ5ą™ut£„÷VT*3ćgśLŁ•…²šĖfÄŌ‰åzS…mgE K@¶Ž€1ä*åg†J=>ĬŽŗUÆ@jC sVķ«ŽŻ›G#oŠvö M}Ņ5’¼!Æ‘72šš’xR©kĀÓÓ¼eå («ļˆKø >å€ FÓņ>ttō9€UBĶ̆µfśƒ¼ŠčgøŠ«£M—v'°Žé–ö+sŁģ!t0Z·X4Ę^ŸŒ)ļMQX2ŲV,Ö. k³bGqu”PX3H¤1²Ą¦ …ĀĮ“ EJ¦ e¶ …ĀšĮ¼’¢–I »†Ušč ĄĆBrļśa¹ļ˜9ń K€2{ö‹}Ę ķf%¢.…BaĶ`„%¬…Ā\XÄ^€Ā|°\Ś–TKp-†) kkŲ­R4Ui_@”PX3Ų„ĘŲŲT(̌UJ"ųX—¤¦0Ąs«ķĢ+fĮßW©Ć ˘¤lwµÅy¬Ą6„eØķvÜEcģõ‰wYŠ:+l”_ŌvąłPہūÅ2lŽÆļYŒ){£®ĘS7 w A¹”@ųp»Ķ·£ŁĒ¾A…ŲXaw„eŁp÷¤5HL0.ķ6nbÖgœ˜…«ī “Šy Ś'Üzøą±õčäŽćĖCõ²D•ŲVpéY_ļ°Ģ6:;†–7…$ģGĒҍk‹=łŽlņŪÜS d5¦^Üw}ąÅ!žAž 0ōå!< ĻĄ ]0„ā29E“¬ņö ‹ÜõX.EF_†æ]•{3Šh©XZ čo:¾…A„äš':ėƒC†NŖ#o䀏P[Ŗ7|VV*Ÿė0aŻÕžw‡f$ķՍ¹ęźk&%ķŖ®t"u©¬˜–ŌgB ‹*Ī9 žŽ!h`w~IH““Հ§ß(ÆY„“®A«­é>ĀUu‰Ē0V™(ģT8/-’Ļ`ł ś°WĢjÜm’ʵjŽRz€éU0:h”Ł*O®B;OQ# …#nņž(¢<¤%C9…Ļ MŚ.„ę¾=ä¼`P,¦Q±MņL'1<(Ÿ°˶ļbs†į„x6F”oč -:©„2Zž¬‰zóŠ®J1V\bĘ­E@E•×>.d(hk‰H܎PMø7ćoG%J5ŗ¢ĪĄŖoәÉČ;’jN}н„pĒgĘß5YOhŹč§Ļ:iN³:ÜCYљ¹Ž 4+<7Ƃ»y¬nG:¦żqä„"ĘUAēYPäį‹L0¤-÷ÄŹÆ¼Ād«ŪĘś³£9:o¶b}“×āŁõ^%ofÆ`)ŸōĖøcF‘YAłŗ`&Xōäżd¤oP²¶Gƒ%tävh&Z£b×£Į&”SY”ņAwØc×ŗŌ'‘c„ūŸŃb”Ś.ØŅɄtmušŃW˜øÓŃ` uz»Œdsdß \ū [ ³zÄ›•Įäč36Œ=k]³żb)fŒ~‹®±”8šK+įĒU÷¢q–4ä’!©t¢ —_l›ńgrDlC Ž„“‡$JüW•k'$rš‡2į‰ēp÷F7åćrå&ŲŁmiĮQlsūäO”‹‹Æ\”źĀ«¼„³ģё;łĘhĖKpl˜$©²ū”OBH1ķ(«.“ąą$%9±§šČҹ§øÕ}A{ņų )lKĪŠĘ²ÜĀFmĮ½õlmж>…yD;«Wŗ¦sz„ƒFSן[Ž’~śŽŽ9Č R’lĪ^`$]›žėvšū]iĮ¹št^čÉxhłģĀbķĖcQt~øŽ×„~…€]H]‡Čcµ‚Q9Ī„“ɦ8NźŃ)%=Œęr ØdæÅܔ4 „o¢«@)‘‘҉æU®Ü†ūį‹wRģÆÓe•Ku@÷–$źBµ±$õlóm– =„•”TgF¦y¹Ę˵ÜI®$E7Ū”æĶōUWĄ¹yŹ$/Ā`:G?OĢQ‡Ķs<“ü2:…‡‘jhwYm‡ž8ź\ĢŪmėS|L×*„&k®Ć$ŻäÆĢ@9lEu:†Ąl•ś÷‘„—ˆkŖŖ›®€Y‘‡ø—ĆV¼jKIvķÉÕwęć"d±Cl¦@kƒ.č}@ˆ£Œę„Åż*‰„•õ”ȲĶ{£‚"+G9U¼£š$¶ņܶYĮ³–Ą’S ō_ft.ßéą É6ē×QtJj4åō]²ä™äQFŠhŒ¤$–ŗ1Õ F!ŹÉPč`āaž#eŗMŻśŸŁś„zŠitxX¢ĢhƼĄąč`”Ņ“0o†—QgDyP°qŹ)&ļ2ś<õź^ŚPŅŃ{±3ż¢kgfšy&’ć{†^‡Óö®‘¼dģ\«Óõ 3OŒŽŗ7”‡ ”)? A@&“ØF=;¶ “·äe',ĀPl£”NĒr±ŖF2ŹC”ø…ÜY#“ėtVĆu,¢Ī§ēY²ŹĀ '4²ŃS†•piy'<®i‚g@ Œ¶2µŹĮhy픋!b•‹›Ļx^§ ƒ29ؼźĄ(ĄqżGʉ7 gzLóĪ[O‚Įqf"#i42{Ć=V®²ĀHčLŹ7YOføĘ:£ÅU¼×dČŠŌ Ļ1gĢJ©Wŗ¦žøł cĘ£aČx²ęōLżźl^é­÷Äoō ^ų«SˆxN§āI™šĪrŖóLŌŅĮę)ŁĖµˆ€†–åęęš²Xˆ’h,.,%`d9YoSF¬÷ˆāńÄߓŁå.9+Nö*V=-M÷ØD‡Zźp,¾r™«ę†Qh±—Ń‹”āV¶E›˜Ulē^¦™L暴H¬Ź;RF® ļ…±0]$?aō§Ģž‹ņ˜Ļ6ŒŖ\CFd'tɘvԁdøuńF“cĶŃ-Ba8ut®«łjß;‚M¹µ'ƅb+§ŠĪo·AŪWœn¤®1ØźY›`Ŗ¦Ńņy3CŹĖčÓ+mļYxS:azŪ”k€‘‘ŃÖ~›7 |ó’ fæĘ‹ŖŃś§ī‹ĒŅ%ē°°ĄØY€łP³żb–ĄncæE­F¾ÉEc‚ʘw†QX^M` {}ŹS±›.śŲpą*1q_ąĘri¹]Ó\ēBaYŃ6ÜZ;Ų("W±R+„ …ĀtHe2L‚«P(¬!śž’*F‡E¬( #A€BaQ PXc”(Öež6ŲLc!‡×B”°F°~Ūzuėj”D”°†°%“@¶Q(Ö B#[”ū\^\(Œ«“ĄM[dū2 ŪBū‚ķ¶H(Ę Ü¶¾Ś*» {}ڲŽyȖćĀ. ¶χŚÜ/–a;šØf QHX“V ˜°h ĮYXų_h7Ū^ z­½įÅŲ  y°˜Ö³0”-B–ˆYEƒ¢†’9Ē¢ƒ½ŌŌ&'Æ {Äü‚eGŗWL<€U4F’<øė®)8\hI †Ę ÷²Fl'ˆ0¹©Xs&÷‚we÷BüŁdB¹å;3· Aź9=z2ūŠ1ąv=¤-ƒM=DL4˜~Š}aÕŃį0ż SĆa‡=F{`Ōa ŠyŸ¬ĄmцK.{Ō_łŪ†Į\¤-Żé§śTwź‹1ČöJˆéUüzhĆŠ–1ōźœŽp—µ1”iįW›ś¤g0„ĮŌ.ź«O ©Ä™ˆź« ķÄ`ÖÅj«ŒŒCīYPi”ŲĀa§ż=f`FÖÖk¼w‹ahQ„5OĢ™x%ŅśŽ>yTįbödŲUó„Jņ:łY»y†ę5y؆°!æS^!ĮnA9µ]p${ĪbL–ÕóĶ£k£Ē¢ €c¢Äa2°Ž>āBzÕłe5ŠäpƒeėĶˆĆ5œ2fåtėFåźģĪµÓłÅŽ|r.Å·Źt‹’Ģ80žO|*“9 DYš9„>!AÅ}6ŠČŒK¬ŹIØÜōb[±>pŸ¹Ć’°ų䵫ŒūXÓnņ)²äŽ/Ė$*£ĶŠJ :PÅ5ņBĄ5Vź_l-÷³[Fąm!ų÷µ”¶Wgf„„6Źä$&FAH3ˉÓKƒEFģ'É%±"Ž“hQłNB1żCńYg‰@†BLę’@ĘC˜œAhń4å4‚R@±©XNć+ƒ÷²ÖŒŒµ ¬0Å«:¦IT¢Š¢g‡cøś†ß–št0ˆ$•UoņźNŅU|©s)“ņSfŁsL9é¦yŗQŸ„”ĆŃyžĀųFRņTA^…ē¢ ¾¢ģ¦Ö$%ąl!‘Ź0гK}e’w‚r1źŚX=é ™²ÉČOń“+ÆO»§7ŗrX”ą¾NÆq˜é nŹĖ4÷ĢԌłSR§5āY/`ŽX˜ž—ń0½ĒĶ7=©“ķb“’t'ó0:ĪkćPZÉi;f3žŠN0”•RVī½:2Ŗ›[¶¾‚d>ņślžš×¢£yFøŚĻ=ü>c`݁iG”Ń\YŒžfxO:ø¶Ō¦<Ól®10tξó[C•·‰,;c#ńĒXI–fāωP¼CĒÄńöv«\ Į<iV°Øā@S>Ü~ē“ŃĢó›ą ‰)Lž č;£.…×øī“ÆĶB S‰f',īšŪīĮń(§øŌ}(¦{q}Ƭ~›' Rž Ć!Š†>¼ĶĀ•&“Oęņž²×:‹5¼Źėˆ-£”ŠEĢŖÓq£=ÆD}¶E›…@ £%×Ų‘`:ŽŗŠ®ÖlØ'ž‰Ń];ņD2ŽfHy¼Ē•Łp„ŽMZų$4Tļmе>ŚŅŚ!&OÓl’ä'Æ£[Xå(.z¦œ65 t…:żB E¢-f„QN×4Ńv Ļ¤ŽNŚ6sŽ5km”¢D³@¹LauA×Yķ×ēҵ]ę™Pö6ŽļvŗÖK1 ®ā*@,j÷ÕXa‘×w¬s×'×WŒcÆO”¬ĆFG½`• @.<)Ę‹ˆ„F…B”P( …B”P( …B”P( …¹°OČŽ¦÷ Įā³7 {Ś –¬N»¦ K„›ŲŪ‚‹K,ŸMXŁhUdŠæäP(Ɛóę6‚`±Äs;X–k1G_ 06Łxb–-–«ŚEg“‡Ķ'6čĢ–ÆŚźé!¤ĪØ£[¶ŖN,µµ¼ÖRUėńķ {C!ĖY=ź-ßŪĢā½Ķ%–¦ŗŸ-Ī·±¬ŲNF;ųģŽó›:»ż6óųžŃņjjī@³!Źę˜dØÉ×B”W ±Țrښp#™ŻwŪ‰]a¶•"¹“ęŗX[žŠ»ųœšc¶&Ż_ŪRŠ¶×Śōc)«…^­ŪÖ­ ·ĪŽ+X÷Žõ†a±Ą!slP²¤%–滞į°|ŌžĀČŲTb½¾gīmĻc–ėśÖÖēĀėü­‘_Ł(…Åc`ˆĶ^mš±„ĪĻę¾XIEND®B`‚”ōĀ;^’A Ŗ‰PNG  IHDR?)ŖsRGB®ĪégAMA± üa>IDATx^ķŻ Ō}i=šæKB¢$…H QŗŒˆ0BM+Ef$„S)ӔĀha”AĶ ©©‰š¦’ŪX*riŠ2&¢B¹Wŗ¹–k¹’ļē’¾æµžŁĪłŸĖ»÷y÷¼’ē»ÖosöŁgŸg?Ļļž<ĻoĄ±£ƒŸ ½xļķ,ńE”+öŽĪŸśĖŠ{š?ęŽŸ× }tHŸĪŸŗ’z$ščż×¹āAūÆsŗ†®µ÷öj¹÷ēLJnæ÷v§ų”Š-öŽūøŠ÷Ž.ĹGÉ ~pļķ,aŸ¹÷v#Ü't—Š’„~z’ó…>(d°?*ßś¾Oč7ŲĄ«B’~üÓü±mī Ą'†ōé"œzhčF”·„Ī=!ōĮ”+C7½3d¬æ0ōŠŠµCŸś“ŠG†Č/>ųšŠw„€Ąć‰O}IčÆB -¹ø’¦c¾ äĻ a‚W‡Žś¤Šg…žŗač !ƒüa”o uĢ× żżžė„¾?ōó! ąV!ƌ°’fčmūĒXöKBĘžkB”ĒW…~ T xnŗIč"N„])€[‡Z÷ņś!7€Ŗ ‹Īq£p׿שĄU»ĘŽŪćŠ±Õ¾B{Īg†Äw»ė¬ÄuC_üÓ±cļk^’.ä¼·;pČøfˆĀ*°V˜¹ćŖxčCʏ€]č Bw՘SņžBśÖš ¹ń®s ’b¾åų§`źąœŠ?‡Ģo…>;Ÿā¶üiˆė¢. ½2Ä5Ņ®…¾;ō¼süö”ē‡>=ō‹”Ū„ŚĒĶ:-ō”;„ž;dž5Dū–v½č!ƒD Äļ†ÖŶ.«¾Ą(„×3ļ‡Ÿė“)Ę (rżō®·Õø²\?Zi•ÖÄ!ĄćBśĻ?_r£…:‡€Ć†¾6ō!!q0åšĆ””šo‹„hW0Po Uū^znØą’) mĮ?(jšō“÷^ė=“Ü?LEαjxģ!a FåņĪųĶxß/d¬oŅ֏ QS¢Ę­ųæŽA{büīśŪP÷Jf=¢Ūßy]Š)ķ÷¤÷ż!†U85TŚŖ…s$-œcŠĒ`Ü8ĽA’śķ8©BƒƒĄ÷ŠV„MiVn«ör­AņE(Šŗ·…PBĀę øehxĒZˆ!??“‹éq«öPڦŽ[ś”9@šźøÜĄŠÜ4$Ē‚x+c‚WäśЧ•?JĒŲ|^ˆ×ä\ŸQÄuĮ»n’k)Xŗ)¹’+ōŸ” ‰ Žq½Ż8¼;Ä#ØsĢG{Ļ%—éü—ė9.QĀEo±MP׫’jŪ÷žŠW„Ä]Ą5–a÷Y.€{;Œ½N„e.«µ ŃĶBī‘×óÅ!ˆxŸa’’“”o iĒ?„0Õ7„~%$<‘Uv JÖēß ±n„šÆCē…L zaØÅ˜!ĄY!}+¬3vĘZfZé·10F `L…uŸb“•¢ĀŪbüPč!±Š—Ę–"ūS˜Ę“Rn ƒp‡Ņ'x”0Ć@am’Ü=ˆĄ“€¦Ó¬œ3¦`œš„„7ń¾}ZhS ėĆ瓆¬¼Ī#¼4Pi% `ĄÅ2:£ķń+wŃt°¦˜ 0ķEKžĪwM’å“ u #²Œ®]’9 ɳšbä²!›Å*ų¬6ĶŹ#®¼ū坰ä¬wM®R²®7lĒÕÕĻąžyT^‘䕤“XźYŪ:§ś«0„1BŪ)fć'glxX=å%“¢Č`ĢvĶnœ ŚT`M¹é…ąZīČ"ŅŖŽhIÆÜA.$ה+ȵfé -/ć)”¼zkˆņ ©[˜š3h–÷Į…cåĶē²ČeŻ\˵eB]‹Å¶ąĒļµĻo ”6aP–‰å’EēĘžMHüEĮpĆÜåĘŖpo)U‹˜\ū!!Œėa4æ[ gź‡õ@>sŻø{ŚdšØ¾sÜ’:ī¾y:‚°Ą<֗Ą­åčy7ė@ŸČbS’r)¬$Ėš/ =9dVćĒC”±d ^éCįaä’óŅÖÅŗż¹ī• óJŒŸE8Źó²¹6ĻPŅNx· š¾Ó§Ė /Ć+6d,ɂl~/~e°„Ądµ]*Aģ7Å[Œ-ŚdüOZė²ęā—1Įrļ E; 0Å’n Š€2Ćh°®Ėźw„2”˜ ®A7ĆÕ'—-Ĕ†ćN[܂q(Q"t’OY…mf08…Įz²īŪĀu†Óŗ«p€0qńė^ ”q/”8G­ĘoS, Z˜ĪsŽ0Ņ82jö}ČPĀ‚Ļ[၊įyæB[JŹZ××F†Š²āym2ž“ĻL!„(üC¶šŲ–yø¢¬‚A¤x4=!^üZˆ›Z13eĄŖ±Ø<֖}*ZńņA„6žƒB¶ŠNSø%üPIŲ©@øyG”_Ė+”)O“·D9šŽx ’Ū—‡€š «…Ņ^€ĒŹ`ר`®ŲŌe„É%11&7Ÿ+H)8į„Ąõē¾b.øPĖąĖ»p­-‘©÷›UŲ48llڟ»ĘŖ@jń‘}ĀØŹQ<ŽŁ”6PĘy豬’SŽ’3œ±ŒRBĶZ€ŽŽ£ŠŁĶJĢŸ”9åwtY„ĄX°Ą…;l‹äŒi”ŽŽŽ“¦T¬Éļč8Ҙz°££cĘč  £ć$FW'1ŗčč8‰Ń@GGGG{ś-@öłwttœD°~Ū{kš•iźč82č ž?ģ4“DŚ~š±KCwtĢ Gi/€Ŗ«öяŠQßŲ&:ę¾{Må$»×)2Ų©‚TĒŽ`_²m§«ź¶©f«ĄĀ¦0 *šøßõ_mõÓePdĪPĄbĪP¤ķ’¹cīżyµĄ:!€ā–T”$•WŹU‰‘Ua%•żRČÓ^|õėķo®rJö&{Ō’ 'ź–Ū]g­½Ā ŠB*xQūĻ=’Oµuģ•IVR̵4𪬔幪¢xšĖp›ćQ«°kōz'!֙äVŪ׬ō!&x`AøÕKSl€Pn ģ)WŪ #±*<%Ą)õŹ”Üf­•¹r¬Å®Ÿ ŲŃqRc•PŌ@Énåˆ<6©ŠNŖB£˜¦‚ŠUFI•VŸ§ 6ŸŚåJ.Wé%ĀLš:/B“˾Ėg¶Š®Ö¢œź¹lēTh£FŪŖ‡“L…EĻ}SüT[µœžOż¹*H¹ ō6PąMY¾¬cÖIŖ6BQȎsŃĶ«<¢äQƒ4pźšQ®i+-$•œć\Ē\ƒŅš{‚Ī»ĒŌbõ8vcÆ-āW–J~FU`9!”šg$Td^zwŖ)SśQ”±ŌŹÄżų׊?ĪóŸĪ"2 *!{F„:}…ƒķŲĒ:!Į3'Ž1¼Ŗ_fp¼ēž˜*Āé;Ē)ƈ²p%Pרßsåė±ĘĻ\ߣzO1ŌõėųXE$ µgF»ä3(4•V[“óĄŠ˜Õ³ ĀĮKRփ@ ÕKC„Ļ3žTVK®U>e}Ö÷„•"QLRÉØŖ¼)ŒńTčIJśĀćŖ(yi”xj~#™Ø­JS+·żČśurCkĘ3dõ[h3cCł–ēG”«iē³™#c° X ²äĄ¢ą»ŹÅ\zĻ[«ē“aJ‚" YęJcb÷”œóTPń÷ĖCž!G¹:ķā©»€0²śCčw^ %Ā›į‘yæ øżŚAéń"xĀRäisyŚHįšš<†M’™ ŖēŲé7×sJóäŠ ¼m/ø.eÆÆ…Žźź©”Ū12¦ZĄqåLķaVƒU§Ŗ¶#{ėį•\yaå "&ņl6®fk{u>3°hŖ¦]ŚmB啹²˜M¢²ĀšŲ1yŠ 0Ø0ūmµ J­¼‘u±‰ĖŖ]īŪõYTÖR?¹yįS•G'čĀ'żF‰DUdy8j¾U^Ó¢€šć×Ņ7ʉ°šZ-©?(męåłķ‚ĻŖ{K=bĶo(%1 ˜W%yģzņ=Īõ?ųG½{׊…Œ€)€Įā¢>'Ä ĖbVn”Œ>Ė%öci¹Ž˜Śo„2ż˜‰56Ųb\.!ʖż[bj®ŗx“¶Q«0ō0ų¶›a];~‹ŚVķ_§Ż‹Ą”hū?T>`]t0¦*SNųe¬YіQ=ŻĘć”ÄŖd`ą% ·UÜČņ°ā^0 č|ē˜yšŖMfœ–ę÷æŖmslw”mū.Ʋc¦Ų Ą].³ø+ɽ J“Q¦eš=P’å'ä¾CM†ŌČ-p¹„-j!©J×1eH”Ī Yæ ī狳%±Ä¢bZSœ<^„„­õ >ʇ+łĒ::×q„yÅ¦ī‘ Ki ä(2Ļ%äŁ`pJ­®p×eøµgä>%Ź$Bµ™g#^–ü¢<)U!g½q«…Fś”bsIR ?’ćžü†[mC^ [xPśShę<łŽ”1Švßł Fā³ßŌ8JžéW}¬_üĘuj¶FÜļ1īĘĘļć*¼R …TB÷-\0Ķl”™ėÕ ‡¾Õ^Iåz~žē J€ŚžģŲ­ebPL\Ģ“ T —@ŲOy¶?įbH$¹_Ā)¶Äˆ2ŌĪ„8å#ĮEųä(±ŹHlˆĮż–°Źc`P‹›&„RqÆcf–Š+—Õ’Ėņ{oÅ£ų^8Dx=÷Ķw¼OuńšMBA9ń†„Fņž—Ā!”²ć•Rq.EAų=¶ūŅ!¢lKÉyų©äžõg„LĄ6 |”—˜Īqž›ĀĀ]r]q½žš*V—§ŠĻ.ń+ާœü„NYźK϶£7Ė”ożŽŖRY×ó{æĮKYRJC[1±ūtŽŒöÅ!ߙ*³ ‡5” ęrYµf9¹Ņ‘%Ó.Bįž…QīW»¼÷¬ÓBBŹĀu( sļīÉ=ž"”U»jg¤ūDśŪ«¶ė+ī¼’ 8ÓÆ+}lö†+ÆÜ_-Ą2†ī©Ā8Ÿ¹ēöwēų/”š¾ö=ĻĘ*×6…hlܗ’÷d\×āšBœCI åŒ?ĻÆ(Šā”‡#`Q` $ėiĄ¹Į,#!—·ķÖ#ŖÅĖŁćŒ ±l=W·¦l¬^ćĀĄh./&å*ĖšcT–Ęg–‹ (iHa<ĢĮ’`2ķįZš]ĄL˜ƒŚY.<›²ÕÖż»Bą÷„ƒ@AÕ‡+B–C»^GĒ$˜BŲšcÉ«Wx¼_FÖó×9cnöØķ¼®kMD H‡bjŠ+ĢaG£6Ųö\Ū\m~"„<`ń¹ćµgĮ>ʁ·ŽrE2-Q¶qÅnEŪo…6žPµ|YOVØÜc³o€ńžēdŪ®%ÆĆڳå¢āΉĄõf}Ē‚’¬°¦”›×įqļŪćõ¹}_h?/ū+Ŗsź=,{_ēÓ~īčččččĒŽż˹’–[›Ÿ=IEND®B`‚‹že«¶*Åx‰PNG  IHDRCsÉŪsRGB®ĪégAMA± üa5IDATx^ķŻ˜e¹šAAZP E¤)U&4)!HĀ„Iæ ÷"pi”xA €HŃ %HB"H"# E©”‹bči0”½ßļŻ3qŻ»åĢīŁĶŁŻł?Ļūœ9sĪ̼ó~ßŪēœo®¬‡aŲ°a:tīŹŪŗÅ[o½•½łę›Ł +¬PŁSæųĶo~“}ó›ß¬¼«OÜ~ūķŁ7¾ńŹ»śĘÉ'Ÿ<īoūŪ¾•·%j‰“N:éƆ€æžõÆ ųĆ*ļźßūŽ÷*[õ‹żčG•­śĒŠ+®xQeŗÖ=>Uy-Q¢DDÆ6ÉW¶ŖĒ?’łĻģ†nؼė~Ü’ż•­śĆ‡~˜=üšĆ•wÅA®3fĢČRtiG­šōÓOg’ųĒ?*ļŠįńĒt­Æāӕ׃M7ŻtŌĘo\•įŗśź«³ 6Ų ¶?ųąƒläȑ±oÕUWͦL™’=öŲcŁĖ/æœżä'?Énŗé¦ģÖ[oĶ–Yf™ģ”SN‰Ļ×^{ķģōÓOI’rŗģŗė®Ė¾ņ•ÆdóĢ3Oœ³-¼óĪ;AŸ’üē+{Ŗ%Yo½õbŪÄ<ōŠC³I“&e묳Nš…Ϲēž;?~|lS$ß?óĢ3³;īø#Ūh£²O}Ŗ˜]w\5ł5ć8yņäl­µÖŖģɲѣGdņÄOdS§NĶęšk®ģÄOĢžō§?e/½ōRvńŇŅ_xį…Ł"‹,’żå/ ™÷ė×/ūģg?ć°ģ²ĖVĪŲ2ī¹ēžģė_’zåŻæƒŃ0`@¶ą‚ Ęū_żźW³ ł3Ļ<Ēžņ—æĢę›o¾ą÷£>Ź&Nœü¦ˆ=ų²ķĪ:ė¬Ų§ę ~sÕUWÅł~’ūßg_üā³”Šdƾśj¶ęškʵZ˜1c~óĶ7'UŽÖ5zušśėÆW¶²ģ“O>ÉVYe•ģC‰ óī»ļfoæżv(é{ģ‘-¼šĀŁ“3˜lļ½÷Ī~ö³ŸÅd19^|ńÅl·ŻvĖęŸžŹ» MŽ?ž8ūźWæš}ūŪßCE¹ßx捘€x„Lūģ³O‚^x! ž» dų÷æ’½ņ.‹mJ÷­o}k¶<„2dHšd Ž;īøģÉ'Ÿ žæō„/…²o²É&aØ(Ś×¾öµŹ;×4N9[l±0>ä„ē­¶Ś*[|ńÅƐ/½ōŅŁ¼óĪŹ.B|’ż÷³cŽ9&^ˆ|0"ņw¶ƒ[n¹%[h”…²ėÆæ¾r„ž>U0įx'`śōéŁ³Ļ>;{žėo²š@<«hA…œāū¼»‘óõŠC…‚÷ļß?&fĪ3˜Ü+Ƽr¶å–[fK-µTģėP~JĘ Ś~žłēĆQQJn,s>)ę½{Yc5"bųō§kˆ®øāŠŁ’ųĒģ3ŸłLö“N:)®ÅHåĄ#Š>|x+ūŠK,ĒįŒyä‘8ßvŪm†Ł¹Ö_żlēwŽż½=® Ø 0jŌØŖŚ€Æ¼ņJvß}÷ŶÉ7xšą˜”&«n yQŸÉ!Mž ÷r<Ļo‚ WX`˜ŲՀAnøaeOupĢ<Ū®Ē;šČ&¤ūĮ‡{š*z”x¼/8kÖ¬vCé–pģ±ĒFzŃ\ź %ŁQ,!¶Ō‰q"Kūɍ·Ģ•¼^×{÷"Ķā­[ 훂g>ꨣ*ļžä  ݆۵Y¹¶ś™QtüM›6->7ę^É梖å–[.›9sfœ÷sŸū\D7 z`°šæč¢‹Ę¾–R…qĻ=÷\Łģ m&…J9aeO÷ £mĄ¤dŻĪs‘6`KüهŠ"¬ŖkÆ ˜|6_ÉXVöĪōō6ą~‰Š¤c+ÆÕ`X¢!›Šø™­šØęV“ēšDmĮ÷äŅ-AX«ˆÕUxź©§fG‰6JōF¢½m—hD"UŌÅmŸhJ¢@‘.üīwæ‹|oß}÷üN~ز.ō3fL(·”ą‚ .ˆ°UH…WYĒĄ¤ W‹„óĀGTMąņĖ/Ļ–_~łÅåš×\sMT©ß{ļ½lģŲ±Łj«­–vŚiŽŖŲūLXŖhuå•Wf«Æ¾zvŠAEMCųĖhäį·ūlÕvÜł¼öŚkĀ’ųĒ?ŽŚ¹©Aįw޲S4;ģ°Ć¢p&ģwœŌædrüńLJ!‘āL˜0!ŗm”­.(6Jtrš#„cŠļ¾ūī(ꮓŅJŁ÷æ’żĒgœ9½ā.C)Ü';Ż© łJ¤?üį³·”rœ”ĀXµ…žŽX.Å<5ŃōD;$Ś+wĀ\ƛh‰D\Ó&‰€?"Ń-‰ž3ў‰4f/®ģĖqk¢ŻžˆńŃ·ŃX~.Ńź‰6O„'³a¾DŹų—$ź0T~)ƒ=ųąƒc"É[£ä½ņBE«“O>9”Ļć»<Ø\WN{ÄGDįg‹-ŲĆŚƒ’›¬ņźSO=5Œbž\^å_GBŠ‚]rÉ%1¹ńäw’ż÷{¢@xdØäؾŸ×?j2“³Ė—SØKM„œ(›)„Š·ćŽ;†qbtµcZ]˜{ļ½7Œ©āź]wŻ®³`¤qJ)¢é ąf›mÅ=ökē‘I»2o 3¢ј6"łŖ«ČżÆøāŠ0j—^zi—DVs myŅü./Kd[É|j¢«ĶŖģc^Kōh"į;7Ā[œč¶DÓ½“Ø)6Mō‰ņ˜±QQQi™‘Øé5iB‡A©MTžńK”ģē•)TgŪ€ (Ga)¹EßĪϘRd×d\—aŗ}ą¼1V `ތ1"ūóŸ’ŹĻČ6lö1½K'·JB…ą 'Z2ˆ$WöK¤ēä󁉤 Žšī—&’ó į…üHØļ99Ö«ć(;Cą½s€'n\o6Š“ghH!nĆQGՐ¼gCŌ†äĮ¢ų4mŚ“†4)£˜å{¶S˜ßKž¹!)QC £X•&UåŒÕ”H0…ģ IA‚×JF)Ⱦd„¢Ą…æJ7¤ō į„NhH4ųõyRŹø§dä’‹÷ēw^œ«T[$³N_äƒ/<Ų?cƌųNŠfóœ2äI¾īd‹ÆĮ4$ÅjHQO׌+:ēųńćgódģš•R• ū\Œ ^r޽*’æłįŲdšƒoüzo>ķ”'»śeL„לŖĪŻ[CG~ D!Pw¢ˆ0 Q50Mņ–ął}¹ß¢]€ZÕžÆšu÷·†žŽØ<š%MššÓ'‰ŗĀåö*Ć Q­Ań*ļw„”Õ†•R€ÖžEpŽü>«­„EŃšWjåq\aō/~ń‹ŹŽĘß(ŠÖ2œīČ=ß|ó͑ﷅBicoFÆž-@ņ.Q‰V•¦8r<…!łįŁgŸĻŃ+ łLXŽ'÷ö<ųoūŪ(żą?ˆœZe]1°ZéĢiTŪČ”Ŗ.·fˆ&å߬!SE4­8æ”P«PT S8$c2‘‡+lBžhn{0vÕ<0”Ćļʍ|Qb ū=€±Õ™PtõŠŸ_’ś×ŃEšØ{SRULõ½"ćåoźŚ>Zh l*ī<×m¶Ł&&ߑGm?üń¤™ÖŸ ĖPhS©T3 *ą%Į›ėD%Jłwx_F$EĄQšóĆ+ Dy -L†ŌoWr%’¦æ}Ø%xu-<ć¦cĀxÕÅš; U†_Ŗ’ŗ+ƒ!ć”˜wT{+z½a&/o²©š·ćIUzym--m%ǦÜ2Ž/ѝ‹Ūn»-ŗ^˜ļy Ž’į“/ķ½×MĻPz‘>»“Švrt/“żZJć0÷Ā@P~‚o½õVUĻR”č&-¦ŽBSüØöŖź«N«ęڧp¤¢­z­Ņļ»*Ä)$ŒŹ²źpņ Q±.‚"EĄ9¢’Dv<š@CJ”B¦:d„r®bN¾ •Ŗīö“­c|6yņ䆞Ēē)T®i°)Œi>īŖł:ö[×Ę—ĻšØC‘µ{Phõ]Ż…¢(»]ˆŽt:‹j'iSōf£#rizL‘ć‹€Z”#÷XvzjY©īMčˆ\šÓäŚŪĒ¾ĒŻŻˆ#>LŌr¬Ž p„śčq)…ģ?ī‰ę­ÖŒŅ”(чQ€%ś0JŠs°^…¬¢l…„%Jō!–ČĻ–Ńv”(Q¢ļĄ"ŖVK¶ĀŅ;J”(Ń·š?‰īoÜ,Q¢óčqOn“ŃFļ <øī’Ō"°F­ŠŠŠ f3WBćŻ5‚qš.†Q°°G-–ļLž<9Ūd1Yß°ęeĆœX #č ėt'ęŌŗĮŃG]ŁŖoœ{ī¹įQJ”(ŃGQ€šŃGõ˜šČŠĘé¬WX[ļłēŸÆ¼ėH‘[6uźŌlƌŁC=TŁŪżøūī»+[mæMańV ąVƒ^½[ŁÓ|ćēę›oŽ j•eqC–ަųćĒūęŚĆ¤?ōŠCĆąäĄ#å"^ń¢ŒŒśŗė®‹#8äC¢ j,(«:YҜ±`€š*mGpĶ5×dĒ|(rJĮ+{³ģĮĢvŁe—즛nŠ•—ĶƒĆ;,[~łå³‰'†¼8 ĘŽŲē0ęĘŲŠÖ “•ÉŚ’ģ ™{tļŒpkčĄ`ōłęū×Ož)µć ‘Efķ…M&…ļ²ų&ĶŠ”C³ 7ܰrTķįzÆæžz .>š‚r³ÜÖ“Ÿ6mZ„śö\Æ`Ķ{Mڲ +d[l±E¬kĻ»u%,¹MN”¼)¼7įšóHÖ¾Ė;™Ģ”jūķ·Ļj ×%Üū¹’…Č#†”R 8p¶œń™+&Yó¢"«ÕW_=ĘØ%/Z”›l¾Ž ó<ćA¤ź{Œų€":Ūm·ŻfG‡9|ß÷܃ė^8 pĢ’oMeŃ=® Ø 0jŌØB³›2ßu×]įĢ  Ā¢(,' ·¬[ĻŚÆ¼ņŹńBx%,+‚éÓ§UcxᨀQć”ܛA×.ćĮLئ”y[8öŲc#ģ-GˆŗÜrĖ…įď ŹcmµÕVŃ3ńLžņRß]|ńÅĆĖņZī£ZŒ=:¢“ö@ŽdĄ³ēµ …?ąw¾óÓE]4<ŗ䏹ēĒ0dŅ®;ļ¼3Œ¬9b<ŖĮ1Ē“vŚi•w’¬Y³"ŚŌĪtóИįå¹ēž‹ĒøIE%”_ø/„ /|pyŌå8†ŒYc5bŽ›CRĪĶ=ó”%œw^Oł¬&čLŠšIĄAIŃ*{»ÉŠnZk?ēĻūŻ…Ī“-Ÿm}}<§Ékźwж“ĀĻ–e ūc_Rˆ†dōc»Zø?ĒY&¼½6 rŽR4RŁ[Ģ‹üŲĪŹŗhp±Źks“¶æ)TКzķy-Ųøqµ@ćfmĮC r°¶¬>ā‰šC˜*”G5‡¼ģķ·ß®¼«=„„ĀΜæö"ŽUq“ēhާŸ~ŗź*p¤9łŖŚIį,/g‘JÓp“·s̜€Ā)ĻŽ/žDK¼%ÆIŽĶ!EÉCčīĻńĶĆöĪ€üĢK¼5‚|Fn­Į¼ c)kSY‹Tr8GóĪ@kh© @”×N䎕ēI$ö”žļĻx‰ x~ļoEÉŌ}ķ·ß~19U‹ŌxĄˆŽ—¤@äĖ#ŃJŽ6smßĖǘk:޹®%ȍ\ĢA¼x~ķ§Č::Ŗ’9?€?÷`x}Åj÷jžÆc“¶ń¬ˆŲš§VĘՋŚ'х‰>Ht]¢]QōsńÜöæ˜č‘DVŲ}*‘aV…¤S剈Uwż£mnDŽH„;³˜1¹+‘xu‘D®ĒY·’’= U$ąå Rø©’ÆRnŪ¤ó¤ŸŠ‹·4_ųĀBx&ƒŠ*āIXYa˜sńÕV‚‹¤&ƒœŌ`ņüŪn»mXt“O‡‚®·Žz”8öéõ:·cX{^Jµ—gįżxjē­Õ¦¢(†TÄBN#FŒOoņI‘šO‘—÷Œ7SMā“£ļ0hīA§€7ō]JŪФŒŗ0|÷Żw…1įÅõńķs!xn(Ģ |2¤ųch„[RøŽ?÷P-ŚK(4£h.1 ĘMeLVr”Ä"QcN±ńä+%Į?^ćM¾ž P’‘ Šŗ8…¦Ę£9ZŖuu”ųōDg%Ś”²¤5A‘.@ÜØ·„äā5…OQn)•(TAN^±P Yō –Š”×dŁc»–(Ņ «®ą”=ķÆĪ"üčwØęĒ@]-Ć|Ī“…®ų1X‰ē™čźŹ6:#Q·CŲ—?ŒŅyLHUMh/SĻ c镤. ŁImt äŚĀļj ŚKź-uJĢ!Øäņ4x`(µ„ѝ«aė:Wœąß#vu,«ęϹšsččģ`•u Ē+!ưj²¾Ž>œ={cćc¬Å|K—,Åę?lfÕܘ—())A^^«¬ƒD"Ayy9« ÅÄÄ ::šUęS¶*QYQ W‘+k™¬¬¬ R©”UÖĆŌłŠŠŠBl¬åĮšĆ怬XoÖ2!33Ge•uÉdČĶĶeÕd …īīī`-ꓕčö›g|æ³ĘĄ\Ó[³YYYlĶø‚‚¶f™óēĻkXeØ““”­YSēKflĶ2—/_Övvv²ź‰ŒŒ ¶f=¦{’×××kļŽ½Ė*ĖĢĒuE}„Ų‚@IA vfģDMM >śō#Äü>ŗOœ©>ƒM›6a×®]x/ū=¾ļ€»…äjŁ>śźGžŽ|HvIpńĀEōöö"3-)©)PŻQaoń^~Ū¬YčģīdŪā Ń ā“ VMųęļß ³gqēl ÷£ęB æ®ÖرļĄ>ˆSÄh½×Ź·Y …R±1ĖūĢõł_>‡\.gÕd ­Zq¬āܰ}Ėv$&&āšįĆx}ŻėHJJĀ‘#Gąļė®Ž.DDDąŠ”CųqšGŌ~Y‹÷wæņ#åP¶)”R©°&j ŖNVA©Pņūęž»Y¼Ć#Ć|½Pŗ{»ńńńY5wø>éN)Īüķ T7TČ)ČAiE)®^把£p¶sf[ O’£~ģŲ¹©8qńī(ī )= Õ'Ŗž»p”*Ć„‹—ŲÖVB÷¶½~ó:+ęN˽H³„šńĒŠŠklA`||ņ9tßw”lTBk«l&³ŃżŌÖÖ"yk2FÜGąóKŌÕÕńLYĢ‚­Ęvövü¶K~±/śæˆĄą@ČČ0`;Ą$Ī]@o_/æŻBį‚ē­-o±jnhĘ4Xŗ>Į>X¹t%$¹ˆE| ¬ _‡ųŲxxxz°­H÷V FxT8<†<–ž†õkÖcė»[±ĢkŖUCņg ŪŲ:᳓ŸĶjdĄ˜G”²ŖuWė ß/Ē«aƲG MÜÅÕŲŠˆŪ·o[“LŽ©÷ŲĻߌ;č~øŪ. Ń…ƒvœæ8Yymßµ”»§k×®ÅīŻ»ˆ—WæŒÓŸžFż·õčųWŗzŗ hP >.]ŗąfļĘ÷<æ¶ś5ŲŚĶ>ĻŒ‹~Ń,iV4ó”4“ĘFÓēpŖ‡}”ų‡N6NPµŖp’ž}x?ē  įyßēŁ–Ļ÷UĢŲńšæ×Yjjj2؟Z­fNØ»Y‡€åxŠöķżķh»Ū†ąĮhV5ćō©Óˆˆąæw_wHs„żu(¢×Eóū↢¶enć×Ć~†Š”ģY–ćŽU’ś-S  ĀŽŁžUÓ3¶?ż2•Æ·/R·§bcāF¼™ų&‚‚ Ž&ęs9#:Īņ”Čł`oooÖńXĀÅÅš½Ęß’ŠŒE`@ ’ßMFśŪéX²!”!š[ī‡wR߁«««ĮsšƒƒƒĮqčgg#_ßtW”‹ī5ĻšłÅ—±}źīZU©įķć 7‘{Ö &ę–P†ßŲō[3MčƀŻŚ{Ķ÷Xeš‡ūõiÅ)b­F£a-ʙ{]é¾ kó÷äkæžźkÖbz{ö÷Ģ/żź%ź‘Ÿ“ƒ¾ośžUÄ] mKģ즿]7——§ŠöaĢf 999ӎŽĶĖL@nf›.¹Ye<ˆćĒ³ŹPaa!ŠŠŠX5”ē§\Ŗ½„dq2k1Äupr}Ü­©1܌±““4VYn”ĘŲ ½ģģl¾³Wļa×C8ŗ8Āż9wÖbܕ+WŸÉ3SSS‘ŸŸĻ*ėP]]mŃLĄ7o`ÕŖU°·›ž+åt3 My<ųUUUPŖ‘-Ķf­OĢK\»v­YOOO„……±Ź±0ĒL`ēŠćėėĖ÷^O55Ģe*nŻŗ…įį…Ž}ZžžžšóócÕdO5x 7Ŗåūā p@f6_S›¹ž ¼ŲüæM¦’ĢL Ų°a«Ģ×ŠŠĄß.›ŗXlāāāųa]KqĆc{öģ1øXlŚŪŪł9.ÜØ“„øžžāābVĶ 3=ĶizÖĆR ‰Ī“u” DĄh£ DĄ(0 BŒ€£ DĄ(0 B ųˆŽ§ĻĒ}žIEND®B`‚orafce-VERSION_4_14_4/doc/sql_migration/sql_migration00.md000066400000000000000000000023431501757153000233670ustar00rootroot00000000000000Oracle 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_4_14_4/doc/sql_migration/sql_migration01.md000066400000000000000000000423701501757153000233740ustar00rootroot00000000000000Chapter 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_4_14_4/doc/sql_migration/sql_migration02.md000066400000000000000000000525411501757153000233760ustar00rootroot00000000000000Chapter 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_4_14_4/doc/sql_migration/sql_migration03.md000066400000000000000000000265601501757153000234010ustar00rootroot00000000000000Chapter 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_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.6 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_4_14_4/doc/sql_migration/sql_migration04.md000066400000000000000000001457371501757153000234120ustar00rootroot00000000000000Chapter 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, 
               n.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.3.6 Hierarchical Query Displaying data from the root **Functional differences** - **Oracle database** - Specifying CONNECT_BY_ROOT in the select list of a hierarchical query displays data from the root. - **PostgreSQL** - CONNECT_BY_ROOT cannot be specified. **Migration procedure** In a recursive query that uses a WITH clause, add a root column 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 root column to the column list of the query result of the WITH clause. - In the first query, specify the root columnName to the values of the columns from the root to the node. - Specify m.rootName in the next query. (rootName is a root column.) The following shows the conversion format containing rootName. ~~~ WITH RECURSIVE queryName( columnUsed, rootName ) AS ( SELECT columnUsed, columnName FROM targetTableOfHierarchicalQuery UNION ALL SELECT columnUsed(qualified by n), w.rootName 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 root data is displayed.
Oracle database PostgreSQL
SELECT staff_id, name, CONNECT_BY_ROOT name as "Manager" 
  FROM staff_table 
  START WITH staff_id = '1001' 
  CONNECT BY PRIOR staff_id = manager_id;







WITH RECURSIVE staff_table_w( staff_id, 
 name, 
 Manager ) AS 
 (   SELECT staff_id, name, name 
       FROM staff_table 
     UNION ALL 
     SELECT n.staff_id, n.name, w.Manager 
       FROM staff_table n, staff_table_w w 
       WHERE w.staff_id = n.manager_id
 )
 SELECT staff_id, name, Manager 
 FROM staff_table_w;
##### 4.2.3.7 Hierarchical Query identifys the leaves **Functional differences** - **Oracle database** - Specifying CONNECT_BY_ISLEAF in the select list of a hierarchical query can identify the leaf rows. This returns 1 if the current row is a leaf. Otherwise it returns 0. - **PostgreSQL** - CONNECT_BY_ISLEAF cannot be specified. **Migration procedure** In a recursive query that uses a WITH clause, the leaf can be checked using a sub-query 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 a sub-query to the column list of the query result of the WITH clause. The following shows the conversion format containing rootName. ~~~ WITH RECURSIVE queryName( columnUsed1, columnUsed2 ) AS ( SELECT columnUsed, columnUsed2 FROM targetTableOfHierarchicalQuery UNION ALL SELECT columnUsed(qualified by n), columnUsed2(qualified by n) FROM targetTableOfHierarchicalQuery n, queryName w WHERE conditionalExprOfConnectByClause ) SELECT *, CASE WHEN EXISTS(select * from queryName p where p.columnUsed1 = e.columnUsed2) THEN 0 ELSE 1 END as is_leaf FROM queryName e; ~~~ For conditionalExprOfConnectByClause, use w to qualify the part qualified by PRIOR. **Migration example** The example below shows migration when the leaf data is displayed.
Oracle database PostgreSQL
SELECT staff_id, name, CONNECT_BY_ISLEAF 
  FROM staff_table 
  START WITH staff_id = '1001' 
  CONNECT BY PRIOR staff_id = manager_id;








WITH RECURSIVE staff_table_w( staff_id, 
                            name ) AS 
 (   SELECT staff_id, name
       FROM staff_table 
     UNION ALL 
     SELECT n.staff_id, n.name
       FROM staff_table n, staff_table_w w 
       WHERE w.staff_id = n.manager_id
 )
 SELECT staff_id, name,
       CASE WHEN EXISTS(select 1 from staff_table_w p where p.manager_id = e.staff_id)
            THEN 0 ELSE 1 END 
        as is_leaf 
 FROM staff_table_w e;
##### 4.2.3.8 Returns all possible hierarchy permutations **Functional differences** - **Oracle database** - When CONNECT BY LEVEL is used without START WITH clause and PRIOR operator. - **PostgreSQL** - CONNECT BY LEVEL cannot be specified. **Migration procedure** In a recursive query that uses a WITH clause, returns all possible hierarchy permutations can use the descartes product. Use the following procedure to perform migration: 1. Replace the hierarchical query with syntax that uses a recursive query (WITH clause). 2. The left query of Union ALL does not specify a filter condition. The right query is the Descartes product of two tables, and the filter condition is the number of recursions. The following shows the conversion format containing rootName. ~~~ WITH RECURSIVE queryName( columnUsed1, level ) AS ( SELECT columnUsed, 1 FROM targetTableOfHierarchicalQuery UNION ALL SELECT columnUsed(qualified by n), w.level+1 FROM targetTableOfHierarchicalQuery n, queryName w WHERE w.level+1 < levelNum ); ~~~ **Migration example** The example below shows migration when returns all possible hierarchy permutations of two levels.
Oracle database PostgreSQL
select staff_id, name, level 
    from staff_table 
    connect by level < 3;






WITH RECURSIVE staff_table_w( staff_id, 
                     name 
                     level ) AS 
 (   SELECT staff_id, name, 1 
       FROM staff_table 
     UNION ALL 
     SELECT n.staff_id, n.name, w.level + 1 
       FROM staff_table n, staff_table_w w
        WHERE w.level + 1 < 3 
 )
 SELECT staff_id, name, level 
 FROM staff_table_w;
#### 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_4_14_4/doc/sql_migration/sql_migration05.md000066400000000000000000001401271501757153000233770ustar00rootroot00000000000000Chapter 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_4_14_4/doc/sql_migration/sql_migration06.md000066400000000000000000002161601501757153000234010ustar00rootroot00000000000000Chapter 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 UTL_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_4_14_4/doc/sql_migration/sql_migration07.md000066400000000000000000000164121501757153000234000ustar00rootroot00000000000000Appendix 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_4_14_4/expected/000077500000000000000000000000001501757153000162175ustar00rootroot00000000000000orafce-VERSION_4_14_4/expected/aggregates.out000066400000000000000000000064611501757153000210700ustar00rootroot00000000000000SET search_path TO public, oracle; -- 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_4_14_4/expected/dbms_alert_session_A.out000066400000000000000000000063451501757153000230770ustar00rootroot00000000000000\set ECHO none 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_4_14_4/expected/dbms_alert_session_B.out000066400000000000000000000051361501757153000230750ustar00rootroot00000000000000\set ECHO none /* 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_4_14_4/expected/dbms_alert_session_C.out000066400000000000000000000010211501757153000230630ustar00rootroot00000000000000\set ECHO none /* 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_4_14_4/expected/dbms_output.out000066400000000000000000001100421501757153000213130ustar00rootroot00000000000000\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.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.ENABLE(); 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.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.ENABLE(); 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.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.ENABLE(); 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.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.ENABLE(); 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.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.ENABLE(); 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.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.ENABLE(); 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.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.ENABLE(); 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.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.ENABLE(); 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.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.ENABLE(); 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.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.ENABLE(); 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.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.ENABLE(); 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.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.ENABLE(); 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.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.ENABLE(); 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.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.ENABLE(); 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.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.ENABLE(); 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.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.ENABLE(); 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.SERVEROUTPUT ('t'); PERFORM DBMS_OUTPUT.ENABLE(); 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.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.ENABLE(); 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.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.ENABLE(); 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.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.ENABLE(); 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(); -- SERVEROUTPUT [4] SERVEROUTPUT('t') get_line return null 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.SERVEROUTPUT ('t'); PERFORM DBMS_OUTPUT.ENABLE(); 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(); ORAFCE TEST 1 ORAFCE TEST 2 dbms_output_test ------------------ (1 row) SELECT * FROM dbms_output_test; buff | status --------+-------- | 1 | 1 (2 rows) DROP TABLE dbms_output_test; DROP FUNCTION dbms_output_test(); -- test dbms_output.serveroutput(false) clear buffer select dbms_output.serveroutput(true); serveroutput -------------- (1 row) do $$ BEGIN PERFORM DBMS_OUTPUT.PUT_LINE('1234242'); END$$; 1234242 select dbms_output.serveroutput(false); serveroutput -------------- (1 row) do $$ BEGIN PERFORM DBMS_OUTPUT.PUT_LINE('1234242'); END$$; select dbms_output.serveroutput(true); serveroutput -------------- (1 row) do $$ BEGIN PERFORM DBMS_OUTPUT.PUT_LINE('1234242'); END$$; 1234242 orafce-VERSION_4_14_4/expected/dbms_pipe_session_A.out000066400000000000000000000034421501757153000227200ustar00rootroot00000000000000\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_4_14_4/expected/dbms_pipe_session_B.out000066400000000000000000000140001501757153000227110ustar00rootroot00000000000000\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_4_14_4/expected/dbms_random.out000066400000000000000000000040151501757153000212350ustar00rootroot00000000000000-- 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 -------- Y9 (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.value(10,10)::numeric(10, 8); value ------------- 10.00000000 (1 row) SELECT dbms_random.value(15,10)::numeric(10, 8); value ------------- 10.40015223 (1 row) SELECT dbms_random.seed(5); seed ------ (1 row) SELECT dbms_random.string('u', 10); string ------------ HBZCDCHLMX (1 row) SELECT dbms_random.string('l', 10); string ------------ ahzfkgjhkg (1 row) SELECT dbms_random.string('a', 10); string ------------ pxxodQYutY (1 row) SELECT dbms_random.string('x', 10); string ------------ HN0GQ5J0M1 (1 row) SELECT dbms_random.string('p', 10); string ------------ VEhX"|=i1& (1 row) SELECT dbms_random.string('uu', 10); -- error ERROR: this first parameter value is more than 1 characters long SELECT dbms_random.string('w', 10); string ------------ MIAXPCTOMD (1 row) -- although it is useless, and deprecated on Oracle -- it should be last command SELECT dbms_random.terminate(); terminate ----------- (1 row) orafce-VERSION_4_14_4/expected/dbms_random_1.out000066400000000000000000000040151501757153000214550ustar00rootroot00000000000000-- Tests for package DBMS_RANDOM SELECT dbms_random.initialize(8); initialize ------------ (1 row) SELECT dbms_random.normal()::numeric(10, 8); normal ------------ 0.12583199 (1 row) SELECT dbms_random.normal()::numeric(10, 8); normal ------------- -0.61543969 (1 row) SELECT dbms_random.seed(8); seed ------ (1 row) SELECT dbms_random.random(); random ------------ 1951052976 (1 row) SELECT dbms_random.seed('test'); seed ------ (1 row) SELECT dbms_random.string('U',5); string -------- LWLPN (1 row) SELECT dbms_random.string('P',2); string -------- \a (1 row) SELECT dbms_random.string('x',4); string -------- HJPS (1 row) SELECT dbms_random.string('a',2); string -------- Hg (1 row) SELECT dbms_random.string('l',3); string -------- fwz (1 row) SELECT dbms_random.seed(5); seed ------ (1 row) SELECT dbms_random.value()::numeric(10, 8); value ------------ 0.08003045 (1 row) SELECT dbms_random.value(10,15)::numeric(10, 8); value ------------- 12.24227702 (1 row) SELECT dbms_random.value(10,10)::numeric(10, 8); value ------------- 10.00000000 (1 row) SELECT dbms_random.value(15,10)::numeric(10, 8); value ------------- 14.47000931 (1 row) SELECT dbms_random.seed(5); seed ------ (1 row) SELECT dbms_random.string('u', 10); string ------------ HBZCDCHLMX (1 row) SELECT dbms_random.string('l', 10); string ------------ ahzfkgjhkg (1 row) SELECT dbms_random.string('a', 10); string ------------ pxxodQYutY (1 row) SELECT dbms_random.string('x', 10); string ------------ HN0GQ5J0M1 (1 row) SELECT dbms_random.string('p', 10); string ------------ VEhX"|=i1& (1 row) SELECT dbms_random.string('uu', 10); -- error ERROR: this first parameter value is more than 1 characters long SELECT dbms_random.string('w', 10); string ------------ MIAXPCTOMD (1 row) -- although it is useless, and deprecated on Oracle -- it should be last command SELECT dbms_random.terminate(); terminate ----------- (1 row) orafce-VERSION_4_14_4/expected/dbms_random_2.out000066400000000000000000000042261501757153000214620ustar00rootroot00000000000000-- Tests for package DBMS_RANDOM SELECT dbms_random.initialize(8); initialize ------------ (1 row) SELECT dbms_random.normal()::numeric(10, 8); normal ------------- -2.88076095 (1 row) SELECT dbms_random.normal()::numeric(10, 8); normal ------------ 1.07890275 (1 row) SELECT dbms_random.seed(8); seed ------ (1 row) SELECT dbms_random.random(); random -------- -32638 (1 row) SELECT dbms_random.seed('test'); seed ------ (1 row) SELECT dbms_random.string('U',5); string -------- XXEJF (1 row) SELECT dbms_random.string('P',2); string -------- go (1 row) SELECT dbms_random.string('x',4); string -------- V3W9 (1 row) SELECT dbms_random.string('a',2); string -------- GC (1 row) SELECT dbms_random.string('l',3); string -------- pbr (1 row) SELECT dbms_random.seed(5); seed ------ (1 row) SELECT dbms_random.value()::numeric(10, 8); value ------------ 0.00164795 (1 row) SELECT dbms_random.value(10,15)::numeric(10, 8); value ------------- 14.37820435 (1 row) SELECT dbms_random.value(10,10)::numeric(10, 8); value ------------- 10.00000000 (1 row) SELECT dbms_random.value(15,10)::numeric(10, 8); value ------------- 13.73062134 (1 row) SELECT dbms_random.seed(5); seed ------ (1 row) SELECT dbms_random.string('u', 10); string ------------ AWJTVYSOVZ (1 row) SELECT dbms_random.string('l', 10); string ------------ ewknadjpja (1 row) SELECT dbms_random.string('a', 10); string ------------ trXSPLgEQe (1 row) SELECT dbms_random.string('x', 10); string ------------ J85H7G1H2E (1 row) SELECT dbms_random.string('p', 10); string ------------ FHkm:uKzx? (1 row) SELECT dbms_random.string('uu', 10); -- error ERROR: this first parameter value is more than 1 characters long SELECT dbms_random.string('w', 10); string ------------ ZQMJCOVPXT (1 row) -- although it is useless, and deprecated on Oracle -- it should be last command SELECT dbms_random.terminate(); terminate ----------- (1 row) orafce-VERSION_4_14_4/expected/dbms_sql.out000066400000000000000000000400121501757153000205510ustar00rootroot00000000000000do $$ declare c int; strval varchar; intval int; nrows int default 30; begin c := dbms_sql.open_cursor(); call dbms_sql.parse(c, 'select ''ahoj'' || i, i from generate_series(1, :nrows) g(i)'); call dbms_sql.bind_variable(c, 'nrows', nrows); call dbms_sql.define_column(c, 1, strval); call dbms_sql.define_column(c, 2, intval); perform dbms_sql.execute(c); while dbms_sql.fetch_rows(c) > 0 loop call dbms_sql.column_value(c, 1, strval); call dbms_sql.column_value(c, 2, intval); raise notice 'c1: %, c2: %', strval, intval; end loop; call dbms_sql.close_cursor(c); end; $$; NOTICE: c1: ahoj1, c2: 1 NOTICE: c1: ahoj2, c2: 2 NOTICE: c1: ahoj3, c2: 3 NOTICE: c1: ahoj4, c2: 4 NOTICE: c1: ahoj5, c2: 5 NOTICE: c1: ahoj6, c2: 6 NOTICE: c1: ahoj7, c2: 7 NOTICE: c1: ahoj8, c2: 8 NOTICE: c1: ahoj9, c2: 9 NOTICE: c1: ahoj10, c2: 10 NOTICE: c1: ahoj11, c2: 11 NOTICE: c1: ahoj12, c2: 12 NOTICE: c1: ahoj13, c2: 13 NOTICE: c1: ahoj14, c2: 14 NOTICE: c1: ahoj15, c2: 15 NOTICE: c1: ahoj16, c2: 16 NOTICE: c1: ahoj17, c2: 17 NOTICE: c1: ahoj18, c2: 18 NOTICE: c1: ahoj19, c2: 19 NOTICE: c1: ahoj20, c2: 20 NOTICE: c1: ahoj21, c2: 21 NOTICE: c1: ahoj22, c2: 22 NOTICE: c1: ahoj23, c2: 23 NOTICE: c1: ahoj24, c2: 24 NOTICE: c1: ahoj25, c2: 25 NOTICE: c1: ahoj26, c2: 26 NOTICE: c1: ahoj27, c2: 27 NOTICE: c1: ahoj28, c2: 28 NOTICE: c1: ahoj29, c2: 29 NOTICE: c1: ahoj30, c2: 30 do $$ declare c int; strval varchar; intval int; nrows int default 30; begin c := dbms_sql.open_cursor(); call dbms_sql.parse(c, 'select ''ahoj'' || i, i from generate_series(1, :nrows) g(i)'); call dbms_sql.bind_variable(c, 'nrows', nrows); call dbms_sql.define_column(c, 1, strval); call dbms_sql.define_column(c, 2, intval); perform dbms_sql.execute(c); while dbms_sql.fetch_rows(c) > 0 loop strval := dbms_sql.column_value_f(c, 1, strval); intval := dbms_sql.column_value_f(c, 2, intval); raise notice 'c1: %, c2: %', strval, intval; end loop; call dbms_sql.close_cursor(c); end; $$; NOTICE: c1: ahoj1, c2: 1 NOTICE: c1: ahoj2, c2: 2 NOTICE: c1: ahoj3, c2: 3 NOTICE: c1: ahoj4, c2: 4 NOTICE: c1: ahoj5, c2: 5 NOTICE: c1: ahoj6, c2: 6 NOTICE: c1: ahoj7, c2: 7 NOTICE: c1: ahoj8, c2: 8 NOTICE: c1: ahoj9, c2: 9 NOTICE: c1: ahoj10, c2: 10 NOTICE: c1: ahoj11, c2: 11 NOTICE: c1: ahoj12, c2: 12 NOTICE: c1: ahoj13, c2: 13 NOTICE: c1: ahoj14, c2: 14 NOTICE: c1: ahoj15, c2: 15 NOTICE: c1: ahoj16, c2: 16 NOTICE: c1: ahoj17, c2: 17 NOTICE: c1: ahoj18, c2: 18 NOTICE: c1: ahoj19, c2: 19 NOTICE: c1: ahoj20, c2: 20 NOTICE: c1: ahoj21, c2: 21 NOTICE: c1: ahoj22, c2: 22 NOTICE: c1: ahoj23, c2: 23 NOTICE: c1: ahoj24, c2: 24 NOTICE: c1: ahoj25, c2: 25 NOTICE: c1: ahoj26, c2: 26 NOTICE: c1: ahoj27, c2: 27 NOTICE: c1: ahoj28, c2: 28 NOTICE: c1: ahoj29, c2: 29 NOTICE: c1: ahoj30, c2: 30 drop table if exists foo; create table foo(a int, b varchar, c numeric); do $$ declare c int; begin c := dbms_sql.open_cursor(); call dbms_sql.parse(c, 'insert into foo values(:a, :b, :c)'); for i in 1..100 loop call dbms_sql.bind_variable(c, 'a', i); call dbms_sql.bind_variable(c, 'b', 'Ahoj ' || i); call dbms_sql.bind_variable(c, 'c', i + 0.033); perform dbms_sql.execute(c); end loop; end; $$; select * from foo; a | b | c -----+----------+--------- 1 | Ahoj 1 | 1.033 2 | Ahoj 2 | 2.033 3 | Ahoj 3 | 3.033 4 | Ahoj 4 | 4.033 5 | Ahoj 5 | 5.033 6 | Ahoj 6 | 6.033 7 | Ahoj 7 | 7.033 8 | Ahoj 8 | 8.033 9 | Ahoj 9 | 9.033 10 | Ahoj 10 | 10.033 11 | Ahoj 11 | 11.033 12 | Ahoj 12 | 12.033 13 | Ahoj 13 | 13.033 14 | Ahoj 14 | 14.033 15 | Ahoj 15 | 15.033 16 | Ahoj 16 | 16.033 17 | Ahoj 17 | 17.033 18 | Ahoj 18 | 18.033 19 | Ahoj 19 | 19.033 20 | Ahoj 20 | 20.033 21 | Ahoj 21 | 21.033 22 | Ahoj 22 | 22.033 23 | Ahoj 23 | 23.033 24 | Ahoj 24 | 24.033 25 | Ahoj 25 | 25.033 26 | Ahoj 26 | 26.033 27 | Ahoj 27 | 27.033 28 | Ahoj 28 | 28.033 29 | Ahoj 29 | 29.033 30 | Ahoj 30 | 30.033 31 | Ahoj 31 | 31.033 32 | Ahoj 32 | 32.033 33 | Ahoj 33 | 33.033 34 | Ahoj 34 | 34.033 35 | Ahoj 35 | 35.033 36 | Ahoj 36 | 36.033 37 | Ahoj 37 | 37.033 38 | Ahoj 38 | 38.033 39 | Ahoj 39 | 39.033 40 | Ahoj 40 | 40.033 41 | Ahoj 41 | 41.033 42 | Ahoj 42 | 42.033 43 | Ahoj 43 | 43.033 44 | Ahoj 44 | 44.033 45 | Ahoj 45 | 45.033 46 | Ahoj 46 | 46.033 47 | Ahoj 47 | 47.033 48 | Ahoj 48 | 48.033 49 | Ahoj 49 | 49.033 50 | Ahoj 50 | 50.033 51 | Ahoj 51 | 51.033 52 | Ahoj 52 | 52.033 53 | Ahoj 53 | 53.033 54 | Ahoj 54 | 54.033 55 | Ahoj 55 | 55.033 56 | Ahoj 56 | 56.033 57 | Ahoj 57 | 57.033 58 | Ahoj 58 | 58.033 59 | Ahoj 59 | 59.033 60 | Ahoj 60 | 60.033 61 | Ahoj 61 | 61.033 62 | Ahoj 62 | 62.033 63 | Ahoj 63 | 63.033 64 | Ahoj 64 | 64.033 65 | Ahoj 65 | 65.033 66 | Ahoj 66 | 66.033 67 | Ahoj 67 | 67.033 68 | Ahoj 68 | 68.033 69 | Ahoj 69 | 69.033 70 | Ahoj 70 | 70.033 71 | Ahoj 71 | 71.033 72 | Ahoj 72 | 72.033 73 | Ahoj 73 | 73.033 74 | Ahoj 74 | 74.033 75 | Ahoj 75 | 75.033 76 | Ahoj 76 | 76.033 77 | Ahoj 77 | 77.033 78 | Ahoj 78 | 78.033 79 | Ahoj 79 | 79.033 80 | Ahoj 80 | 80.033 81 | Ahoj 81 | 81.033 82 | Ahoj 82 | 82.033 83 | Ahoj 83 | 83.033 84 | Ahoj 84 | 84.033 85 | Ahoj 85 | 85.033 86 | Ahoj 86 | 86.033 87 | Ahoj 87 | 87.033 88 | Ahoj 88 | 88.033 89 | Ahoj 89 | 89.033 90 | Ahoj 90 | 90.033 91 | Ahoj 91 | 91.033 92 | Ahoj 92 | 92.033 93 | Ahoj 93 | 93.033 94 | Ahoj 94 | 94.033 95 | Ahoj 95 | 95.033 96 | Ahoj 96 | 96.033 97 | Ahoj 97 | 97.033 98 | Ahoj 98 | 98.033 99 | Ahoj 99 | 99.033 100 | Ahoj 100 | 100.033 (100 rows) truncate foo; do $$ declare c int; begin c := dbms_sql.open_cursor(); call dbms_sql.parse(c, 'insert into foo values(:a, :b, :c)'); for i in 1..100 loop perform dbms_sql.bind_variable_f(c, 'a', i); perform dbms_sql.bind_variable_f(c, 'b', 'Ahoj ' || i); perform dbms_sql.bind_variable_f(c, 'c', i + 0.033); perform dbms_sql.execute(c); end loop; end; $$; select * from foo; a | b | c -----+----------+--------- 1 | Ahoj 1 | 1.033 2 | Ahoj 2 | 2.033 3 | Ahoj 3 | 3.033 4 | Ahoj 4 | 4.033 5 | Ahoj 5 | 5.033 6 | Ahoj 6 | 6.033 7 | Ahoj 7 | 7.033 8 | Ahoj 8 | 8.033 9 | Ahoj 9 | 9.033 10 | Ahoj 10 | 10.033 11 | Ahoj 11 | 11.033 12 | Ahoj 12 | 12.033 13 | Ahoj 13 | 13.033 14 | Ahoj 14 | 14.033 15 | Ahoj 15 | 15.033 16 | Ahoj 16 | 16.033 17 | Ahoj 17 | 17.033 18 | Ahoj 18 | 18.033 19 | Ahoj 19 | 19.033 20 | Ahoj 20 | 20.033 21 | Ahoj 21 | 21.033 22 | Ahoj 22 | 22.033 23 | Ahoj 23 | 23.033 24 | Ahoj 24 | 24.033 25 | Ahoj 25 | 25.033 26 | Ahoj 26 | 26.033 27 | Ahoj 27 | 27.033 28 | Ahoj 28 | 28.033 29 | Ahoj 29 | 29.033 30 | Ahoj 30 | 30.033 31 | Ahoj 31 | 31.033 32 | Ahoj 32 | 32.033 33 | Ahoj 33 | 33.033 34 | Ahoj 34 | 34.033 35 | Ahoj 35 | 35.033 36 | Ahoj 36 | 36.033 37 | Ahoj 37 | 37.033 38 | Ahoj 38 | 38.033 39 | Ahoj 39 | 39.033 40 | Ahoj 40 | 40.033 41 | Ahoj 41 | 41.033 42 | Ahoj 42 | 42.033 43 | Ahoj 43 | 43.033 44 | Ahoj 44 | 44.033 45 | Ahoj 45 | 45.033 46 | Ahoj 46 | 46.033 47 | Ahoj 47 | 47.033 48 | Ahoj 48 | 48.033 49 | Ahoj 49 | 49.033 50 | Ahoj 50 | 50.033 51 | Ahoj 51 | 51.033 52 | Ahoj 52 | 52.033 53 | Ahoj 53 | 53.033 54 | Ahoj 54 | 54.033 55 | Ahoj 55 | 55.033 56 | Ahoj 56 | 56.033 57 | Ahoj 57 | 57.033 58 | Ahoj 58 | 58.033 59 | Ahoj 59 | 59.033 60 | Ahoj 60 | 60.033 61 | Ahoj 61 | 61.033 62 | Ahoj 62 | 62.033 63 | Ahoj 63 | 63.033 64 | Ahoj 64 | 64.033 65 | Ahoj 65 | 65.033 66 | Ahoj 66 | 66.033 67 | Ahoj 67 | 67.033 68 | Ahoj 68 | 68.033 69 | Ahoj 69 | 69.033 70 | Ahoj 70 | 70.033 71 | Ahoj 71 | 71.033 72 | Ahoj 72 | 72.033 73 | Ahoj 73 | 73.033 74 | Ahoj 74 | 74.033 75 | Ahoj 75 | 75.033 76 | Ahoj 76 | 76.033 77 | Ahoj 77 | 77.033 78 | Ahoj 78 | 78.033 79 | Ahoj 79 | 79.033 80 | Ahoj 80 | 80.033 81 | Ahoj 81 | 81.033 82 | Ahoj 82 | 82.033 83 | Ahoj 83 | 83.033 84 | Ahoj 84 | 84.033 85 | Ahoj 85 | 85.033 86 | Ahoj 86 | 86.033 87 | Ahoj 87 | 87.033 88 | Ahoj 88 | 88.033 89 | Ahoj 89 | 89.033 90 | Ahoj 90 | 90.033 91 | Ahoj 91 | 91.033 92 | Ahoj 92 | 92.033 93 | Ahoj 93 | 93.033 94 | Ahoj 94 | 94.033 95 | Ahoj 95 | 95.033 96 | Ahoj 96 | 96.033 97 | Ahoj 97 | 97.033 98 | Ahoj 98 | 98.033 99 | Ahoj 99 | 99.033 100 | Ahoj 100 | 100.033 (100 rows) truncate foo; do $$ declare c int; a int[]; b varchar[]; ca numeric[]; begin c := dbms_sql.open_cursor(); call dbms_sql.parse(c, 'insert into foo values(:a, :b, :c)'); a := ARRAY[1, 2, 3, 4, 5]; b := ARRAY['Ahoj', 'Nazdar', 'Bazar']; ca := ARRAY[3.14, 2.22, 3.8, 4]; call dbms_sql.bind_array(c, 'a', a); call dbms_sql.bind_array(c, 'b', b); call dbms_sql.bind_array(c, 'c', ca); raise notice 'inserted rows %d', dbms_sql.execute(c); end; $$; NOTICE: inserted rows 3d select * from foo; a | b | c ---+--------+------ 1 | Ahoj | 3.14 2 | Nazdar | 2.22 3 | Bazar | 3.8 (3 rows) truncate foo; -- should not to crash, when bound array is null do $$ declare c int; ca numeric[]; begin c := dbms_sql.open_cursor(); call dbms_sql.parse(c, 'insert into foo values(:a, 10, 20)'); call dbms_sql.bind_array(c, 'a', ca); raise notice 'inserted rows %d', dbms_sql.execute(c); end; $$; NOTICE: inserted rows 0d -- should not to crash, when we try to touch result without execute do $$ declare c int; a int[]; begin c := dbms_sql.open_cursor(); call dbms_sql.parse(c, 'select i from generate_series(1, 2) g(i)'); call dbms_sql.define_array(c, 1, a, 10, 1); call dbms_sql.column_value(c, 1, a); call dbms_sql.close_cursor(c); end; $$; ERROR: cursor is not executed CONTEXT: SQL statement "call dbms_sql.column_value(c, 1, a)" PL/pgSQL function inline_code_block line 9 at CALL -- should not to crash, when the variable is overwritten DO $$ declare c integer; n integer; c2 numeric; begin c := dbms_sql.open_cursor(); call dbms_sql.parse(c, 'INSERT INTO foo(a) VALUES (:bnd2)'); call dbms_sql.bind_variable(c, 'bnd2', c2); call dbms_sql.bind_variable(c, 'bnd2', c2); n := dbms_sql.execute(c); end $$; -- should not to crash, when we try to read column without data do $$ declare c int; strval varchar; intval int; begin c := dbms_sql.open_cursor(); call dbms_sql.parse(c, 'select ''foo'', 1'); call dbms_sql.define_column(c, 1, strval); call dbms_sql.define_column(c, 2, intval); perform dbms_sql.execute(c); while dbms_sql.fetch_rows(c) > -1 loop call dbms_sql.column_value(c, 1, strval); end loop; call dbms_sql.close_cursor(c); end; $$; ERROR: no data found CONTEXT: SQL statement "call dbms_sql.column_value(c, 1, strval)" PL/pgSQL function inline_code_block line 14 at CALL select * from foo; a | b | c ---+---+--- | | (1 row) truncate foo; do $$ declare c int; a int[]; b varchar[]; ca numeric[]; begin c := dbms_sql.open_cursor(); call dbms_sql.parse(c, 'insert into foo values(:a, :b, :c)'); a := ARRAY[1, 2, 3, 4, 5]; b := ARRAY['Ahoj', 'Nazdar', 'Bazar']; ca := ARRAY[3.14, 2.22, 3.8, 4]; call dbms_sql.bind_array(c, 'a', a, 2, 3); call dbms_sql.bind_array(c, 'b', b, 3, 4); call dbms_sql.bind_array(c, 'c', ca); raise notice 'inserted rows %d', dbms_sql.execute(c); end; $$; NOTICE: inserted rows 1d select * from foo; a | b | c ---+-------+----- 3 | Bazar | 3.8 (1 row) truncate foo; do $$ declare c int; a int[]; b varchar[]; ca numeric[]; begin c := dbms_sql.open_cursor(); call dbms_sql.parse(c, 'select i, ''Ahoj'' || i, i + 0.003 from generate_series(1, 35) g(i)'); call dbms_sql.define_array(c, 1, a, 10, 1); call dbms_sql.define_array(c, 2, b, 10, 1); call dbms_sql.define_array(c, 3, ca, 10, 1); perform dbms_sql.execute(c); while dbms_sql.fetch_rows(c) > 0 loop call dbms_sql.column_value(c, 1, a); call dbms_sql.column_value(c, 2, b); call dbms_sql.column_value(c, 3, ca); raise notice 'a = %', a; raise notice 'b = %', b; raise notice 'c = %', ca; end loop; call dbms_sql.close_cursor(c); end; $$; NOTICE: a = {1,2,3,4,5,6,7,8,9,10} NOTICE: b = {Ahoj1,Ahoj2,Ahoj3,Ahoj4,Ahoj5,Ahoj6,Ahoj7,Ahoj8,Ahoj9,Ahoj10} NOTICE: c = {1.003,2.003,3.003,4.003,5.003,6.003,7.003,8.003,9.003,10.003} NOTICE: a = {11,12,13,14,15,16,17,18,19,20} NOTICE: b = {Ahoj11,Ahoj12,Ahoj13,Ahoj14,Ahoj15,Ahoj16,Ahoj17,Ahoj18,Ahoj19,Ahoj20} NOTICE: c = {11.003,12.003,13.003,14.003,15.003,16.003,17.003,18.003,19.003,20.003} NOTICE: a = {21,22,23,24,25,26,27,28,29,30} NOTICE: b = {Ahoj21,Ahoj22,Ahoj23,Ahoj24,Ahoj25,Ahoj26,Ahoj27,Ahoj28,Ahoj29,Ahoj30} NOTICE: c = {21.003,22.003,23.003,24.003,25.003,26.003,27.003,28.003,29.003,30.003} NOTICE: a = {31,32,33,34,35} NOTICE: b = {Ahoj31,Ahoj32,Ahoj33,Ahoj34,Ahoj35} NOTICE: c = {31.003,32.003,33.003,34.003,35.003} drop table foo; create table tab1(c1 integer, c2 numeric); create or replace procedure single_Row_insert(c1 integer, c2 numeric) as $$ declare c integer; n integer; begin c := dbms_sql.open_cursor(); call dbms_sql.parse(c, 'INSERT INTO tab1 VALUES (:bnd1, :bnd2)'); call dbms_sql.bind_variable(c, 'bnd1', c1); call dbms_sql.bind_variable(c, 'bnd2', c2); n := dbms_sql.execute(c); call dbms_sql.debug_cursor(c); call dbms_sql.close_cursor(c); end $$language plpgsql; do $$ declare a numeric(7,2); begin call single_Row_insert(2,a); end $$; NOTICE: orig query: "INSERT INTO tab1 VALUES (:bnd1, :bnd2)" NOTICE: parsed query: "INSERT INTO tab1 VALUES ($1, $2)" NOTICE: variable "bnd1" is assigned to "2" NOTICE: variable "bnd2" is NULL select * from tab1; c1 | c2 ----+---- 2 | (1 row) do $$ declare a numeric(7,2) default 1.23; begin call single_Row_insert(2,a); end $$; NOTICE: orig query: "INSERT INTO tab1 VALUES (:bnd1, :bnd2)" NOTICE: parsed query: "INSERT INTO tab1 VALUES ($1, $2)" NOTICE: variable "bnd1" is assigned to "2" NOTICE: variable "bnd2" is assigned to "1.23" select * from tab1; c1 | c2 ----+------ 2 | 2 | 1.23 (2 rows) select * from tab1 where c2 is null; c1 | c2 ----+---- 2 | (1 row) do $$ declare a numeric(7,2); begin call single_Row_insert(0,a); -- single_Row_insert(0, null) end $$; NOTICE: orig query: "INSERT INTO tab1 VALUES (:bnd1, :bnd2)" NOTICE: parsed query: "INSERT INTO tab1 VALUES ($1, $2)" NOTICE: variable "bnd1" is assigned to "0" NOTICE: variable "bnd2" is NULL select * from tab1; c1 | c2 ----+------ 2 | 2 | 1.23 0 | (3 rows) do $$ declare a numeric(7,2) default 1.23; begin call single_Row_insert(0,a); -- single_Row_insert(0, 1.23) end $$; NOTICE: orig query: "INSERT INTO tab1 VALUES (:bnd1, :bnd2)" NOTICE: parsed query: "INSERT INTO tab1 VALUES ($1, $2)" NOTICE: variable "bnd1" is assigned to "0" NOTICE: variable "bnd2" is assigned to "1.23" select * from tab1; c1 | c2 ----+------ 2 | 2 | 1.23 0 | 0 | 1.23 (4 rows) drop procedure single_Row_insert; drop table tab1; create table test(id text); insert into test(id) values ('1'), (null); -- should not to crash do $$ declare cursor int; id text; row_counter int := 0; begin cursor := dbms_sql.open_cursor(); call dbms_sql.parse(cursor, 'select id from test'); call dbms_sql.define_column(cursor, 1, 'id'); perform dbms_sql.execute(cursor); while dbms_sql.fetch_rows(cursor) > 0 loop row_counter = row_counter + 1; raise notice 'process row #%', row_counter; call dbms_sql.column_value(cursor, 1, id); raise notice 'row id: `%`', id; end loop; call dbms_sql.close_cursor(cursor); end; $$; NOTICE: process row #1 NOTICE: row id: `1` NOTICE: process row #2 NOTICE: row id: `` drop table test; orafce-VERSION_4_14_4/expected/dbms_sql_1.out000066400000000000000000000400121501757153000207710ustar00rootroot00000000000000do $$ declare c int; strval varchar; intval int; nrows int default 30; begin c := dbms_sql.open_cursor(); call dbms_sql.parse(c, 'select ''ahoj'' || i, i from generate_series(1, :nrows) g(i)'); call dbms_sql.bind_variable(c, 'nrows', nrows); call dbms_sql.define_column(c, 1, strval); call dbms_sql.define_column(c, 2, intval); perform dbms_sql.execute(c); while dbms_sql.fetch_rows(c) > 0 loop call dbms_sql.column_value(c, 1, strval); call dbms_sql.column_value(c, 2, intval); raise notice 'c1: %, c2: %', strval, intval; end loop; call dbms_sql.close_cursor(c); end; $$; NOTICE: c1: ahoj1, c2: 1 NOTICE: c1: ahoj2, c2: 2 NOTICE: c1: ahoj3, c2: 3 NOTICE: c1: ahoj4, c2: 4 NOTICE: c1: ahoj5, c2: 5 NOTICE: c1: ahoj6, c2: 6 NOTICE: c1: ahoj7, c2: 7 NOTICE: c1: ahoj8, c2: 8 NOTICE: c1: ahoj9, c2: 9 NOTICE: c1: ahoj10, c2: 10 NOTICE: c1: ahoj11, c2: 11 NOTICE: c1: ahoj12, c2: 12 NOTICE: c1: ahoj13, c2: 13 NOTICE: c1: ahoj14, c2: 14 NOTICE: c1: ahoj15, c2: 15 NOTICE: c1: ahoj16, c2: 16 NOTICE: c1: ahoj17, c2: 17 NOTICE: c1: ahoj18, c2: 18 NOTICE: c1: ahoj19, c2: 19 NOTICE: c1: ahoj20, c2: 20 NOTICE: c1: ahoj21, c2: 21 NOTICE: c1: ahoj22, c2: 22 NOTICE: c1: ahoj23, c2: 23 NOTICE: c1: ahoj24, c2: 24 NOTICE: c1: ahoj25, c2: 25 NOTICE: c1: ahoj26, c2: 26 NOTICE: c1: ahoj27, c2: 27 NOTICE: c1: ahoj28, c2: 28 NOTICE: c1: ahoj29, c2: 29 NOTICE: c1: ahoj30, c2: 30 do $$ declare c int; strval varchar; intval int; nrows int default 30; begin c := dbms_sql.open_cursor(); call dbms_sql.parse(c, 'select ''ahoj'' || i, i from generate_series(1, :nrows) g(i)'); call dbms_sql.bind_variable(c, 'nrows', nrows); call dbms_sql.define_column(c, 1, strval); call dbms_sql.define_column(c, 2, intval); perform dbms_sql.execute(c); while dbms_sql.fetch_rows(c) > 0 loop strval := dbms_sql.column_value_f(c, 1, strval); intval := dbms_sql.column_value_f(c, 2, intval); raise notice 'c1: %, c2: %', strval, intval; end loop; call dbms_sql.close_cursor(c); end; $$; NOTICE: c1: ahoj1, c2: 1 NOTICE: c1: ahoj2, c2: 2 NOTICE: c1: ahoj3, c2: 3 NOTICE: c1: ahoj4, c2: 4 NOTICE: c1: ahoj5, c2: 5 NOTICE: c1: ahoj6, c2: 6 NOTICE: c1: ahoj7, c2: 7 NOTICE: c1: ahoj8, c2: 8 NOTICE: c1: ahoj9, c2: 9 NOTICE: c1: ahoj10, c2: 10 NOTICE: c1: ahoj11, c2: 11 NOTICE: c1: ahoj12, c2: 12 NOTICE: c1: ahoj13, c2: 13 NOTICE: c1: ahoj14, c2: 14 NOTICE: c1: ahoj15, c2: 15 NOTICE: c1: ahoj16, c2: 16 NOTICE: c1: ahoj17, c2: 17 NOTICE: c1: ahoj18, c2: 18 NOTICE: c1: ahoj19, c2: 19 NOTICE: c1: ahoj20, c2: 20 NOTICE: c1: ahoj21, c2: 21 NOTICE: c1: ahoj22, c2: 22 NOTICE: c1: ahoj23, c2: 23 NOTICE: c1: ahoj24, c2: 24 NOTICE: c1: ahoj25, c2: 25 NOTICE: c1: ahoj26, c2: 26 NOTICE: c1: ahoj27, c2: 27 NOTICE: c1: ahoj28, c2: 28 NOTICE: c1: ahoj29, c2: 29 NOTICE: c1: ahoj30, c2: 30 drop table if exists foo; create table foo(a int, b varchar, c numeric); do $$ declare c int; begin c := dbms_sql.open_cursor(); call dbms_sql.parse(c, 'insert into foo values(:a, :b, :c)'); for i in 1..100 loop call dbms_sql.bind_variable(c, 'a', i); call dbms_sql.bind_variable(c, 'b', 'Ahoj ' || i); call dbms_sql.bind_variable(c, 'c', i + 0.033); perform dbms_sql.execute(c); end loop; end; $$; select * from foo; a | b | c -----+----------+--------- 1 | Ahoj 1 | 1.033 2 | Ahoj 2 | 2.033 3 | Ahoj 3 | 3.033 4 | Ahoj 4 | 4.033 5 | Ahoj 5 | 5.033 6 | Ahoj 6 | 6.033 7 | Ahoj 7 | 7.033 8 | Ahoj 8 | 8.033 9 | Ahoj 9 | 9.033 10 | Ahoj 10 | 10.033 11 | Ahoj 11 | 11.033 12 | Ahoj 12 | 12.033 13 | Ahoj 13 | 13.033 14 | Ahoj 14 | 14.033 15 | Ahoj 15 | 15.033 16 | Ahoj 16 | 16.033 17 | Ahoj 17 | 17.033 18 | Ahoj 18 | 18.033 19 | Ahoj 19 | 19.033 20 | Ahoj 20 | 20.033 21 | Ahoj 21 | 21.033 22 | Ahoj 22 | 22.033 23 | Ahoj 23 | 23.033 24 | Ahoj 24 | 24.033 25 | Ahoj 25 | 25.033 26 | Ahoj 26 | 26.033 27 | Ahoj 27 | 27.033 28 | Ahoj 28 | 28.033 29 | Ahoj 29 | 29.033 30 | Ahoj 30 | 30.033 31 | Ahoj 31 | 31.033 32 | Ahoj 32 | 32.033 33 | Ahoj 33 | 33.033 34 | Ahoj 34 | 34.033 35 | Ahoj 35 | 35.033 36 | Ahoj 36 | 36.033 37 | Ahoj 37 | 37.033 38 | Ahoj 38 | 38.033 39 | Ahoj 39 | 39.033 40 | Ahoj 40 | 40.033 41 | Ahoj 41 | 41.033 42 | Ahoj 42 | 42.033 43 | Ahoj 43 | 43.033 44 | Ahoj 44 | 44.033 45 | Ahoj 45 | 45.033 46 | Ahoj 46 | 46.033 47 | Ahoj 47 | 47.033 48 | Ahoj 48 | 48.033 49 | Ahoj 49 | 49.033 50 | Ahoj 50 | 50.033 51 | Ahoj 51 | 51.033 52 | Ahoj 52 | 52.033 53 | Ahoj 53 | 53.033 54 | Ahoj 54 | 54.033 55 | Ahoj 55 | 55.033 56 | Ahoj 56 | 56.033 57 | Ahoj 57 | 57.033 58 | Ahoj 58 | 58.033 59 | Ahoj 59 | 59.033 60 | Ahoj 60 | 60.033 61 | Ahoj 61 | 61.033 62 | Ahoj 62 | 62.033 63 | Ahoj 63 | 63.033 64 | Ahoj 64 | 64.033 65 | Ahoj 65 | 65.033 66 | Ahoj 66 | 66.033 67 | Ahoj 67 | 67.033 68 | Ahoj 68 | 68.033 69 | Ahoj 69 | 69.033 70 | Ahoj 70 | 70.033 71 | Ahoj 71 | 71.033 72 | Ahoj 72 | 72.033 73 | Ahoj 73 | 73.033 74 | Ahoj 74 | 74.033 75 | Ahoj 75 | 75.033 76 | Ahoj 76 | 76.033 77 | Ahoj 77 | 77.033 78 | Ahoj 78 | 78.033 79 | Ahoj 79 | 79.033 80 | Ahoj 80 | 80.033 81 | Ahoj 81 | 81.033 82 | Ahoj 82 | 82.033 83 | Ahoj 83 | 83.033 84 | Ahoj 84 | 84.033 85 | Ahoj 85 | 85.033 86 | Ahoj 86 | 86.033 87 | Ahoj 87 | 87.033 88 | Ahoj 88 | 88.033 89 | Ahoj 89 | 89.033 90 | Ahoj 90 | 90.033 91 | Ahoj 91 | 91.033 92 | Ahoj 92 | 92.033 93 | Ahoj 93 | 93.033 94 | Ahoj 94 | 94.033 95 | Ahoj 95 | 95.033 96 | Ahoj 96 | 96.033 97 | Ahoj 97 | 97.033 98 | Ahoj 98 | 98.033 99 | Ahoj 99 | 99.033 100 | Ahoj 100 | 100.033 (100 rows) truncate foo; do $$ declare c int; begin c := dbms_sql.open_cursor(); call dbms_sql.parse(c, 'insert into foo values(:a, :b, :c)'); for i in 1..100 loop perform dbms_sql.bind_variable_f(c, 'a', i); perform dbms_sql.bind_variable_f(c, 'b', 'Ahoj ' || i); perform dbms_sql.bind_variable_f(c, 'c', i + 0.033); perform dbms_sql.execute(c); end loop; end; $$; select * from foo; a | b | c -----+----------+--------- 1 | Ahoj 1 | 1.033 2 | Ahoj 2 | 2.033 3 | Ahoj 3 | 3.033 4 | Ahoj 4 | 4.033 5 | Ahoj 5 | 5.033 6 | Ahoj 6 | 6.033 7 | Ahoj 7 | 7.033 8 | Ahoj 8 | 8.033 9 | Ahoj 9 | 9.033 10 | Ahoj 10 | 10.033 11 | Ahoj 11 | 11.033 12 | Ahoj 12 | 12.033 13 | Ahoj 13 | 13.033 14 | Ahoj 14 | 14.033 15 | Ahoj 15 | 15.033 16 | Ahoj 16 | 16.033 17 | Ahoj 17 | 17.033 18 | Ahoj 18 | 18.033 19 | Ahoj 19 | 19.033 20 | Ahoj 20 | 20.033 21 | Ahoj 21 | 21.033 22 | Ahoj 22 | 22.033 23 | Ahoj 23 | 23.033 24 | Ahoj 24 | 24.033 25 | Ahoj 25 | 25.033 26 | Ahoj 26 | 26.033 27 | Ahoj 27 | 27.033 28 | Ahoj 28 | 28.033 29 | Ahoj 29 | 29.033 30 | Ahoj 30 | 30.033 31 | Ahoj 31 | 31.033 32 | Ahoj 32 | 32.033 33 | Ahoj 33 | 33.033 34 | Ahoj 34 | 34.033 35 | Ahoj 35 | 35.033 36 | Ahoj 36 | 36.033 37 | Ahoj 37 | 37.033 38 | Ahoj 38 | 38.033 39 | Ahoj 39 | 39.033 40 | Ahoj 40 | 40.033 41 | Ahoj 41 | 41.033 42 | Ahoj 42 | 42.033 43 | Ahoj 43 | 43.033 44 | Ahoj 44 | 44.033 45 | Ahoj 45 | 45.033 46 | Ahoj 46 | 46.033 47 | Ahoj 47 | 47.033 48 | Ahoj 48 | 48.033 49 | Ahoj 49 | 49.033 50 | Ahoj 50 | 50.033 51 | Ahoj 51 | 51.033 52 | Ahoj 52 | 52.033 53 | Ahoj 53 | 53.033 54 | Ahoj 54 | 54.033 55 | Ahoj 55 | 55.033 56 | Ahoj 56 | 56.033 57 | Ahoj 57 | 57.033 58 | Ahoj 58 | 58.033 59 | Ahoj 59 | 59.033 60 | Ahoj 60 | 60.033 61 | Ahoj 61 | 61.033 62 | Ahoj 62 | 62.033 63 | Ahoj 63 | 63.033 64 | Ahoj 64 | 64.033 65 | Ahoj 65 | 65.033 66 | Ahoj 66 | 66.033 67 | Ahoj 67 | 67.033 68 | Ahoj 68 | 68.033 69 | Ahoj 69 | 69.033 70 | Ahoj 70 | 70.033 71 | Ahoj 71 | 71.033 72 | Ahoj 72 | 72.033 73 | Ahoj 73 | 73.033 74 | Ahoj 74 | 74.033 75 | Ahoj 75 | 75.033 76 | Ahoj 76 | 76.033 77 | Ahoj 77 | 77.033 78 | Ahoj 78 | 78.033 79 | Ahoj 79 | 79.033 80 | Ahoj 80 | 80.033 81 | Ahoj 81 | 81.033 82 | Ahoj 82 | 82.033 83 | Ahoj 83 | 83.033 84 | Ahoj 84 | 84.033 85 | Ahoj 85 | 85.033 86 | Ahoj 86 | 86.033 87 | Ahoj 87 | 87.033 88 | Ahoj 88 | 88.033 89 | Ahoj 89 | 89.033 90 | Ahoj 90 | 90.033 91 | Ahoj 91 | 91.033 92 | Ahoj 92 | 92.033 93 | Ahoj 93 | 93.033 94 | Ahoj 94 | 94.033 95 | Ahoj 95 | 95.033 96 | Ahoj 96 | 96.033 97 | Ahoj 97 | 97.033 98 | Ahoj 98 | 98.033 99 | Ahoj 99 | 99.033 100 | Ahoj 100 | 100.033 (100 rows) truncate foo; do $$ declare c int; a int[]; b varchar[]; ca numeric[]; begin c := dbms_sql.open_cursor(); call dbms_sql.parse(c, 'insert into foo values(:a, :b, :c)'); a := ARRAY[1, 2, 3, 4, 5]; b := ARRAY['Ahoj', 'Nazdar', 'Bazar']; ca := ARRAY[3.14, 2.22, 3.8, 4]; call dbms_sql.bind_array(c, 'a', a); call dbms_sql.bind_array(c, 'b', b); call dbms_sql.bind_array(c, 'c', ca); raise notice 'inserted rows %d', dbms_sql.execute(c); end; $$; NOTICE: inserted rows 3d select * from foo; a | b | c ---+--------+------ 1 | Ahoj | 3.14 2 | Nazdar | 2.22 3 | Bazar | 3.8 (3 rows) truncate foo; -- should not to crash, when bound array is null do $$ declare c int; ca numeric[]; begin c := dbms_sql.open_cursor(); call dbms_sql.parse(c, 'insert into foo values(:a, 10, 20)'); call dbms_sql.bind_array(c, 'a', ca); raise notice 'inserted rows %d', dbms_sql.execute(c); end; $$; NOTICE: inserted rows 0d -- should not to crash, when we try to touch result without execute do $$ declare c int; a int[]; begin c := dbms_sql.open_cursor(); call dbms_sql.parse(c, 'select i from generate_series(1, 2) g(i)'); call dbms_sql.define_array(c, 1, a, 10, 1); call dbms_sql.column_value(c, 1, a); call dbms_sql.close_cursor(c); end; $$; ERROR: cursor is not executed CONTEXT: SQL statement "CALL dbms_sql.column_value(c, 1, a)" PL/pgSQL function inline_code_block line 9 at CALL -- should not to crash, when the variable is overwritten DO $$ declare c integer; n integer; c2 numeric; begin c := dbms_sql.open_cursor(); call dbms_sql.parse(c, 'INSERT INTO foo(a) VALUES (:bnd2)'); call dbms_sql.bind_variable(c, 'bnd2', c2); call dbms_sql.bind_variable(c, 'bnd2', c2); n := dbms_sql.execute(c); end $$; -- should not to crash, when we try to read column without data do $$ declare c int; strval varchar; intval int; begin c := dbms_sql.open_cursor(); call dbms_sql.parse(c, 'select ''foo'', 1'); call dbms_sql.define_column(c, 1, strval); call dbms_sql.define_column(c, 2, intval); perform dbms_sql.execute(c); while dbms_sql.fetch_rows(c) > -1 loop call dbms_sql.column_value(c, 1, strval); end loop; call dbms_sql.close_cursor(c); end; $$; ERROR: no data found CONTEXT: SQL statement "CALL dbms_sql.column_value(c, 1, strval)" PL/pgSQL function inline_code_block line 14 at CALL select * from foo; a | b | c ---+---+--- | | (1 row) truncate foo; do $$ declare c int; a int[]; b varchar[]; ca numeric[]; begin c := dbms_sql.open_cursor(); call dbms_sql.parse(c, 'insert into foo values(:a, :b, :c)'); a := ARRAY[1, 2, 3, 4, 5]; b := ARRAY['Ahoj', 'Nazdar', 'Bazar']; ca := ARRAY[3.14, 2.22, 3.8, 4]; call dbms_sql.bind_array(c, 'a', a, 2, 3); call dbms_sql.bind_array(c, 'b', b, 3, 4); call dbms_sql.bind_array(c, 'c', ca); raise notice 'inserted rows %d', dbms_sql.execute(c); end; $$; NOTICE: inserted rows 1d select * from foo; a | b | c ---+-------+----- 3 | Bazar | 3.8 (1 row) truncate foo; do $$ declare c int; a int[]; b varchar[]; ca numeric[]; begin c := dbms_sql.open_cursor(); call dbms_sql.parse(c, 'select i, ''Ahoj'' || i, i + 0.003 from generate_series(1, 35) g(i)'); call dbms_sql.define_array(c, 1, a, 10, 1); call dbms_sql.define_array(c, 2, b, 10, 1); call dbms_sql.define_array(c, 3, ca, 10, 1); perform dbms_sql.execute(c); while dbms_sql.fetch_rows(c) > 0 loop call dbms_sql.column_value(c, 1, a); call dbms_sql.column_value(c, 2, b); call dbms_sql.column_value(c, 3, ca); raise notice 'a = %', a; raise notice 'b = %', b; raise notice 'c = %', ca; end loop; call dbms_sql.close_cursor(c); end; $$; NOTICE: a = {1,2,3,4,5,6,7,8,9,10} NOTICE: b = {Ahoj1,Ahoj2,Ahoj3,Ahoj4,Ahoj5,Ahoj6,Ahoj7,Ahoj8,Ahoj9,Ahoj10} NOTICE: c = {1.003,2.003,3.003,4.003,5.003,6.003,7.003,8.003,9.003,10.003} NOTICE: a = {11,12,13,14,15,16,17,18,19,20} NOTICE: b = {Ahoj11,Ahoj12,Ahoj13,Ahoj14,Ahoj15,Ahoj16,Ahoj17,Ahoj18,Ahoj19,Ahoj20} NOTICE: c = {11.003,12.003,13.003,14.003,15.003,16.003,17.003,18.003,19.003,20.003} NOTICE: a = {21,22,23,24,25,26,27,28,29,30} NOTICE: b = {Ahoj21,Ahoj22,Ahoj23,Ahoj24,Ahoj25,Ahoj26,Ahoj27,Ahoj28,Ahoj29,Ahoj30} NOTICE: c = {21.003,22.003,23.003,24.003,25.003,26.003,27.003,28.003,29.003,30.003} NOTICE: a = {31,32,33,34,35} NOTICE: b = {Ahoj31,Ahoj32,Ahoj33,Ahoj34,Ahoj35} NOTICE: c = {31.003,32.003,33.003,34.003,35.003} drop table foo; create table tab1(c1 integer, c2 numeric); create or replace procedure single_Row_insert(c1 integer, c2 numeric) as $$ declare c integer; n integer; begin c := dbms_sql.open_cursor(); call dbms_sql.parse(c, 'INSERT INTO tab1 VALUES (:bnd1, :bnd2)'); call dbms_sql.bind_variable(c, 'bnd1', c1); call dbms_sql.bind_variable(c, 'bnd2', c2); n := dbms_sql.execute(c); call dbms_sql.debug_cursor(c); call dbms_sql.close_cursor(c); end $$language plpgsql; do $$ declare a numeric(7,2); begin call single_Row_insert(2,a); end $$; NOTICE: orig query: "INSERT INTO tab1 VALUES (:bnd1, :bnd2)" NOTICE: parsed query: "INSERT INTO tab1 VALUES ($1, $2)" NOTICE: variable "bnd1" is assigned to "2" NOTICE: variable "bnd2" is NULL select * from tab1; c1 | c2 ----+---- 2 | (1 row) do $$ declare a numeric(7,2) default 1.23; begin call single_Row_insert(2,a); end $$; NOTICE: orig query: "INSERT INTO tab1 VALUES (:bnd1, :bnd2)" NOTICE: parsed query: "INSERT INTO tab1 VALUES ($1, $2)" NOTICE: variable "bnd1" is assigned to "2" NOTICE: variable "bnd2" is assigned to "1.23" select * from tab1; c1 | c2 ----+------ 2 | 2 | 1.23 (2 rows) select * from tab1 where c2 is null; c1 | c2 ----+---- 2 | (1 row) do $$ declare a numeric(7,2); begin call single_Row_insert(0,a); -- single_Row_insert(0, null) end $$; NOTICE: orig query: "INSERT INTO tab1 VALUES (:bnd1, :bnd2)" NOTICE: parsed query: "INSERT INTO tab1 VALUES ($1, $2)" NOTICE: variable "bnd1" is assigned to "0" NOTICE: variable "bnd2" is NULL select * from tab1; c1 | c2 ----+------ 2 | 2 | 1.23 0 | (3 rows) do $$ declare a numeric(7,2) default 1.23; begin call single_Row_insert(0,a); -- single_Row_insert(0, 1.23) end $$; NOTICE: orig query: "INSERT INTO tab1 VALUES (:bnd1, :bnd2)" NOTICE: parsed query: "INSERT INTO tab1 VALUES ($1, $2)" NOTICE: variable "bnd1" is assigned to "0" NOTICE: variable "bnd2" is assigned to "1.23" select * from tab1; c1 | c2 ----+------ 2 | 2 | 1.23 0 | 0 | 1.23 (4 rows) drop procedure single_Row_insert; drop table tab1; create table test(id text); insert into test(id) values ('1'), (null); -- should not to crash do $$ declare cursor int; id text; row_counter int := 0; begin cursor := dbms_sql.open_cursor(); call dbms_sql.parse(cursor, 'select id from test'); call dbms_sql.define_column(cursor, 1, 'id'); perform dbms_sql.execute(cursor); while dbms_sql.fetch_rows(cursor) > 0 loop row_counter = row_counter + 1; raise notice 'process row #%', row_counter; call dbms_sql.column_value(cursor, 1, id); raise notice 'row id: `%`', id; end loop; call dbms_sql.close_cursor(cursor); end; $$; NOTICE: process row #1 NOTICE: row id: `1` NOTICE: process row #2 NOTICE: row id: `` drop table test; orafce-VERSION_4_14_4/expected/dbms_utility.out000066400000000000000000000006771501757153000214720ustar00rootroot00000000000000\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) NOTICE: Execution time: 2 seconds orafce-VERSION_4_14_4/expected/files.out000066400000000000000000000154651501757153000200650ustar00rootroot00000000000000SET 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 --run this under unprivileged user CREATE ROLE test_role_files LOGIN; SET ROLE TO test_role_files; -- should to fail, unpriviliged user cannot to change utl_file_dir INSERT INTO utl_file.utl_file_dir(dir) VALUES('test_tmp_dir'); ERROR: permission denied for table utl_file_dir 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) 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) SET ROLE TO DEFAULT; DROP FUNCTION checkFlushFile(text); DELETE FROM utl_file.utl_file_dir; -- try to use named directory INSERT INTO utl_file.utl_file_dir(dir, dirname) VALUES(utl_file.tmpdir(), 'TMPDIR'); SELECT gen_file('TMPDIR'); gen_file ---------- (1 row) SELECT read_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('TMPDIR', 'regress_orafce.txt'); fremove --------- (1 row) DROP FUNCTION gen_file(text); DROP FUNCTION read_file(text); DELETE FROM utl_file.utl_file_dir; -- reconnect \c SET ROLE TO test_role_files; -- use any function from orafce, should not to fail SELECT oracle.add_months('2024-05-20', 1); add_months -------------------------- Thu Jun 20 00:00:00 2024 (1 row) SET ROLE TO DEFAULT; DROP ROLE test_role_files; orafce-VERSION_4_14_4/expected/init.out000066400000000000000000000000171501757153000177110ustar00rootroot00000000000000\set ECHO none orafce-VERSION_4_14_4/expected/nlssort.out000066400000000000000000000015721501757153000204610ustar00rootroot00000000000000-- Tests for nlssort -- Skip this test unless it's a Linux/glibc system with the "en_US.utf8" locale installed. SELECT getdatabaseencoding() <> 'UTF8' OR NOT EXISTS (SELECT 1 FROM pg_collation WHERE collname = 'en_US' AND collencoding = pg_char_to_encoding('UTF8')) OR version() !~ 'linux-gnu' AS skip_test \gset \if :skip_test \quit \endif \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_4_14_4/expected/nlssort_1.out000066400000000000000000000005431501757153000206760ustar00rootroot00000000000000-- Tests for nlssort -- Skip this test unless it's a Linux/glibc system with the "en_US.utf8" locale installed. SELECT getdatabaseencoding() <> 'UTF8' OR NOT EXISTS (SELECT 1 FROM pg_collation WHERE collname = 'en_US' AND collencoding = pg_char_to_encoding('UTF8')) OR version() !~ 'linux-gnu' AS skip_test \gset \if :skip_test \quit orafce-VERSION_4_14_4/expected/nlssort_2.out000066400000000000000000000005671501757153000207050ustar00rootroot00000000000000-- Tests for nlssort -- Skip this test unless it's a Linux/glibc system with the "en_US.utf8" locale installed. SELECT getdatabaseencoding() <> 'UTF8' OR NOT EXISTS (SELECT 1 FROM pg_collation WHERE collname = 'en_US' AND collencoding = pg_char_to_encoding('UTF8')) OR version() !~ 'linux-gnu' AS skip_test \gset \if :skip_test invalid command \if \quit orafce-VERSION_4_14_4/expected/nvarchar2.out000066400000000000000000000030171501757153000206370ustar00rootroot00000000000000\set VERBOSITY terse SET client_encoding = utf8; SET search_path TO public, oracle; -- -- 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_4_14_4/expected/orafce.out000066400000000000000000003137761501757153000202300ustar00rootroot00000000000000\set ECHO none SET search_path TO public, oracle; -- -- test built-in date type oracle compatibility functions -- SELECT add_months (date '2003-08-01', 3); add_months ------------ 2003-11-01 (1 row) SELECT add_months (date '2003-08-01', -3); add_months ------------ 2003-05-01 (1 row) SELECT add_months (date '2003-08-21', -3); add_months ------------ 2003-05-21 (1 row) SELECT add_months (date '2003-01-31', 1); add_months ------------ 2003-02-28 (1 row) SELECT add_months (date '2008-02-28', 1); add_months ------------ 2008-03-28 (1 row) SELECT add_months (date '2008-02-29', 1); add_months ------------ 2008-03-31 (1 row) SELECT add_months (date '2008-01-31', 12); add_months ------------ 2009-01-31 (1 row) SELECT add_months (date '2008-01-31', -12); add_months ------------ 2007-01-31 (1 row) SELECT add_months (date '2008-01-31', 95903); add_months ------------ 9999-12-31 (1 row) SELECT add_months (date '2008-01-31', -80640); add_months --------------- 4712-01-31 BC (1 row) SELECT add_months (date '03-21-2008',3); add_months ------------ 2008-06-21 (1 row) SELECT add_months (date '21-MAR-2008',3); add_months ------------ 2008-06-21 (1 row) SELECT add_months (date '21-MAR-08',3); add_months ------------ 2008-06-21 (1 row) SELECT add_months (date '2008-MAR-21',3); add_months ------------ 2008-06-21 (1 row) SELECT add_months (date 'March 21,2008',3); add_months ------------ 2008-06-21 (1 row) SELECT add_months(date '03/21/2008',3); add_months ------------ 2008-06-21 (1 row) SELECT add_months(date '20080321',3); add_months ------------ 2008-06-21 (1 row) SELECT add_months(date '080321',3); add_months ------------ 2008-06-21 (1 row) 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) 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(date '1900-02-01'); last_day ------------ 1900-02-28 (1 row) SELECT last_day(date '2000-02-01'); last_day ------------ 2000-02-29 (1 row) SELECT last_day(date '2007-02-01'); last_day ------------ 2007-02-28 (1 row) SELECT last_day(date '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 public, oracle; SELECT next_day (date '2003-08-01', 'TUESDAY'); next_day ------------ 2003-08-05 (1 row) SELECT next_day (date '2003-08-06', 'WEDNESDAY'); next_day ------------ 2003-08-13 (1 row) SELECT next_day (date '2003-08-06', 'SUNDAY'); next_day ------------ 2003-08-10 (1 row) SELECT next_day (date '2008-01-01', 'sun'); next_day ------------ 2008-01-06 (1 row) SELECT next_day (date '2008-01-01', 'sunAAA'); next_day ------------ 2008-01-06 (1 row) SELECT next_day (date '2008-01-01', 1); next_day ------------ 2008-01-06 (1 row) SELECT next_day (date '2008-01-01', 7); next_day ------------ 2008-01-05 (1 row) 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) 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) 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) SELECT sys_extract_utc(timestamptz '2024-08-17 00:41:26.655376+02'); sys_extract_utc ---------------------------- 2024-08-16 22:41:26.655376 (1 row) SET timezone to 'europe/prague'; SELECT sys_extract_utc(oracle.date '2024-08-17 00:41:26.655376'); sys_extract_utc --------------------- 2024-08-16 22:41:27 (1 row) SET timezone 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 public,oracle; 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 0 = instr('ab;cdx', ';', 0); ?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) set orafce.using_substring_zero_width_in_substr TO orafce; select oracle.substr('TechOnTheNet', -8, 0) = ''; ?column? ---------- t (1 row) set orafce.using_substring_zero_width_in_substr TO oracle; select oracle.substr('TechOnTheNet', -8, 0) is null; ?column? ---------- t (1 row) set orafce.using_substring_zero_width_in_substr TO warning_oracle; select oracle.substr('TechOnTheNet', -8, 0) is null; WARNING: zero substring_length is used in substr function ?column? ---------- t (1 row) set orafce.using_substring_zero_width_in_substr TO default; select oracle.substr('TechOnTheNet', -8, 0) is null; WARNING: zero substring_length is used in substr function ?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::int, 2); nvl ----- 2 (1 row) select nvl(NULL::double precision, 1); nvl ----- 1 (1 row) select nvl(1.1::double precision, 1); nvl ----- 1.1 (1 row) select nvl(1.1::numeric, 1); nvl ----- 1.1 (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.rvrs ('l', -2, -5); 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_char('-44444'); to_char --------- -44444 (1 row) select to_char('1234567890123456'); to_char ------------------ 1234567890123456 (1 row) select to_char('123.456'); to_char --------- 123.456 (1 row) select to_char('123abc'); to_char --------- 123abc (1 row) select to_char('你儽123@$%abc'); to_char --------------- 你儽123@$%abc (1 row) select to_char('1234567890123456789012345678901234567890123456789012345678901234567890'); to_char ------------------------------------------------------------------------ 1234567890123456789012345678901234567890123456789012345678901234567890 (1 row) select to_char(''); to_char --------- (1 row) select to_char(' '); to_char --------- (1 row) select to_char(null); to_char --------- (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 to_date('', 'yyyy-mm-dd'); to_date --------------- 0001-01-01 BC (1 row) SELECT to_date('112012', 'J'); to_date --------------- 4407-07-30 BC (1 row) SELECT to_date('1003/03/15', 'yyyy/mm/dd'); to_date ------------ 1003-03-15 (1 row) SELECT oracle.to_date('', 'yyyy-mm-dd'); to_date --------- (1 row) SELECT oracle.to_date('112012', 'J'); ERROR: Dates before 1582-10-05 ('J2299159') cannot be verified due to a bug in Oracle. SELECT oracle.to_date('1003-03-15', 'yyyy-mm-dd'); ERROR: Dates before 1100-03-01 cannot be verified due to a bug in Oracle. SET orafce.oracle_compatibility_date_limit TO off; SELECT oracle.to_date('112012', 'J'); to_date ------------------------ 4407-07-30 00:00:00 BC (1 row) SELECT oracle.to_date('1003/03/15', 'yyyy/mm/dd'); to_date --------------------- 1003-03-15 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.qualified_sql_name('1broken'); ERROR: string is not qualified SQL name select dbms_assert.simple_sql_name('1broken'); ERROR: string is not simple SQL 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('ļ½ļ½‚ļ½ƒ'); octet_length -------------- 9 (1 row) SELECT octet_length(to_single_byte('ļ½ļ½‚ļ½ƒ')); 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 oracle.orafce__obsolete_to_date('210514 12:13:44.55'); orafce__obsolete_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 public,oracle; -- 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 public,oracle; -- 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 public,oracle; --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 public,oracle; --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 public,oracle; -- -- 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) -- -- trigger functions -- CREATE TABLE trg_test(a varchar, b int, c varchar, d date, e int); CREATE TRIGGER trg_test_xx BEFORE INSERT OR UPDATE ON trg_test FOR EACH ROW EXECUTE PROCEDURE oracle.replace_empty_strings(true); \pset null *** INSERT INTO trg_test VALUES('',10, 'AHOJ', NULL, NULL); WARNING: Field "a" of table "trg_test" is empty string (replaced by NULL). INSERT INTO trg_test VALUES('AHOJ', NULL, '', '2020-01-01', 100); WARNING: Field "c" of table "trg_test" is empty string (replaced by NULL). SELECT * FROM trg_test; a | b | c | d | e ------+-----+------+------------+----- *** | 10 | AHOJ | *** | *** AHOJ | *** | *** | 2020-01-01 | 100 (2 rows) DELETE FROM trg_test; DROP TRIGGER trg_test_xx ON trg_test; CREATE TRIGGER trg_test_xx BEFORE INSERT OR UPDATE ON trg_test FOR EACH ROW EXECUTE PROCEDURE oracle.replace_null_strings(); INSERT INTO trg_test VALUES(NULL, 10, 'AHOJ', NULL, NULL); INSERT INTO trg_test VALUES('AHOJ', NULL, NULL, '2020-01-01', 100); SELECT * FROM trg_test; a | b | c | d | e ------+-----+------+------------+----- | 10 | AHOJ | *** | *** AHOJ | *** | | 2020-01-01 | 100 (2 rows) DROP TABLE trg_test; SELECT oracle.unistr('\0441\043B\043E\043D'); unistr -------- слон (1 row) SELECT oracle.unistr('d\u0061t\U00000061'); unistr -------- data (1 row) -- run-time error SELECT oracle.unistr('wrong: \db99'); ERROR: invalid Unicode surrogate pair SELECT oracle.unistr('wrong: \db99\0061'); ERROR: invalid Unicode surrogate pair SELECT oracle.unistr('wrong: \+00db99\+000061'); ERROR: invalid Unicode surrogate pair SELECT oracle.unistr('wrong: \+2FFFFF'); ERROR: invalid Unicode escape value SELECT oracle.unistr('wrong: \udb99\u0061'); ERROR: invalid Unicode surrogate pair SELECT oracle.unistr('wrong: \U0000db99\U00000061'); ERROR: invalid Unicode surrogate pair SELECT oracle.unistr('wrong: \U002FFFFF'); ERROR: invalid Unicode escape value ---- -- Tests for the greatest/least scalar function ---- -- The PostgreSQL native function returns NULL only if all parameters are nulls SELECT greatest(2, 6, 8); greatest ---------- 8 (1 row) SELECT greatest(2, NULL, 8); greatest ---------- 8 (1 row) SELECT least(2, 6, 8); least ------- 2 (1 row) SELECT least(2, NULL, 8); least ------- 2 (1 row) -- The Oracle function returns NULL on NULL input, even a single parameter SELECT oracle.greatest(2, 6, 8, 4); greatest ---------- 8 (1 row) SELECT oracle.greatest(2, NULL, 8, 4); greatest ---------- *** (1 row) SELECT oracle.least(2, 6, 8, 1); least ------- 1 (1 row) SELECT oracle.least(2, NULL, 8, 1); least ------- *** (1 row) -- Test different data type SELECT oracle.greatest('A'::text, 'B'::text, 'C'::text, 'D'::text); greatest ---------- D (1 row) SELECT oracle.greatest('A'::bpchar, 'B'::bpchar, 'C'::bpchar, 'D'::bpchar); greatest ---------- D (1 row) SELECT oracle.greatest(1::bigint,2::bigint,3::bigint,4::bigint); greatest ---------- 4 (1 row) SELECT oracle.greatest(1::integer,2::integer,3::integer,4::integer); greatest ---------- 4 (1 row) SELECT oracle.greatest(1::smallint,2::smallint,3::smallint,4::smallint); greatest ---------- 4 (1 row) SELECT oracle.greatest(1.2::numeric,2.4::numeric,2.3::numeric,2.2::numeric); greatest ---------- 2.4 (1 row) SELECT oracle.greatest(1.2::double precision,2.4::double precision,2.3::double precision,2.2::double precision); greatest ---------- 2.4 (1 row) SELECT oracle.greatest(1.2::real,2.4::real,2.2::real,2.3::real); greatest ---------- 2.4 (1 row) SELECT oracle.least('A'::text, 'B'::text, 'C'::text, 'D'::text); least ------- A (1 row) SELECT oracle.least('A'::bpchar, 'B'::bpchar, 'C'::bpchar, 'D'::bpchar); least ------- A (1 row) SELECT oracle.least(1::bigint,2::bigint,3::bigint,4::bigint); least ------- 1 (1 row) SELECT oracle.least(1::integer,2::integer,3::integer,4::integer); least ------- 1 (1 row) SELECT oracle.least(1::smallint,2::smallint,3::smallint,4::smallint); least ------- 1 (1 row) SELECT oracle.least(1.2::numeric,2.4::numeric,2.3::numeric,2.2::numeric); least ------- 1.2 (1 row) SELECT oracle.least(1.2::double precision,2.4::double precision,2.3::double precision,2.2::double precision); least ------- 1.2 (1 row) SELECT oracle.least(1.2::real,2.4::real,2.2::real,2.3::real); least ------- 1.2 (1 row) SELECT i, oracle.greatest(100, 24, 1234, 12, i) FROM generate_series(1,3) g(i); i | greatest ---+---------- 1 | 1234 2 | 1234 3 | 1234 (3 rows) -- test remainder function CREATE TABLE testorafce_remainder(v1 int, v2 int); INSERT INTO testorafce_remainder VALUES(24, 7); INSERT INTO testorafce_remainder VALUES(24, 6); INSERT INTO testorafce_remainder VALUES(24, 5); INSERT INTO testorafce_remainder VALUES(-58, -10); INSERT INTO testorafce_remainder VALUES(58, 10); INSERT INTO testorafce_remainder VALUES(58, -10); INSERT INTO testorafce_remainder VALUES(58, 10); INSERT INTO testorafce_remainder VALUES(-44, -10); INSERT INTO testorafce_remainder VALUES(44, 10); INSERT INTO testorafce_remainder VALUES(44, -10); INSERT INTO testorafce_remainder VALUES(44, 10); SELECT v1, v2, oracle.remainder(v1, v2) FROM testorafce_remainder; v1 | v2 | remainder -----+-----+----------- 24 | 7 | 3 24 | 6 | 0 24 | 5 | -1 -58 | -10 | 2 58 | 10 | -2 58 | -10 | -2 58 | 10 | -2 -44 | -10 | -4 44 | 10 | 4 44 | -10 | 4 44 | 10 | 4 (11 rows) SELECT v1, v2, oracle.remainder(v1::smallint, v2::smallint) FROM testorafce_remainder; v1 | v2 | remainder -----+-----+----------- 24 | 7 | 3 24 | 6 | 0 24 | 5 | -1 -58 | -10 | 2 58 | 10 | -2 58 | -10 | -2 58 | 10 | -2 -44 | -10 | -4 44 | 10 | 4 44 | -10 | 4 44 | 10 | 4 (11 rows) SELECT v1, v2, oracle.remainder(v1::bigint, v2::bigint) FROM testorafce_remainder; v1 | v2 | remainder -----+-----+----------- 24 | 7 | 3 24 | 6 | 0 24 | 5 | -1 -58 | -10 | 2 58 | 10 | -2 58 | -10 | -2 58 | 10 | -2 -44 | -10 | -4 44 | 10 | 4 44 | -10 | 4 44 | 10 | 4 (11 rows) SELECT v1, v2, oracle.remainder(v1::numeric, v2::numeric) FROM testorafce_remainder; v1 | v2 | remainder -----+-----+----------- 24 | 7 | 3 24 | 6 | 0 24 | 5 | -1 -58 | -10 | 2 58 | 10 | -2 58 | -10 | -2 58 | 10 | -2 -44 | -10 | -4 44 | 10 | 4 44 | -10 | 4 44 | 10 | 4 (11 rows) DROP TABLE testorafce_remainder; orafce-VERSION_4_14_4/expected/orafce2.out000066400000000000000000000004061501757153000202710ustar00rootroot00000000000000-- 2) fails and throws error: 'ERROR: could not determine polymorphic type -- because input has type "unknown"' select oracle.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_4_14_4/expected/orafce2_1.out000066400000000000000000000004101501757153000205040ustar00rootroot00000000000000-- 2) fails and throws error: 'ERROR: could not determine polymorphic type -- because input has type "unknown"' select oracle.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_4_14_4/expected/regexp_func.out000066400000000000000000001007531501757153000212630ustar00rootroot00000000000000-- Test for the regexp_*() function \set ECHO none SET search_path TO oracle, "$user", public, pg_catalog; ---- -- Tests for REGEXP_LIKE() ---- -- ORACLE> SELECT 1 FROM DUAL WHERE REGEXP_LIKE('a'||CHR(10)||'d', 'a.d'); -> NULL SELECT REGEXP_LIKE('a'||CHR(10)||'d', 'a.d'); regexp_like ------------- f (1 row) -- ORACLE> SELECT 1 FROM DUAL WHERE REGEXP_LIKE('a'||CHR(10)||'d', 'a.d', 'm'); -> NULL SELECT REGEXP_LIKE('a'||CHR(10)||'d', 'a.d', 'm'); regexp_like ------------- f (1 row) -- ORACLE> SELECT 1 FROM DUAL WHERE REGEXP_LIKE('a'||CHR(10)||'d', 'a.d', 'n'); -> 1 SELECT REGEXP_LIKE('a'||CHR(10)||'d', 'a.d', 'n'); regexp_like ------------- t (1 row) -- ORACLE> SELECT 1 FROM DUAL WHERE REGEXP_LIKE('Steven', '^Ste(v|ph)en$'); -> 1 SELECT REGEXP_LIKE('Steven', '^Ste(v|ph)en$'); regexp_like ------------- t (1 row) -- ORACLE> SELECT 1 FROM DUAL WHERE regexp_like('foo' || chr(10) || 'bar' || chr(10) || 'bequq' || chr(10) || 'baz', '^bar'); -> NULL SELECT REGEXP_LIKE('foo' || chr(10) || 'bar' || chr(10) || 'bequq' || chr(10) || 'baz', '^bar'); regexp_like ------------- f (1 row) -- ORACLE> SELECT 1 FROM DUAL WHERE regexp_like('foo' || chr(10) || 'bar' || chr(10) || 'bequq' || chr(10) || 'baz', 'bar'); -> 1 SELECT REGEXP_LIKE('foo' || chr(10) || 'bar' || chr(10) || 'bequq' || chr(10) || 'baz', 'bar'); regexp_like ------------- t (1 row) -- ORACLE> SELECT 1 FROM DUAL WHERE regexp_like('foo' || chr(10) || 'bar' || chr(10) || 'bequq' || chr(10) || 'baz', '^bar', 'm'); -> 1 SELECT REGEXP_LIKE('foo' || chr(10) || 'bar' || chr(10) || 'bequq' || chr(10) || 'baz', '^bar', 'm'); regexp_like ------------- t (1 row) -- ORACLE> SELECT 1 FROM DUAL WHERE regexp_like('foo' || chr(10) || 'bar' || chr(10) || 'bequq' || chr(10) || 'baz', '^bar', 'n'); -> NULL SELECT REGEXP_LIKE('foo' || chr(10) || 'bar' || chr(10) || 'bequq' || chr(10) || 'baz', '^bar', 'n'); regexp_like ------------- f (1 row) -- ORACLE> SELECT 1 FROM DUAL WHERE REGEXP_LIKE('GREEN', '([aeiou])\1'); -> NULL SELECT REGEXP_LIKE('GREEN', '([aeiou])\1'); regexp_like ------------- f (1 row) -- ORACLE> SELECT 1 FROM DUAL WHERE REGEXP_LIKE('GREEN', '([aeiou])\1', 'i'); -> 1 SELECT REGEXP_LIKE('GREEN', '([aeiou])\1', 'i'); regexp_like ------------- t (1 row) -- ORACLE> SELECT 1 FROM DUAL WHERE REGEXP_LIKE('ORANGE' || chr(10) || 'GREEN', '([aeiou])\1', 'i'); -> 1 SELECT REGEXP_LIKE('ORANGE' || chr(10) || 'GREEN', '([aeiou])\1', 'i'); regexp_like ------------- t (1 row) -- ORACLE> SELECT 1 FROM DUAL WHERE REGEXP_LIKE('ORANGE' || chr(10) || 'GREEN', '^..([aeiou])\1', 'i'); -> NULL SELECT REGEXP_LIKE('ORANGE' || chr(10) || 'GREEN', '^..([aeiou])\1', 'i'); regexp_like ------------- f (1 row) -- ORACLE> SELECT 1 FROM DUAL WHERE REGEXP_LIKE('ORANGE' || chr(10) || 'GREEN', '([aeiou])\1', 'in'); -> 1 SELECT REGEXP_LIKE('ORANGE' || chr(10) || 'GREEN', '([aeiou])\1', 'in'); regexp_like ------------- t (1 row) -- ORACLE> SELECT 1 FROM DUAL WHERE REGEXP_LIKE('ORANGE' || chr(10) || 'GREEN', '^..([aeiou])\1', 'in'); -> NULL SELECT REGEXP_LIKE('ORANGE' || chr(10) || 'GREEN', '^..([aeiou])\1', 'in'); regexp_like ------------- f (1 row) -- ORACLE> SELECT 1 FROM DUAL WHERE REGEXP_LIKE('ORANGE' || chr(10) || 'GREEN', '^..([aeiou])\1', 'im'); -> 1 SELECT REGEXP_LIKE('ORANGE' || chr(10) || 'GREEN', '^..([aeiou])\1', 'im'); regexp_like ------------- t (1 row) ---- -- Tests for REGEXP_COUNT() ---- -- ORACLE> SELECT REGEXP_COUNT('a,b' || chr(10) || 'c','[^,]+') FROM DUAL; -> 2 SELECT REGEXP_COUNT('a,b' || chr(10) || 'c','[^,]+'); regexp_count -------------- 2 (1 row) -- ORACLE> SELECT REGEXP_COUNT('a,b' || chr(10) || 'c','b.c') FROM DUAL; -> 0 SELECT REGEXP_COUNT('a,b' || chr(10) || 'c','b.c'); regexp_count -------------- 0 (1 row) -- ORACLE> SELECT REGEXP_COUNT('a'||CHR(10)||'d', 'a.d') FROM DUAL; -> 0 SELECT REGEXP_COUNT('a'||CHR(10)||'d', 'a.d'); regexp_count -------------- 0 (1 row) -- ORACLE> SELECT REGEXP_COUNT('a'||CHR(10)||'d', 'a.d', 1, 'm') FROM DUAL; -> 0 SELECT REGEXP_COUNT('a'||CHR(10)||'d', 'a.d', 1, 'm'); regexp_count -------------- 0 (1 row) -- ORACLE> SELECT REGEXP_COUNT('a'||CHR(10)||'d', 'a.d', 1, 'n') FROM DUAL; -> 1 SELECT REGEXP_COUNT('a'||CHR(10)||'d', 'a.d', 1, 'n'); regexp_count -------------- 1 (1 row) -- ORACLE> SELECT REGEXP_COUNT('Steven', '^Ste(v|ph)en$') FROM DUAL; -> 1 SELECT REGEXP_COUNT('Steven', '^Ste(v|ph)en$'); regexp_count -------------- 1 (1 row) -- ORACLE> SELECT REGEXP_COUNT('foo' || chr(10) || 'bar' || chr(10) || 'bequq' || chr(10) || 'baz', '^bar') FROM DUAL; -> 0 SELECT REGEXP_COUNT('foo' || chr(10) || 'bar' || chr(10) || 'bequq' || chr(10) || 'baz', '^bar'); regexp_count -------------- 0 (1 row) -- ORACLE> SELECT REGEXP_COUNT('foo' || chr(10) || 'bar' || chr(10) || 'bequq' || chr(10) || 'baz', 'bar') FROM DUAL; -> 1 SELECT REGEXP_COUNT('foo' || chr(10) || 'bar' || chr(10) || 'bequq' || chr(10) || 'baz', 'bar'); regexp_count -------------- 1 (1 row) -- ORACLE> SELECT REGEXP_COUNT('foo' || chr(10) || 'bar' || chr(10) || 'bequq' || chr(10) || 'baz', '^bar', 0, 'm') FROM DUAL; -> ORA-01428: argument '0' is out of range SELECT REGEXP_COUNT('foo' || chr(10) || 'bar' || chr(10) || 'bequq' || chr(10) || 'baz', '^bar', 0, 'm'); ERROR: argument 'position' must be a number greater than 0 -- ORACLE> SELECT REGEXP_COUNT('foo' || chr(10) || 'bar' || chr(10) || 'bequq' || chr(10) || 'baz', '^bar', 1, 'm') FROM DUAL; -> 1 SELECT REGEXP_COUNT('foo' || chr(10) || 'bar' || chr(10) || 'bequq' || chr(10) || 'baz', '^bar', 1, 'm'); regexp_count -------------- 1 (1 row) -- ORACLE> SELECT REGEXP_COUNT('foo' || chr(10) || 'bar' || chr(10) || 'bequq' || chr(10) || 'baz', '^bar', 1, 'n') FROM DUAL; -> 0 SELECT REGEXP_COUNT('foo' || chr(10) || 'bar' || chr(10) || 'bequq' || chr(10) || 'baz', '^bar', 1, 'n'); regexp_count -------------- 0 (1 row) -- ORACLE> SELECT REGEXP_COUNT('GREEN', '([aeiou])\1') FROM DUAL; -> 0 SELECT REGEXP_COUNT('GREEN', '([aeiou])\1'); regexp_count -------------- 0 (1 row) -- ORACLE> SELECT REGEXP_COUNT('GREEN', '([aeiou])\1', 1, 'i') FROM DUAL; -> 1 SELECT REGEXP_COUNT('GREEN', '([aeiou])\1', 1, 'i'); regexp_count -------------- 1 (1 row) -- ORACLE> SELECT REGEXP_COUNT('ORANGE' || chr(10) || 'GREEN', '([aeiou])\1', 1, 'i') FROM DUAL; -> 1 SELECT REGEXP_COUNT('ORANGE' || chr(10) || 'GREEN', '([aeiou])\1', 1, 'i'); regexp_count -------------- 1 (1 row) -- ORACLE> SELECT REGEXP_COUNT('ORANGE' || chr(10) || 'GREEN', '^..([aeiou])\1', 1, 'i') FROM DUAL; -> 0 SELECT REGEXP_COUNT('ORANGE' || chr(10) || 'GREEN', '^..([aeiou])\1', 1, 'i'); regexp_count -------------- 0 (1 row) -- ORACLE> SELECT REGEXP_COUNT('ORANGE' || chr(10) || 'GREEN', '([aeiou])\1', 1, 'in') FROM DUAL; -> 1 SELECT REGEXP_COUNT('ORANGE' || chr(10) || 'GREEN', '([aeiou])\1', 1, 'in'); regexp_count -------------- 1 (1 row) -- ORACLE> SELECT REGEXP_COUNT('ORANGE' || chr(10) || 'GREEN', '^..([aeiou])\1', 1, 'in') FROM DUAL; -> 0 SELECT REGEXP_COUNT('ORANGE' || chr(10) || 'GREEN', '^..([aeiou])\1', 1, 'in'); regexp_count -------------- 0 (1 row) -- ORACLE> SELECT REGEXP_COUNT('ORANGE' || chr(10) || 'GREEN', '^..([aeiou])\1', 1, 'im') FROM DUAL; -> 1 SELECT REGEXP_COUNT('ORANGE' || chr(10) || 'GREEN', '^..([aeiou])\1', 1, 'im'); regexp_count -------------- 1 (1 row) -- ORACLE> SELECT REGEXP_COUNT('123123123123123', '(12)3', 1, 'i') REGEXP_COUNT FROM DUAL; -> 5 SELECT REGEXP_COUNT('123123123123123', '(12)3', 1, 'i'); regexp_count -------------- 5 (1 row) -- ORACLE> SELECT REGEXP_COUNT('123123123123', '123', 3, 'i') COUNT FROM DUAL; -> 3 SELECT REGEXP_COUNT('123123123123', '123', 3, 'i'); regexp_count -------------- 3 (1 row) -- ORACLE> SELECT REGEXP_COUNT('ABC123', '[A-Z]'), REGEXP_COUNT('A1B2C3', '[A-Z]') FROM DUAL; -> 3 | 3 SELECT REGEXP_COUNT('ABC123', '[A-Z]'), oracle.REGEXP_COUNT('A1B2C3', '[A-Z]'); regexp_count | regexp_count --------------+-------------- 3 | 3 (1 row) -- ORACLE> SELECT REGEXP_COUNT('ABC123', '[A-Z][0-9]'), REGEXP_COUNT('A1B2C3', '[A-Z][0-9]') FROM DUAL; -> 1 | 3 SELECT REGEXP_COUNT('ABC123', '[A-Z][0-9]'), oracle.REGEXP_COUNT('A1B2C3', '[A-Z][0-9]'); regexp_count | regexp_count --------------+-------------- 1 | 3 (1 row) -- ORACLE> SELECT REGEXP_COUNT('ABC123', '^[A-Z][0-9]'), REGEXP_COUNT('A1B2C3', '^[A-Z][0-9]') FROM DUAL; -> 0 | 1 SELECT REGEXP_COUNT('ABC123', '^[A-Z][0-9]'), oracle.REGEXP_COUNT('A1B2C3', '^[A-Z][0-9]'); regexp_count | regexp_count --------------+-------------- 0 | 1 (1 row) -- ORACLE> SELECT REGEXP_COUNT('ABC123', '([A-Z][0-9]){2}'), REGEXP_COUNT('A1B2C3', '([A-Z][0-9]){2}') FROM DUAL; -> 0 | 1 SELECT REGEXP_COUNT('ABC123', '([A-Z][0-9]){2}'), oracle.REGEXP_COUNT('A1B2C3', '([A-Z][0-9]){2}'); regexp_count | regexp_count --------------+-------------- 0 | 1 (1 row) -- Check negatives values that must throw an error SELECT REGEXP_COUNT('ORANGE' || chr(10) || 'GREEN', '^..([aeiou])\1', -1, 'i'); ERROR: argument 'position' must be a number greater than 0 ---- -- Tests for REGEXP_INSTR() ---- -- ORACLE> SELECT REGEXP_INSTR('1234567890', '(123)(4(56)(78))') FROM DUAL; -> 1 SELECT REGEXP_INSTR('1234567890', '(123)(4(56)(78))'); regexp_instr -------------- 1 (1 row) -- ORACLE> SELECT REGEXP_INSTR('1234567890', '(4(56)(78))') FROM DUAL; -> 4 SELECT REGEXP_INSTR('1234567890', '(4(56)(78))'); regexp_instr -------------- 4 (1 row) -- ORACLE> SELECT regexp_instr('1234567890', '123(4(56)(78))', 3) FROM DUAL; -> 0 SELECT REGEXP_INSTR('1234567890', '(123)(4(56)(78))', 3); regexp_instr -------------- 0 (1 row) -- ORACLE> SELECT REGEXP_INSTR('1234567890', '(4(56)(78))', 3) FROM DUAL; -> 4 SELECT REGEXP_INSTR('1234567890', '(4(56)(78))', 3); regexp_instr -------------- 4 (1 row) -- ORACLE> SELECT REGEXP_INSTR('500 Oracle Parkway, Redwood Shores, CA', '[^ ]+', 1, 6) FROM DUAL; -> 37 SELECT REGEXP_INSTR('500 Oracle Parkway, Redwood Shores, CA', '[^ ]+', 1, 6); regexp_instr -------------- 37 (1 row) -- ORACLE> SELECT REGEXP_INSTR('500 Oracle Parkway, Redwood Shores, CA', '[S|R|P][[:alpha:]]{6}', 3, 2, 0) FROM DUAL; -> 21 SELECT REGEXP_INSTR('500 Oracle Parkway, Redwood Shores, CA', '[S|R|P][[:alpha:]]{6}', 3, 2, 0); regexp_instr -------------- 21 (1 row) -- ORACLE> SELECT REGEXP_INSTR('500 Oracle Parkway, Redwood Shores, CA', '[S|R|P][[:alpha:]]{6}', 3, 2, 1) FROM DUAL; -> 28 SELECT REGEXP_INSTR('500 Oracle Parkway, Redwood Shores, CA', '[S|R|P][[:alpha:]]{6}', 3, 2, 1); regexp_instr -------------- 28 (1 row) -- ORACLE> SELECT REGEXP_INSTR('500 Oracle Parkway, Redwood Shores, CA', '[s|r|p][[:alpha:]]{6}', 3, 2, 1, 'i') FROM DUAL; -> 28 SELECT REGEXP_INSTR('500 Oracle Parkway, Redwood Shores, CA', '[q|r|p][[:alpha:]]{6}', 3, 2, 1, 'i'); regexp_instr -------------- 28 (1 row) -- ORACLE> SELECT REGEXP_INSTR('1234567890', '(123)(4(56)(78))', 1, 1, 0, 'i', 0) FROM DUAL; -> 1 SELECT REGEXP_INSTR('1234567890', '(123)(4(56)(78))', 1, 1, 0, 'i', 0); regexp_instr -------------- 1 (1 row) -- ORACLE> SELECT REGEXP_INSTR('1234567890', '(123)(4(56)(78))', 1, 1, 0, 'i', 1) FROM DUAL; -> 1 SELECT REGEXP_INSTR('1234567890', '(123)(4(56)(78))', 1, 1, 0, 'i', 1); regexp_instr -------------- 1 (1 row) -- ORACLE> SELECT REGEXP_INSTR('1234567890', '(123)(4(56)(78))', 1, 1, 0, 'i', 2) FROM DUAL; -> 4 SELECT REGEXP_INSTR('1234567890', '(123)(4(56)(78))', 1, 1, 0, 'i', 2); regexp_instr -------------- 4 (1 row) -- ORACLE> SELECT REGEXP_INSTR('1234567890', '(123)(4(56)(78))', 1, 1, 0, 'i', 4) FROM DUAL; -> 7 SELECT REGEXP_INSTR('1234567890', '(123)(4(56)(78))', 1, 1, 0, 'i', 4); regexp_instr -------------- 7 (1 row) -- ORACLE> SELECT REGEXP_INSTR('1234567890 1234567890', '(123)(4(56)(78))', 1, 1, 0, 'i', 4) FROM DUAL; -> 7 SELECT REGEXP_INSTR('1234567890 1234567890', '(123)(4(56)(78))', 1, 1, 0, 'i', 4); regexp_instr -------------- 7 (1 row) -- ORACLE> SELECT REGEXP_INSTR('1234567890 1234567890', '(123)(4(56)(78))', 1, 2, 0, 'i', 4) FROM DUAL; -> 18 SELECT REGEXP_INSTR('1234567890 1234567890', '(123)(4(56)(78))', 1, 2, 0, 'i', 4); regexp_instr -------------- 18 (1 row) -- ORACLE> SELECT REGEXP_INSTR('1234567890 1234567890', '(123)(4(56)(78))', 1, 2, 1, 'i', 4) FROM DUAL; -> 20 SELECT REGEXP_INSTR('1234567890 1234567890', '(123)(4(56)(78))', 1, 2, 1, 'i', 4); regexp_instr -------------- 20 (1 row) -- ORACLE> SELECT REGEXP_INSTR('1234567890 1234567890 1234567890', '(123)(4(56)(78))', 1, 3, 0,'i', 4) FROM DUAL; -> 29 SELECT REGEXP_INSTR('1234567890 1234567890 1234567890', '(123)(4(56)(78))', 1, 3, 0, 'i', 4); regexp_instr -------------- 29 (1 row) -- ORACLE> SELECT REGEXP_INSTR('1234567890 1234567890 1234567890', '(123)(4(56)(78))', 1, 3, 1,'i', 4) FROM DUAL; -> 31 SELECT REGEXP_INSTR('1234567890 1234567890 1234567890', '(123)(4(56)(78))', 1, 3, 1, 'i', 4); regexp_instr -------------- 31 (1 row) -- DROP TABLE regexp_temp; -- CREATE TABLE regexp_temp(empName varchar2(20), emailID varchar2(20)); -- INSERT INTO regexp_temp (empName, emailID) VALUES ('John Doe', 'johndoe@example.com'); -- INSERT INTO regexp_temp (empName, emailID) VALUES ('Jane Doe', 'janedoe'); -- COMMIT; CREATE TEMPORARY TABLE regexp_temp(empName varchar(20), emailID varchar(20)); INSERT INTO regexp_temp (empName, emailID) VALUES ('John Doe', 'johndoe@example.com'); INSERT INTO regexp_temp (empName, emailID) VALUES ('Jane Doe', 'janedoe'); -- -- ORACLE> SELECT emailID, REGEXP_INSTR(emailID, '\w+@\w+(\.\w+)+') "IS_A_VALID_EMAIL" FROM regexp_temp; -- EMAILID IS_A_VALID_EMAIL -- -------------------- ---------------- -- johndoe@example.com 1 -- example.com 0 SELECT emailID, REGEXP_INSTR(emailID, '\w+@\w+(\.\w+)+') FROM regexp_temp; emailid | regexp_instr ---------------------+-------------- johndoe@example.com | 1 janedoe | 0 (2 rows) -- -- ORACLE> SELECT emailID, REGEXP_INSTR(emailID, '\w+@\w+(\.\w+)+', 1, 1, 0, 'i', 0) "IS_A_VALID_EMAIL" FROM regexp_temp; -- EMAILID IS_A_VALID_EMAIL -- -------------------- ---------------- -- johndoe@example.com 1 -- example.com 0 SELECT emailID, REGEXP_INSTR(emailID, '\w+@\w+(\.\w+)+', 1, 1, 0, 'i', 0) FROM regexp_temp; emailid | regexp_instr ---------------------+-------------- johndoe@example.com | 1 janedoe | 0 (2 rows) -- -- ORACLE> SELECT emailID, REGEXP_INSTR(emailID, '\w+@\w+(\.\w+)+', 1, 1, 0, 'i', 1) "IS_A_VALID_EMAIL" FROM regexp_temp; -- EMAILID IS_A_VALID_EMAIL -- -------------------- ---------------- -- johndoe@example.com 16 -- example.com 0 SELECT emailID, REGEXP_INSTR(emailID, '\w+@\w+(\.\w+)+', 1, 1, 0, 'i', 1) FROM regexp_temp; emailid | regexp_instr ---------------------+-------------- johndoe@example.com | 16 janedoe | 0 (2 rows) DROP TABLE regexp_temp; -- Check negatives values that must throw an error SELECT REGEXP_INSTR('1234567890 1234567890 1234567890', '(123)(4(56)(78))', -1, 3, 1, 'i', 4); ERROR: argument 'position' must be a number greater than 0 SELECT REGEXP_INSTR('1234567890 1234567890 1234567890', '(123)(4(56)(78))', 1, -3, 1, 'i', 4); ERROR: argument 'occurence' must be a number greater than 0 SELECT REGEXP_INSTR('1234567890 1234567890 1234567890', '(123)(4(56)(78))', 1, 3, -1, 'i', 4); ERROR: argument 'return_opt' must be 0 or 1 SELECT REGEXP_INSTR('1234567890 1234567890 1234567890', '(123)(4(56)(78))', 1, 3, 1, 'i', -4); ERROR: argument 'group' must be a positive number -- ORACLE> SELECT REGEXP_INSTR('123 123456 1234567, 1234567 1234567 12', '[^ ]+', 1, 6) FROM DUAL; -> 37 SELECT REGEXP_INSTR('123 123456 1234567, 1234567 1234567 12', '[^ ]+', 1, 6) ; regexp_instr -------------- 37 (1 row) -- ORACLE> SELECT REGEXP_INSTR('123 123456 1234567, 1234567 1234567 12', '[^ ]+', 1, 6, 1) FROM DUAL; -> 39 SELECT REGEXP_INSTR('123 123456 1234567, 1234567 1234567 12', '[^ ]+', 1, 6, 1) ; regexp_instr -------------- 39 (1 row) -- ORACLE> SELECT REGEXP_INSTR('123 123456 1234567, 1234567 1234567 12', '[^ ]+', 1, 6, 1, 'i') FROM DUAL; -> 39 SELECT REGEXP_INSTR('123 123456 1234567, 1234567 1234567 12', '[^ ]+', 1, 6, 1, 'i') ; regexp_instr -------------- 39 (1 row) ---- -- Tests for REGEXP_SUBSTR() ---- -- ORACLE> SELECT REGEXP_SUBSTR('a,b'||chr(10)||'c','[^,]+',1,2) FROM DUAL; -> b and c SELECT REGEXP_SUBSTR('a,b'||chr(10)||'c','[^,]+',1,2); regexp_substr --------------- b + c (1 row) -- ORACLE> SELECT REGEXP_SUBSTR('a,b'||chr(10)||'c','.',1,4) FROM DUAL; -> c SELECT REGEXP_SUBSTR('a,b'||chr(10)||'c','.',1,4); regexp_substr --------------- c (1 row) -- ORACLE> SELECT REGEXP_SUBSTR('number of your street, zipcode town, FR', ',[^,]+') FROM DUAL; -> , zipcode town SELECT REGEXP_SUBSTR('number of your street, zipcode town, FR', ',[^,]+'); regexp_substr ---------------- , zipcode town (1 row) -- ORACLE> SELECT REGEXP_SUBSTR('http://www.example.com/products', 'http://([[:alnum:]]+\.?){3,4}/?') FROM DUAL; -> http://www.example.com/ SELECT REGEXP_SUBSTR('http://www.example.com/products', 'http://([[:alnum:]]+\.?){3,4}/?'); regexp_substr ------------------------- http://www.example.com/ (1 row) -- ORACLE> SELECT REGEXP_SUBSTR('number of your street, zipcode town, FR', ',[^,]+', 24) FROM DUAL; -> , FR SELECT REGEXP_SUBSTR('number of your street, zipcode town, FR', ',[^,]+', 24); regexp_substr --------------- , FR (1 row) -- ORACLE> SELECT REGEXP_SUBSTR('number of your street, zipcode town, FR', ',[^,]+', 1, 1) FROM DUAL; -> , zipcode town SELECT REGEXP_SUBSTR('number of your street, zipcode town, FR', ',[^,]+', 1, 1); regexp_substr ---------------- , zipcode town (1 row) -- ORACLE> SELECT REGEXP_SUBSTR('number of your street, zipcode town, FR', ',[^,]+', 1, 2) FROM DUAL; -> , FR SELECT REGEXP_SUBSTR('number of your street, zipcode town, FR', ',[^,]+', 1, 2); regexp_substr --------------- , FR (1 row) -- ORACLE> SELECT REGEXP_SUBSTR('number of your street, zipcode town, FR', ',\s+[Zf][^,]+', 1, 1) FROM DUAL; -> NULL SELECT REGEXP_SUBSTR('number of your street, zipcode town, FR', ',\s+[Zf][^,]+', 1, 1); regexp_substr --------------- (1 row) -- ORACLE> SELECT REGEXP_SUBSTR('number of your street, zipcode town, FR', ',\s+[Zf][^,]+', 1, 1, 'i') FROM DUAL; -> , zipcode town SELECT REGEXP_SUBSTR('number of your street, zipcode town, FR', ',\s+[Zf][^,]+', 1, 1, 'i'); regexp_substr ---------------- , zipcode town (1 row) -- ORACLE> SELECT REGEXP_SUBSTR('number of your street, zipcode town, FR', ',\s+[Zf][^,]+', 1, 1, 'i', 0) FROM DUAL; -> , zipcode town SELECT REGEXP_SUBSTR('number of your street, zipcode town, FR', ',\s+[Zf][^,]+', 1, 1, 'i', 0); regexp_substr ---------------- , zipcode town (1 row) -- ORACLE> SELECT REGEXP_SUBSTR('number of your street, zipcode town, FR', ',\s+[Zf][^,]+', 1, 1, 'i', 1) FROM DUAL; -> NULL SELECT REGEXP_SUBSTR('number of your street, zipcode town, FR', ',\s+[Zf][^,]+', 1, 1, 'i', 1); regexp_substr --------------- (1 row) -- ORACLE> SELECT REGEXP_SUBSTR('number of your street, zipcode town, FR', ',\s+([Zf][^,]+)', 1, 1, 'i', 1) FROM DUAL; -> zipcode town SELECT REGEXP_SUBSTR('number of your street, zipcode town, FR', ',\s+([Zf][^,]+)', 1, 1, 'i', 1); regexp_substr --------------- zipcode town (1 row) -- ORACLE> SELECT REGEXP_SUBSTR('1234567890 1234567890', '(123)(4(56)(78))', 1, 1, 'i', 4) FROM DUAL; -> 78 SELECT REGEXP_SUBSTR('1234567890 1234567890', '(123)(4(56)(78))', 1, 1, 'i', 4); regexp_substr --------------- 78 (1 row) -- ORACLE> SELECT REGEXP_SUBSTR('1234567890 1234557890', '(123)(4(5[56])(78))', 1, 2, 'i', 3) FROM DUAL; -> 55 SELECT REGEXP_SUBSTR('1234567890 1234557890', '(123)(4(5[56])(78))', 1, 2, 'i', 3); regexp_substr --------------- 55 (1 row) -- ORACLE> SELECT REGEXP_SUBSTR('1234567890 1234567890', '(123)(4(56)(78))', 1, 1, 'i', 0) FROM DUAL; -> 12345678 SELECT REGEXP_SUBSTR('1234567890 1234567890', '(123)(4(56)(78))', 1, 1, 'i', 0); regexp_substr --------------- 12345678 (1 row) -- Check negatives values that must throw an error SELECT REGEXP_SUBSTR('1234567890 1234567890', '(123)(4(56)(78))', -1, 1, 'i', 0); ERROR: argument 'position' must be a number greater than 0 SELECT REGEXP_SUBSTR('1234567890 1234567890', '(123)(4(56)(78))', 1, -1, 'i', 0); ERROR: argument 'occurence' must be a number greater than 0 SELECT REGEXP_SUBSTR('1234567890 1234567890', '(123)(4(56)(78))', 1, 1, 'i', -1); ERROR: argument 'group' must be a positive number ---- -- Tests for REGEXP_REPLACE() ---- -- ORACLE> SELECT REGEXP_REPLACE('512.123.4567', '([[:digit:]]{3})\.([[:digit:]]{3})\.([[:digit:]]{4})', '(\1) \2-\3') FROM DUAL; -> (512) 123-4567 SELECT REGEXP_REPLACE('512.123.4567', '([[:digit:]]{3})\.([[:digit:]]{3})\.([[:digit:]]{4})', '(\1) \2-\3'); regexp_replace ---------------- (512) 123-4567 (1 row) -- ORACLE> SELECT REGEXP_REPLACE('512.123.4567 612.123.4567', '([[:digit:]]{3})\.([[:digit:]]{3})\.([[:digit:]]{4})', '(\1) \2-\3') FROM DUAL; -> (512) 123-4567 (612) 123-4567 SELECT oracle.REGEXP_REPLACE('512.123.4567 612.123.4567', '([[:digit:]]{3})\.([[:digit:]]{3})\.([[:digit:]]{4})', '(\1) \2-\3'); regexp_replace ------------------------------- (512) 123-4567 (612) 123-4567 (1 row) -- ORACLE> SELECT REGEXP_REPLACE('number your street, zipcode town, FR', '( ){2,}', ' ') FROM DUAL; -> number your street, zipcode town, FR SELECT oracle.REGEXP_REPLACE('number your street, zipcode town, FR', '( ){2,}', ' '); regexp_replace -------------------------------------- number your street, zipcode town, FR (1 row) -- ORACLE> SELECT REGEXP_REPLACE('number your street,'||CHR(10)||' zipcode town, FR', '( ){2,}', ' ') FROM DUAL; -> number your street, -- zipcode town, FR SELECT oracle.REGEXP_REPLACE('number your street,'||CHR(10)||' zipcode town, FR', '( ){2,}', ' '); regexp_replace --------------------- number your street,+ zipcode town, FR (1 row) -- ORACLE> SELECT REGEXP_REPLACE('number your street, zipcode town, FR', '( ){2,}', ' ', 9) FROM DUAL; -> number your street, zipcode town, FR SELECT oracle.REGEXP_REPLACE('number your street, zipcode town, FR', '( ){2,}', ' ', 9); regexp_replace ---------------------------------------- number your street, zipcode town, FR (1 row) -- ORACLE> SELECT REGEXP_REPLACE('number your street, zipcode town, FR', '( ){2,}', ' ', 9, 0) FROM DUAL; -> number your street, zipcode town, FR SELECT oracle.REGEXP_REPLACE('number your street, zipcode town, FR', '( ){2,}', ' ', 9, 0); regexp_replace ---------------------------------------- number your street, zipcode town, FR (1 row) -- ORACLE> SELECT REGEXP_REPLACE('number your street, zipcode town, FR', '( ){2,}', ' ', 9, 2) FROM DUAL; -> number your street, zipcode town, FR SELECT oracle.REGEXP_REPLACE('number your street, zipcode town, FR', '( ){2,}', ' ', 9, 2); regexp_replace --------------------------------------------- number your street, zipcode town, FR (1 row) -- ORACLE> SELECT REGEXP_REPLACE('number your street, zipcode town, FR', '( ){2,}', ' ', 9, 2, 'm') FROM DUAL; -> number your street, zipcode town, FR SELECT oracle.REGEXP_REPLACE('number your street, zipcode town, FR', '( ){2,}', ' ', 9, 2, 'm'); regexp_replace --------------------------------------------- number your street, zipcode town, FR (1 row) -- ORACLE> SELECT REGEXP_REPLACE('number your street, zipcode town, FR', '([EURT]){2,}', '[\1]', 9, 2, 'i') FROM DUAL; -> number your s[t], zipcode town, FR SELECT oracle.REGEXP_REPLACE('number your street, zipcode town, FR', '([EURT]){2,}', '[\1]', 9, 2, 'i'); regexp_replace ---------------------------------------------- number your s[t], zipcode town, FR (1 row) -- ORACLE> SELECT REGEXP_REPLACE('number your street, zipcode town, FR', '[ ]{2,}', ' ', 9, 2) FROM DUAL; -> number your street, zipcode town, FR SELECT oracle.REGEXP_REPLACE('number your street, zipcode town, FR', '( ){2,}', ' ', 9, 2); regexp_replace --------------------------------------------- number your street, zipcode town, FR (1 row) -- ORACLE> SELECT REGEXP_REPLACE ('A PostgreSQL function', 'A|e|i|o|u', 'X', 1, 2) FROM DUAL; -> A PXstgreSQL function SELECT oracle.REGEXP_REPLACE ('A PostgreSQL function', 'A|e|i|o|u', 'X', 1, 2); regexp_replace ----------------------- A PXstgreSQL function (1 row) -- ORACLE> SELECT REGEXP_REPLACE ('A PostgreSQL function', 'a|e|i|o|u', 'X', 1, 0, 'i') FROM DUAL; -> X PXstgrXSQL fXnctXXn SELECT oracle.REGEXP_REPLACE ('A PostgreSQL function', 'a|e|i|o|u', 'X', 1, 0, 'i'); regexp_replace ----------------------- X PXstgrXSQL fXnctXXn (1 row) -- ORACLE> SELECT REGEXP_REPLACE ('A PostgreSQL function', 'a|e|i|o|u', 'X', 1, 1, 'i') FROM DUAL; -> X PostgreSQL function SELECT oracle.REGEXP_REPLACE ('A PostgreSQL function', 'a|e|i|o|u', 'X', 1, 1, 'i'); regexp_replace ----------------------- X PostgreSQL function (1 row) -- ORACLE> SELECT REGEXP_REPLACE ('A PostgreSQL function', 'a|e|i|o|u', 'X', 1, 2, 'i') FROM DUAL; -> A PXstgreSQL function SELECT oracle.REGEXP_REPLACE ('A PostgreSQL function', 'a|e|i|o|u', 'X', 1, 2, 'i'); regexp_replace ----------------------- A PXstgreSQL function (1 row) -- ORACLE> SELECT REGEXP_REPLACE ('A PostgreSQL function', 'a|e|i|o|u', 'X', 1, 3, 'i') FROM DUAL; -> A PostgrXSQL function SELECT oracle.REGEXP_REPLACE ('A PostgreSQL function', 'a|e|i|o|u', 'X', 1, 3, 'i'); regexp_replace ----------------------- A PostgrXSQL function (1 row) -- ORACLE> SELECT REGEXP_REPLACE ('A PostgreSQL function', 'a|e|i|o|u', 'X', 1, 9, 'i') FROM DUAL; -> A PostgreSQL function SELECT oracle.REGEXP_REPLACE ('A PostgreSQL function', 'a|e|i|o|u', 'X', 1, 9, 'i'); regexp_replace ----------------------- A PostgreSQL function (1 row) -- ORACLE> SELECT REGEXP_REPLACE ('A PostgreSQL function', 'A|e|i|o|u', 'X', 1, 9) FROM DUAL; -> A PostgreSQL function SELECT oracle.REGEXP_REPLACE ('A PostgreSQL function', 'A|e|i|o|u', 'X', 1, 9); regexp_replace ----------------------- A PostgreSQL function (1 row) -- ORACLE> SELECT REGEXP_REPLACE ('A PostgreSQL function', 'a|e|i|o|u', 'X', -1, 0, 'i') FROM DUAL; -> ORA-01428 SELECT oracle.REGEXP_REPLACE ('A PostgreSQL function', 'a|e|i|o|u', 'X', -1, 0, 'i'); ERROR: argument 'position' must be a number greater than 0 -- ORACLE> SELECT REGEXP_REPLACE ('A PostgreSQL function', 'a|e|i|o|u', 'X', 1, -1, 'i') FROM DUAL; -> ORA-01428 SELECT oracle.REGEXP_REPLACE ('A PostgreSQL function', 'a|e|i|o|u', 'X', 1, -1, 'i'); ERROR: argument 'occurrence' must be a positive number -- ORACLE> SELECT REGEXP_REPLACE ('A PostgreSQL function', 'a|e|i|o|u', 'X', 1, 1, 'g') FROM DUAL; -> ORA-01760 SELECT oracle.REGEXP_REPLACE ('A PostgreSQL function', 'a|e|i|o|u', 'X', 1, 1, 'g'); ERROR: modifier 'g' is not supported by this function -- -- Test NULL input in the regexp_* functions that must returned NULL except for the modifier -- or regexp flag. There is an exception with regexp_replace(), if the pattern is null (second -- parameter) the original string is returned. We don't test functions witht the STRICT attribute -- SELECT oracle.REGEXP_LIKE(NULL, '\d+', 'i'); regexp_like ------------- (1 row) SELECT oracle.REGEXP_LIKE('1234', NULL, 'i'); regexp_like ------------- (1 row) SELECT oracle.REGEXP_LIKE('1234', '\d+', NULL); regexp_like ------------- t (1 row) SELECT oracle.REGEXP_LIKE('1234', '\d+', ''); regexp_like ------------- t (1 row) SELECT oracle.REGEXP_COUNT('1234', '\d', NULL) ; regexp_count -------------- (1 row) SELECT oracle.REGEXP_COUNT('1234', '\d', 1, NULL) ; regexp_count -------------- 4 (1 row) SELECT oracle.REGEXP_COUNT('1234', '\d', 1, '') ; regexp_count -------------- 4 (1 row) SELECT oracle.REGEXP_COUNT('1234', '\d', NULL, NULL) ; regexp_count -------------- (1 row) SELECT oracle.REGEXP_COUNT(NULL, '4', 1, 'i'); regexp_count -------------- (1 row) SELECT oracle.REGEXP_INSTR('1234', '4', NULL); regexp_instr -------------- (1 row) SELECT oracle.REGEXP_INSTR('1234', '4', 1, NULL); regexp_instr -------------- (1 row) SELECT oracle.REGEXP_INSTR('1234', '4', 1, 1, NULL); regexp_instr -------------- (1 row) SELECT oracle.REGEXP_INSTR('1234', '4', 1, 1, 1, NULL); regexp_instr -------------- 5 (1 row) SELECT oracle.REGEXP_INSTR('1234', '4', 1, 1, 1, NULL, 0); regexp_instr -------------- 5 (1 row) SELECT oracle.REGEXP_INSTR('1234', '4', 1, 1, 0, NULL); regexp_instr -------------- 4 (1 row) SELECT oracle.REGEXP_INSTR('1234', '4', 1, 1, 0, 'i', NULL); regexp_instr -------------- (1 row) SELECT oracle.REGEXP_INSTR('1234', '4', 1, 1, 0, '', NULL); regexp_instr -------------- (1 row) SELECT oracle.REGEXP_INSTR(NULL, '4', 1, 1, 0, 'i', 2); regexp_instr -------------- (1 row) SELECT oracle.REGEXP_INSTR(NULL, '4', 1, 1, 0, 'i', 2); regexp_instr -------------- (1 row) SELECT oracle.REGEXP_SUBSTR('1234', '1(.*)', null); regexp_substr --------------- (1 row) SELECT oracle.REGEXP_SUBSTR('1234', '234', 1, null); regexp_substr --------------- (1 row) SELECT oracle.REGEXP_SUBSTR('1234', '234', 1, 1, null); regexp_substr --------------- 234 (1 row) SELECT oracle.REGEXP_SUBSTR('1234', '234', 1, 1, ''); regexp_substr --------------- 234 (1 row) SELECT oracle.REGEXP_SUBSTR('1234', '234', 1, 1, 'i', null); regexp_substr --------------- (1 row) -- test for capture group SELECT oracle.REGEXP_SUBSTR('1234', '2(3)(4)', 1, 1, 'i', 1); regexp_substr --------------- 3 (1 row) SELECT oracle.REGEXP_SUBSTR('1234', '2(3)(4)', 1, 1, 'i', 2); regexp_substr --------------- 4 (1 row) SELECT oracle.REGEXP_SUBSTR('1234', '2(3)(4)', 1, 1, 'i', 0); regexp_substr --------------- 234 (1 row) -- ORACLE> SELECT REGEXP_REPLACE(null, '\d', 'a') FROM DUAL; -> NULL SELECT oracle.REGEXP_REPLACE(null, '\d', 'a'); regexp_replace ---------------- (1 row) -- ORACLE> SELECT REGEXP_REPLACE('1234', null, 'a') FROM DUAL; -> 1234 SELECT oracle.REGEXP_REPLACE('1234', null, 'a'); regexp_replace ---------------- 1234 (1 row) -- ORACLE> SELECT REGEXP_REPLACE('1234', null, null) FROM DUAL; -> 1234 SELECT oracle.REGEXP_REPLACE('1234', null, null); regexp_replace ---------------- 1234 (1 row) -- ORACLE> SELECT REGEXP_REPLACE('1234', '\d', null) FROM DUAL; -> NULL SELECT oracle.REGEXP_REPLACE('1234', '\d', null); regexp_replace ---------------- (1 row) -- ORACLE> SELECT REGEXP_REPLACE('1234', '\d', 'a', null) FROM DUAL; -> NULL SELECT oracle.REGEXP_REPLACE('1234', '\d', 'a', null); regexp_replace ---------------- (1 row) -- ORACLE> SELECT REGEXP_REPLACE('1234', null, 'a', 2) FROM DUAL; -> 1234 SELECT oracle.REGEXP_REPLACE('1234', null, 'a', 2); regexp_replace ---------------- 1234 (1 row) -- ORACLE> SELECT REGEXP_REPLACE('1234', null, 'a', null) FROM DUAL; -> NULL SELECT oracle.REGEXP_REPLACE('1234', null, 'a', null); regexp_replace ---------------- (1 row) -- ORACLE> SELECT REGEXP_REPLACE('1234', null, 'a', 1) FROM DUAL; -> 1234 SELECT oracle.REGEXP_REPLACE('1234', null, 'a', 1); regexp_replace ---------------- 1234 (1 row) -- ORACLE> SELECT REGEXP_REPLACE('1234', null, 'a', 1, null) FROM DUAL; -> NULL SELECT oracle.REGEXP_REPLACE('1234', null, 'a', 1, null); regexp_replace ---------------- (1 row) -- ORACLE> SELECT REGEXP_REPLACE('1234', '\d', 'a', 1, null) FROM DUAL; -> NULL SELECT oracle.REGEXP_REPLACE('1234', '\d', 'a', 1, null); regexp_replace ---------------- (1 row) -- ORACLE> SELECT REGEXP_REPLACE('1234', '\d', 'a', 1, 1, null) FROM DUAL; -> a234 SELECT oracle.REGEXP_REPLACE('1234', '\d', 'a', 1, 1, null); regexp_replace ---------------- a234 (1 row) -- ORACLE> SELECT REGEXP_REPLACE('1234', '\d', 'a', 1, NULL, 'i') FROM DUAL; -> NULL SELECT oracle.REGEXP_REPLACE('1234', '\d', 'a', 1, NULL, 'i'); regexp_replace ---------------- (1 row) -- ORACLE> SELECT REGEXP_REPLACE('1234', null, 'a', 1, 1, 'i') FROM DUAL; -> 1234 SELECT oracle.REGEXP_REPLACE('1234', null, 'a', 1, 1, 'i'); regexp_replace ---------------- 1234 (1 row) orafce-VERSION_4_14_4/expected/varchar2.out000066400000000000000000000055521501757153000204670ustar00rootroot00000000000000\set VERBOSITY terse SET client_encoding = utf8; SET search_path TO public, oracle; -- -- 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_4_14_4/file.c000066400000000000000000000730401501757153000155050ustar00rootroot00000000000000/* * Attention - this functionality doesn't work when Orace is not linked with * correct runtime library. The combination "vcruntime140.dll" is working for * PostgreSQL 12 (vcruntime140d.dll doesn't work). Probably this runtime should * be same like Postgres server runtime (what is used can be detected by * dependency walker). Without correct linking the server crash when IO related * functionality is used. */ #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/acl.h" #include "utils/builtins.h" #include "utils/memutils.h" #ifdef WIN32 #include "utils/pg_locale.h" #endif #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); static int orafce_umask = 077; char *orafce_umask_str = NULL; static Oid orafce_set_umask_roleid = InvalidOid; void orafce_umask_assign_hook(const char *newvalue, void *extra) { orafce_umask = *((int *) extra); } bool orafce_umask_check_hook(char **newval, void **extra, GucSource source) { int digits = 0; char *ptr = *newval; int *myextra; if (orafce_initialized && IsNormalProcessingMode() && IsTransactionState()) { if (!superuser()) { if (!OidIsValid(orafce_set_umask_roleid)) orafce_set_umask_roleid = get_role_oid("orafce_set_umask", false); if (!has_privs_of_role(GetUserId(), orafce_set_umask_roleid)) { GUC_check_errcode(ERRCODE_INSUFFICIENT_PRIVILEGE); GUC_check_errmsg("permission denied to set \"orafce.umask\""); GUC_check_errdetail("Only roles with privileges of the \"orafce_set_umask\" can set \"orafce.umask\"."); return false; } } } while (*ptr) { if (*ptr < '0' || *ptr > '7') { GUC_check_errdetail("invalid octal digit"); return false; } if (digits > 3) { GUC_check_errdetail("number is too big (only four digits are allowed"); return false; } ptr++; digits++; } #if PG_VERSION_NUM >= 160000 myextra = (int *) guc_malloc(LOG, sizeof(int)); #else myextra = (int *) malloc(sizeof(int)); #endif if (!myextra) return false; *myextra = (int) strtol(*newval, NULL, 8); *extra = (void *) myextra; return true; } /* * 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, size_t *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); } } /* * On WIN32 platform multibyte chars are not supported by * fopen function. Instead we can use _wfopen functin. The * arguments are of wchar strings, and should to use UTF16 * charset. Conversion from server encoding to wide strings * is provided by function char2wchar (tested only for UTF8) */ #ifdef WIN32 static wchar_t * to_wchar(const char *str) { size_t nbytes; wchar_t *buff; nbytes = strlen(str); if ((nbytes + 1) > INT_MAX / sizeof(wchar_t)) ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"))); buff = (wchar_t *) palloc((nbytes + 1) * sizeof(wchar_t)); char2wchar(buff, nbytes + 1, str, nbytes, 0); return buff; } #endif /* * FUNCTION UTL_FILE.FOPEN(location text, * filename text, * open_mode text, * max_linesize integer * [, encoding text ]) * 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; mode_t oldmask; 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. */ oldmask = umask((mode_t) orafce_umask); #ifndef WIN32 file = fopen(fullname, mode); #else if (pg_database_encoding_max_length() > 1) { wchar_t *_fullname = to_wchar(fullname); wchar_t *_mode = to_wchar(mode); file = _wfopen(_fullname, _mode); pfree(_fullname); pfree(_mode); } else file = fopen(fullname, mode); #endif umask(oldmask); 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 many files opened concurrently"), 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) { 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, size_t max_linesize, int encoding, bool *iseof) { int c; char *buffer = NULL; char *bpt; size_t csize = 0; text *result = NULL; bool eof = true; 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, size2int(csize), false); decoded = (char *) pg_do_encoding_conversion((unsigned char *) buffer, size2int(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) { size_t max_linesize = 0; /* keep compiler quiet */ int encoding = 0; /* keep compiler quiet */ FILE *f; text *result; bool iseof; 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)) { size_t len = (size_t) 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) { size_t max_linesize = 0; /* keep compiler quiet */ int encoding = 0; /* keep compiler quiet */ FILE *f; text *result; bool iseof; 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; size_t 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) { 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; 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; 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; size_t max_linesize; int encoding; size_t format_length; char *fpt; int cur_par = 0; size_t cur_len = 0; 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; 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); for (i = 0; i < MAX_SLOTS; i++) { if (slots[i].id == d) { FILE *f = slots[i].file; slots[i].file = NULL; slots[i].id = INVALID_SLOTID; if (f && fclose(f) != 0) { if (errno == EBADF) CUSTOM_EXCEPTION(INVALID_FILEHANDLE, "File is not an opened"); else STRERROR_EXCEPTION(WRITE_ERROR); } 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; for (i = 0; i < MAX_SLOTS; i++) { if (slots[i].id != INVALID_SLOTID) { FILE *f = slots[i].file; slots[i].file = NULL; slots[i].id = INVALID_SLOTID; if (f && fclose(f) != 0) { if (errno == EBADF) CUSTOM_EXCEPTION(INVALID_FILEHANDLE, "File is not an opened"); else STRERROR_EXCEPTION(WRITE_ERROR); } } } 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; 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) { Oid argtypes[] = {TEXTOID}; /* 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(); } static char * safe_named_location(text *location) { static SPIPlanPtr plan = NULL; MemoryContext old_cxt; Datum values[1]; char nulls[1] = {' '}; char *result; old_cxt = CurrentMemoryContext; values[0] = PointerGetDatum(location); if (SPI_connect() < 0) ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), errmsg("SPI_connect failed"))); if (!plan) { Oid argtypes[] = {TEXTOID}; /* Don't use LIKE not to escape '_' and '%' */ SPIPlanPtr p = SPI_prepare( "SELECT dir FROM utl_file.utl_file_dir WHERE dirname = $1", 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) { char *loc = SPI_getvalue(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1); if (loc) result = MemoryContextStrdup(old_cxt, loc); else result = NULL; } else result = NULL; SPI_finish(); MemoryContextSwitchTo(old_cxt); return result; } /* * get_safe_path - make a fullpath and check security. */ static char * get_safe_path(text *location_or_dirname, text *filename) { char *fullname; char *location; bool check_locality; NON_EMPTY_TEXT(location_or_dirname); NON_EMPTY_TEXT(filename); location = safe_named_location(location_or_dirname); if (location) { int aux_pos = size2int(strlen(location)); int aux_len = VARSIZE_ANY_EXHDR(filename); fullname = palloc(aux_pos + 1 + aux_len + 1); strcpy(fullname, location); fullname[aux_pos] = '/'; memcpy(fullname + aux_pos + 1, VARDATA(filename), aux_len); fullname[aux_pos + aux_len + 1] = '\0'; /* location is safe (ensured by dirname) */ check_locality = false; pfree(location); } else { int aux_pos = VARSIZE_ANY_EXHDR(location_or_dirname); int aux_len = VARSIZE_ANY_EXHDR(filename); fullname = palloc(aux_pos + 1 + aux_len + 1); memcpy(fullname, VARDATA(location_or_dirname), aux_pos); fullname[aux_pos] = '/'; memcpy(fullname + aux_pos + 1, VARDATA(filename), aux_len); fullname[aux_pos + aux_len + 1] = '\0'; check_locality = true; } /* check locality in canonizalized form of path */ canonicalize_path(fullname); if (check_locality) check_secure_locality(fullname); return fullname; } /* * CREATE FUNCTION utl_file.fremove( * location text, * filename text) */ Datum utl_file_fremove(PG_FUNCTION_ARGS) { char *fullname; NOT_NULL_ARG(0); NOT_NULL_ARG(1); fullname = get_safe_path(PG_GETARG_TEXT_P(0), PG_GETARG_TEXT_P(1)); #ifndef WIN32 if (unlink(fullname) != 0) IO_EXCEPTION(); #else if (pg_database_encoding_max_length() > 1) { wchar_t *_fullname = to_wchar(fullname); if (_wunlink(_fullname) != 0) IO_EXCEPTION(); pfree(_fullname); } else { if (unlink(fullname) != 0) IO_EXCEPTION(); } #endif 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; 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)); #ifndef WIN32 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(); #else if (pg_database_encoding_max_length() > 1) { wchar_t *_dstpath = to_wchar(dstpath); wchar_t *_srcpath = to_wchar(srcpath); if (!overwrite) { struct _stat _st; if (_wstat(_dstpath, &_st) == 0) CUSTOM_EXCEPTION(WRITE_ERROR, "File exists"); else if (errno != ENOENT) IO_EXCEPTION(); } /* * Originaly there was rename() function, but this cannot * to replace other existing file. */ if (!MoveFileExW(_srcpath, _dstpath, MOVEFILE_REPLACE_EXISTING)) IO_EXCEPTION(); pfree(_dstpath); pfree(_srcpath); } else { if (!overwrite) { struct stat st; if (stat(dstpath, &st) == 0) CUSTOM_EXCEPTION(WRITE_ERROR, "File exists"); else if (errno != ENOENT) IO_EXCEPTION(); } if (!MoveFileEx(srcpath, dstpath, MOVEFILE_REPLACE_EXISTING)) IO_EXCEPTION(); } #endif 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; 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))); #ifndef WIN32 srcfile = fopen(srcpath, "rt"); #else if (pg_database_encoding_max_length() > 1) { wchar_t *_srcpath = to_wchar(srcpath); wchar_t *_mode = to_wchar("rt"); srcfile = _wfopen(_srcpath, _mode); pfree(_srcpath); pfree(_mode); } else srcfile = fopen(srcpath, "rt"); #endif if (srcfile == NULL) { /* failed to open src file. */ IO_EXCEPTION(); } #ifndef WIN32 dstfile = fopen(dstpath, "wt"); #else if (pg_database_encoding_max_length() > 1) { wchar_t *_dstpath = to_wchar(dstpath); wchar_t *_mode = to_wchar("wt"); dstfile = _wfopen(_dstpath, _mode); pfree(_dstpath); pfree(_mode); } else dstfile = fopen(dstpath, "wt"); #endif if (dstfile == NULL) { /* failed to open dst file. */ fclose(srcfile); IO_EXCEPTION(); } if (copy_text_file(srcfile, dstfile, start_line, end_line)) IO_EXCEPTION(); fclose(srcfile); fclose(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; size_t len; int i; buffer = palloc(MAX_LINESIZE); errno = 0; /* skip first start_line. */ for (i = 1; i < start_line; i++) { CHECK_FOR_INTERRUPTS(); do { if (fgets(buffer, MAX_LINESIZE, 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, MAX_LINESIZE, srcfile) == NULL) return errno; len = strlen(buffer); if (fwrite(buffer, 1, len, dstfile) != len) return errno; } while(buffer[len - 1] != '\n'); } pfree(buffer); 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 }; 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)); #ifndef WIN32 if (stat(fullname, &st) == 0) { values[0] = BoolGetDatum(true); values[1] = Int64GetDatum(st.st_size); values[2] = Int32GetDatum(st.st_blksize); } else { values[0] = BoolGetDatum(false); nulls[1] = true; nulls[2] = true; } #else if (pg_database_encoding_max_length() > 1) { wchar_t *_fullname = to_wchar(fullname); struct _stat _st; if (_wstat(_fullname, &_st) == 0) { values[0] = BoolGetDatum(true); values[1] = Int64GetDatum(_st.st_size); values[2] = 512; /* NTFS block size */ } else { values[0] = BoolGetDatum(false); nulls[1] = true; nulls[2] = true; } pfree(_fullname); } else if (stat(fullname, &st) == 0) { values[0] = BoolGetDatum(true); values[1] = Int64GetDatum(st.st_size); values[2] = 512; /* NTFS block size */ } else { values[0] = BoolGetDatum(false); nulls[1] = true; nulls[2] = true; } #endif 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 PG_RETURN_TEXT_P(cstring_to_text(tmpdir)); } orafce-VERSION_4_14_4/install_bindist.py000066400000000000000000000003551501757153000201550ustar00rootroot00000000000000import os import sys import shutil os.makedirs(sys.argv[2], exist_ok=True) shutil.copy(sys.argv[3], os.path.join(sys.argv[2], sys.argv[4])) for f in sys.argv[5:]: shutil.copy(os.path.join(sys.argv[1], f), os.path.join(sys.argv[2], f))orafce-VERSION_4_14_4/magic.c000066400000000000000000000001301501757153000156340ustar00rootroot00000000000000#include "postgres.h" #include "fmgr.h" #ifdef PG_MODULE_MAGIC PG_MODULE_MAGIC; #endif orafce-VERSION_4_14_4/math.c000066400000000000000000000072101501757153000155130ustar00rootroot00000000000000#include "postgres.h" #include #include "funcapi.h" #include "fmgr.h" #include "utils/numeric.h" #include "utils/builtins.h" #include "orafce.h" #include "builtins.h" PG_FUNCTION_INFO_V1(orafce_reminder_smallint); PG_FUNCTION_INFO_V1(orafce_reminder_int); PG_FUNCTION_INFO_V1(orafce_reminder_bigint); PG_FUNCTION_INFO_V1(orafce_reminder_numeric); /* * CREATE OR REPLACE FUNCTION oracle.remainder(smallint, smallint) * RETURNS smallint */ Datum orafce_reminder_smallint(PG_FUNCTION_ARGS) { int16 arg1 = PG_GETARG_INT16(0); int16 arg2 = PG_GETARG_INT16(1); if (arg2 == 0) { ereport(ERROR, (errcode(ERRCODE_DIVISION_BY_ZERO), errmsg("division by zero"))); } if (arg2 == -1) PG_RETURN_INT16(0); PG_RETURN_INT16(arg1 - ((int16) round(((double) arg1) / ((double) arg2)) * arg2)); } /* * CREATE OR REPLACE FUNCTION oracle.remainder(int, int) * RETURNS int */ Datum orafce_reminder_int(PG_FUNCTION_ARGS) { int32 arg1 = PG_GETARG_INT32(0); int32 arg2 = PG_GETARG_INT32(1); if (arg2 == 0) { ereport(ERROR, (errcode(ERRCODE_DIVISION_BY_ZERO), errmsg("division by zero"))); } if (arg2 == -1) PG_RETURN_INT32(0); PG_RETURN_INT32(arg1 - ((int32) round(((double) arg1) / ((double) arg2)) * arg2)); } /* * CREATE OR REPLACE FUNCTION oracle.remainder(bigint, bigint) * RETURNS bigint */ Datum orafce_reminder_bigint(PG_FUNCTION_ARGS) { int64 arg1 = PG_GETARG_INT64(0); int64 arg2 = PG_GETARG_INT64(1); if (arg2 == 0) { ereport(ERROR, (errcode(ERRCODE_DIVISION_BY_ZERO), errmsg("division by zero"))); } if (arg2 == -1) PG_RETURN_INT32(0); PG_RETURN_INT64(arg1 - ((int64) round(((long double) arg1) / ((long double) arg2)) * arg2)); } /* * This will handle NaN and Infinity cases */ static Numeric duplicate_numeric(Numeric num) { Numeric res; res = (Numeric) palloc(VARSIZE(num)); memcpy(res, num, VARSIZE(num)); return res; } static Numeric get_numeric_in(const char *str) { return DatumGetNumeric( DirectFunctionCall3(numeric_in, CStringGetDatum(str), ObjectIdGetDatum(0), Int32GetDatum(-1))); } static bool orafce_numeric_is_inf(Numeric num) { #if PG_VERSION_NUM >= 140000 return numeric_is_inf(num); #else /* older releases doesn't support +-Infinitity in numeric type */ return false; #endif } /* * CREATE OR REPLACE FUNCTION oracle.remainder(numeric, numeric) * RETURNS numeric */ Datum orafce_reminder_numeric(PG_FUNCTION_ARGS) { Numeric num1 = PG_GETARG_NUMERIC(0); Numeric num2 = PG_GETARG_NUMERIC(1); Numeric result; float8 val2; if (numeric_is_nan(num1)) duplicate_numeric(num1); if (numeric_is_nan(num2)) duplicate_numeric(num2); val2 = DatumGetFloat8(DirectFunctionCall1(numeric_float8, NumericGetDatum(num2))); if (val2 == 0) ereport(ERROR, (errcode(ERRCODE_DIVISION_BY_ZERO), errmsg("division by zero"))); if (orafce_numeric_is_inf(num1)) PG_RETURN_NUMERIC(get_numeric_in("NaN")); if (orafce_numeric_is_inf(num2)) duplicate_numeric(num1); #if PG_VERSION_NUM >= 150000 result = numeric_sub_opt_error( num1, numeric_mul_opt_error( DatumGetNumeric( DirectFunctionCall2( numeric_round, NumericGetDatum( numeric_div_opt_error(num1, num2,NULL)), Int32GetDatum(0))), num2, NULL), NULL); #else result = DatumGetNumeric( DirectFunctionCall2(numeric_sub, NumericGetDatum(num1), DirectFunctionCall2(numeric_mul, DirectFunctionCall2(numeric_round, DirectFunctionCall2(numeric_div, NumericGetDatum(num1), NumericGetDatum(num2)), Int32GetDatum(0)), NumericGetDatum(num2)))); #endif PG_RETURN_NUMERIC(result); } orafce-VERSION_4_14_4/meson.build000066400000000000000000000120221501757153000165550ustar00rootroot00000000000000project('orafce', ['c'], version: '4.15.0') pg_config = find_program('pg_config') bindir = run_command(pg_config, '--bindir', check: true).stdout().strip() includedir_server = run_command(pg_config, '--includedir-server', check: true).stdout().strip() includedir = run_command(pg_config, '--includedir', check: true).stdout().strip() pkglibdir = run_command(pg_config, '--pkglibdir', check: true).stdout().strip() sharedir = run_command(pg_config, '--sharedir', check: true).stdout().strip() libdir = run_command(pg_config, '--libdir', check: true).stdout().strip() versionstring = run_command(pg_config, '--version', check: true).stdout().strip() pg_version = versionstring.split(' ')[1] if pg_version.endswith('devel') pg_version_arr = [pg_version.split('devel')[0], '0'] elif pg_version.contains('beta') pg_version_arr = [pg_version.split('beta')[0], '0'] elif pg_version.contains('rc') pg_version_arr = [pg_version.split('rc')[0], '0'] else pg_version_arr = pg_version.split('.') endif pg_version_major = pg_version_arr[0].to_int() pg_version_minor = pg_version_arr[1].to_int() pg_version_num = (pg_version_major * 10000) + pg_version_minor module_version_minor = meson.project_version() module_version_arr = module_version_minor.split('.') module_version = module_version_arr[0] + '.' + module_version_arr[1] module_name = meson.project_name() sources = files( 'aggregate.c', 'alert.c', 'assert.c', 'convert.c', 'datefce.c', 'dbms_sql.c', 'file.c', 'charlen.c', 'charpad.c', 'magic.c', 'math.c', 'nvarchar2.c', 'orafce.c', 'others.c', 'parse_keyword.c', 'pipe.c', 'plunit.c', 'plvdate.c', 'plvlex.c', 'plvstr.c', 'plvsubst.c', 'putline.c', 'random.c', 'regexp.c', 'replace_empty_string.c', 'shmmc.c', 'sqlparse.c', 'utility.c', 'varchar2.c', ) data = [ module_name + '.control', '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', 'orafce--3.9--3.10.sql', 'orafce--3.10--3.11.sql', 'orafce--3.11--3.12.sql', 'orafce--3.12--3.13.sql', 'orafce--3.13--3.14.sql', 'orafce--3.14--3.15.sql', 'orafce--3.15--3.16.sql', 'orafce--3.16--3.17.sql', 'orafce--3.17--3.18.sql', 'orafce--3.18--3.19.sql', 'orafce--3.19--3.20.sql', 'orafce--3.20--3.21.sql', 'orafce--3.21--3.22.sql', 'orafce--3.22--3.23.sql', 'orafce--3.23--3.24.sql', 'orafce--3.24--3.25.sql', 'orafce--3.25--4.0.sql', 'orafce--4.0--4.1.sql', 'orafce--4.1--4.2.sql', 'orafce--4.2--4.3.sql', 'orafce--4.3--4.4.sql', 'orafce--4.4--4.5.sql', 'orafce--4.5--4.6.sql', 'orafce--4.6--4.7.sql', 'orafce--4.7--4.8.sql', 'orafce--4.8--4.9.sql', 'orafce--4.9--4.10.sql', 'orafce--4.10--4.11.sql', 'orafce--4.11--4.12.sql', 'orafce--4.12--4.13.sql', 'orafce--4.13--4.14.sql', 'orafce--4.14--4.15.sql', module_name + '--' + module_version + '.sql' ] tests = [ 'init', 'orafce', 'orafce2', 'dbms_output', 'dbms_utility', 'files', 'varchar2', 'nvarchar2', 'aggregates', 'nlssort', 'dbms_random', 'regexp_func', 'dbms_sql', ] compilerName = meson.get_compiler('c').get_id() if meson.get_compiler('c').get_id() == 'msvc' incdir = [includedir_server / 'port/win32_msvc', includedir_server / 'port/win32', includedir_server, includedir] postgres_lib = meson.get_compiler('c').find_library( 'postgres', dirs: libdir, static: true, required: true ) else incdir = [ includedir_server ] postgres_lib = [] endif module_lib = shared_module( module_name, sources, include_directories: incdir, install: true, install_dir: pkglibdir, name_prefix: '', dependencies: postgres_lib, ) install_data(data, install_dir: sharedir / 'extension') fs = import('fs') bindistdir = fs.expanduser('~' / module_name / module_name + '-' + '-'.join( [ module_version_minor, target_machine.cpu(), target_machine.system() ] )) lib_name = fs.name(module_lib.full_path()) lib_suffix = lib_name.split('.')[1] python_exe = find_program('python3', 'python') custom_target('bindist', depends: module_lib, input: module_lib, output: 'bindist', command: [ python_exe, meson.current_source_dir() / 'install_bindist.py', meson.current_source_dir(), bindistdir, module_lib.full_path(), fs.stem(lib_name) + '_' + pg_version_major.to_string() + '.' + lib_suffix, data ], install: false, build_by_default: false) pg_regress = find_program( 'pg_regress', dirs: [pkglibdir / 'pgxs/src/test/regress'] ) test('regress', pg_regress, args: ['--bindir', bindir, '--inputdir', meson.current_source_dir(), '--encoding', 'utf8', '--schedule', meson.current_source_dir() / 'parallel_schedule', ] + tests, ) orafce-VERSION_4_14_4/msvc/000077500000000000000000000000001501757153000153665ustar00rootroot00000000000000orafce-VERSION_4_14_4/msvc/orafce.2010.sln000066400000000000000000000041671501757153000177340ustar00rootroot00000000000000 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_4_14_4/msvc/orafce.2010.vcxproj000066400000000000000000000777531501757153000206460ustar00rootroot00000000000000 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_4_14_4/msvc/orafce.2010.vcxproj.filters000066400000000000000000000107331501757153000222760ustar00rootroot00000000000000 {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_4_14_4/nvarchar2.c000066400000000000000000000115121501757153000164500ustar00rootroot00000000000000/*---------------------------------------------------------------------------- * * nvarchar2.c * NVARCHAR2 type for PostgreSQL. * *---------------------------------------------------------------------------- */ #include "postgres.h" #include "access/hash.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, size2int(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, size2int(maxmblen))); } /* * nvarchar2typmodin -- type modifier input function * * just use varchartypmodin() */ /* * nvarchar2typmodout -- type modifier output function * * just use varchartypmodout() */ orafce-VERSION_4_14_4/orafce--3.10--3.11.sql000066400000000000000000000004121501757153000174640ustar00rootroot00000000000000ALTER FUNCTION utl_file.fopen(text, text, text, integer, name) SECURITY INVOKER; ALTER FUNCTION utl_file.fopen(text, text, text, integer) SECURITY INVOKER; GRANT SELECT ON TABLE utl_file.utl_file_dir TO PUBLIC; GRANT EXECUTE ON FUNCTION utl_file.tmpdir() TO PUBLIC; orafce-VERSION_4_14_4/orafce--3.11--3.12.sql000066400000000000000000000004271501757153000174740ustar00rootroot00000000000000CREATE OR REPLACE FUNCTION oracle.replace_empty_strings() RETURNS TRIGGER AS 'MODULE_PATHNAME','orafce_replace_empty_strings' LANGUAGE 'c'; CREATE OR REPLACE FUNCTION oracle.replace_null_strings() RETURNS TRIGGER AS 'MODULE_PATHNAME','orafce_replace_null_strings' LANGUAGE 'c'; orafce-VERSION_4_14_4/orafce--3.12--3.13.sql000066400000000000000000000000001501757153000174610ustar00rootroot00000000000000orafce-VERSION_4_14_4/orafce--3.13--3.14.sql000066400000000000000000000024631501757153000175020ustar00rootroot00000000000000CREATE OR REPLACE FUNCTION oracle.unistr(text) RETURNS text AS 'MODULE_PATHNAME','orafce_unistr' LANGUAGE 'c'; 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; INSERT INTO pg_depend (classid, objid, objsubid, refclassid, refobjid, refobjsubid, deptype) VALUES('pg_proc'::regclass::oid, 'varchar2'::regproc::oid, 0, 'pg_proc'::regclass::oid, 'varchar2_transform'::regproc::oid, 0, 'n'); END $$; 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; INSERT INTO pg_depend (classid, objid, objsubid, refclassid, refobjid, refobjsubid, deptype) VALUES('pg_proc'::regclass::oid, 'nvarchar2'::regproc::oid, 0, 'pg_proc'::regclass::oid, 'nvarchar2_transform'::regproc::oid, 0, 'n'); END $$; orafce-VERSION_4_14_4/orafce--3.14--3.15.sql000066400000000000000000000477151501757153000175150ustar00rootroot00000000000000-- Translate Oracle regexp modifier into PostgreSQl ones -- Append the global modifier if $2 is true. Used internally -- by regexp_*() functions bellow. CREATE OR REPLACE FUNCTION oracle.translate_oracle_modifiers(text, bool) RETURNS text AS $$ DECLARE modifiers text; BEGIN -- Check that we don't have modifier not supported by Oracle IF $1 ~ '[^icnsmx]' THEN -- Modifier 's' is not supported by Oracle but it is a synonym -- of 'n', we translate 'n' into 's' bellow. It is safe to allow it. RAISE EXCEPTION 'argument ''flags'' has unsupported modifier(s).'; END IF; -- Oracle 'n' modifier correspond to 's' POSIX modifier -- Oracle 'm' modifier correspond to 'n' POSIX modifier modifiers := translate($1, 'nm', 'sn'); IF $2 THEN modifiers := modifiers || 'g'; END IF; RETURN modifiers; END; $$ LANGUAGE plpgsql; -- REGEXP_LIKE( string text, pattern text) -> boolean CREATE OR REPLACE FUNCTION oracle.regexp_like(text, text) RETURNS boolean AS $$ -- Oracle default behavior is newline-sensitive, -- PostgreSQL not, so force 'p' modifier to affect -- newline-sensitivity but not ^ and $ search. SELECT CASE WHEN (count(*) > 0) THEN true ELSE false END FROM regexp_matches($1, $2, 'p'); $$ LANGUAGE 'sql'; -- REGEXP_LIKE( string text, pattern text, flags text ) -> boolean CREATE OR REPLACE FUNCTION oracle.regexp_like(text, text, text) RETURNS boolean AS $$ DECLARE modifiers text; BEGIN modifiers := oracle.translate_oracle_modifiers($3, false); IF (regexp_matches($1, $2, modifiers))[1] IS NOT NULL THEN RETURN true; END IF; RETURN false; END; $$ LANGUAGE plpgsql; -- REGEXP_COUNT( string text, pattern text ) -> integer CREATE OR REPLACE FUNCTION oracle.regexp_count(text, text) RETURNS integer AS $$ -- Oracle default behavior is newline-sensitive, -- PostgreSQL not, so force 'p' modifier to affect -- newline-sensitivity but not ^ and $ search. SELECT count(*)::integer FROM regexp_matches($1, $2, 'pg'); $$ LANGUAGE 'sql'; -- REGEXP_COUNT( string text, pattern text, position int ) -> integer CREATE OR REPLACE FUNCTION oracle.regexp_count(text, text, integer) RETURNS integer AS $$ DECLARE v_cnt integer; BEGIN -- Check numeric arguments IF $3 < 1 THEN RAISE EXCEPTION 'argument ''position'' must be a number greater than 0'; END IF; -- Oracle default behavior is newline-sensitive, -- PostgreSQL not, so force 'p' modifier to affect -- newline-sensitivity but not ^ and $ search. v_cnt := (SELECT count(*)::integer FROM regexp_matches(substr($1, $3), $2, 'pg')); RETURN v_cnt; END; $$ LANGUAGE plpgsql; -- REGEXP_COUNT( string text, pattern text, position int, flags text ) -> integer CREATE OR REPLACE FUNCTION oracle.regexp_count(text, text, integer, text) RETURNS integer AS $$ DECLARE modifiers text; v_cnt integer; BEGIN -- Check numeric arguments IF $3 < 1 THEN RAISE EXCEPTION 'argument ''position'' must be a number greater than 0'; END IF; modifiers := oracle.translate_oracle_modifiers($4, true); v_cnt := (SELECT count(*)::integer FROM regexp_matches(substr($1, $3), $2, modifiers)); RETURN v_cnt; END; $$ LANGUAGE plpgsql; -- REGEXP_INSTR( string text, pattern text ) -> integer CREATE OR REPLACE FUNCTION oracle.regexp_instr(text, text) RETURNS integer AS $$ DECLARE v_pos integer; v_pattern text; BEGIN -- Without subexpression specified, assume 0 which mean that the first -- position for the substring matching the whole pattern is returned. -- We need to enclose the pattern between parentheses. v_pattern := '(' || $2 || ')'; -- Oracle default behavior is newline-sensitive, -- PostgreSQL not, so force 'p' modifier to affect -- newline-sensitivity but not ^ and $ search. v_pos := (SELECT position((SELECT (regexp_matches($1, v_pattern, 'pg'))[1] OFFSET 0 LIMIT 1) IN $1)); -- position() returns NULL when not found, we need to return 0 instead IF v_pos IS NOT NULL THEN RETURN v_pos; END IF; RETURN 0; END; $$ LANGUAGE plpgsql; -- REGEXP_INSTR( string text, pattern text, position int ) -> integer CREATE OR REPLACE FUNCTION oracle.regexp_instr(text, text, integer) RETURNS integer AS $$ DECLARE v_pos integer; v_pattern text; BEGIN IF $3 < 1 THEN RAISE EXCEPTION 'argument ''position'' must be a number greater than 0'; END IF; -- Without subexpression specified, assume 0 which mean that the first -- position for the substring matching the whole pattern is returned. -- We need to enclose the pattern between parentheses. v_pattern := '(' || $2 || ')'; -- Oracle default behavior is newline-sensitive, -- PostgreSQL not, so force 'p' modifier to affect -- newline-sensitivity but not ^ and $ search. v_pos := (SELECT position((SELECT (regexp_matches(substr($1, $3), v_pattern, 'pg'))[1] OFFSET 0 LIMIT 1) IN $1)); -- position() returns NULL when not found, we need to return 0 instead IF v_pos IS NOT NULL THEN RETURN v_pos; END IF; RETURN 0; END; $$ LANGUAGE plpgsql; -- REGEXP_INSTR( string text, pattern text, position int, occurence int ) -> integer CREATE OR REPLACE FUNCTION oracle.regexp_instr(text, text, integer, integer) RETURNS integer AS $$ DECLARE v_pos integer; v_pattern text; BEGIN IF $3 < 1 THEN RAISE EXCEPTION 'argument ''position'' must be a number greater than 0'; END IF; IF $4 < 1 THEN RAISE EXCEPTION 'argument ''occurence'' must be a number greater than 0'; END IF; -- Without subexpression specified, assume 0 which mean that the first -- position for the substring matching the whole pattern is returned. -- We need to enclose the pattern between parentheses. v_pattern := '(' || $2 || ')'; -- Oracle default behavior is newline-sensitive, -- PostgreSQL not, so force 'p' modifier to affect -- newline-sensitivity but not ^ and $ search. v_pos := (SELECT position((SELECT (regexp_matches(substr($1, $3), v_pattern, 'pg'))[1] OFFSET $4 - 1 LIMIT 1) IN $1)); -- position() returns NULL when not found, we need to return 0 instead IF v_pos IS NOT NULL THEN RETURN v_pos; END IF; RETURN 0; END; $$ LANGUAGE plpgsql; -- REGEXP_INSTR( string text, pattern text, position int, occurence int, return_opt int ) -> integer CREATE OR REPLACE FUNCTION oracle.regexp_instr(text, text, integer, integer, integer) RETURNS integer AS $$ DECLARE v_pos integer; v_len integer; v_pattern text; BEGIN IF $3 < 1 THEN RAISE EXCEPTION 'argument ''position'' must be a number greater than 0'; END IF; IF $4 < 1 THEN RAISE EXCEPTION 'argument ''occurence'' must be a number greater than 0'; END IF; IF $5 != 0 AND $5 != 1 THEN RAISE EXCEPTION 'argument ''return_opt'' must be 0 or 1'; END IF; -- Without subexpression specified, assume 0 which mean that the first -- Without subexpression specified, assume 0 which mean that the first -- position for the substring matching the whole pattern is returned. -- We need to enclose the pattern between parentheses. v_pattern := '(' || $2 || ')'; -- Oracle default behavior is newline-sensitive, -- PostgreSQL not, so force 'p' modifier to affect -- newline-sensitivity but not ^ and $ search. v_pos := (SELECT position((SELECT (regexp_matches(substr($1, $3), v_pattern, 'pg'))[1] OFFSET $4-1 LIMIT 1) IN $1)); -- position() returns NULL when not found, we need to return 0 instead IF v_pos IS NOT NULL THEN IF $5 = 1 THEN v_len := (SELECT length((SELECT (regexp_matches(substr($1, $3), v_pattern, 'pg'))[1] OFFSET $4 - 1 LIMIT 1))); v_pos := v_pos + v_len; END IF; RETURN v_pos; END IF; RETURN 0; END; $$ LANGUAGE plpgsql; -- REGEXP_INSTR( string text, pattern text, position int, occurence int, return_opt int, flags text ) -> integer CREATE OR REPLACE FUNCTION oracle.regexp_instr(text, text, integer, integer, integer, text) RETURNS integer AS $$ DECLARE v_pos integer; v_len integer; modifiers text; v_pattern text; BEGIN -- Check numeric arguments IF $3 < 1 THEN RAISE EXCEPTION 'argument ''position'' must be a number greater than 0'; END IF; IF $4 < 1 THEN RAISE EXCEPTION 'argument ''occurence'' must be a number greater than 0'; END IF; IF $5 != 0 AND $5 != 1 THEN RAISE EXCEPTION 'argument ''return_opt'' must be 0 or 1'; END IF; modifiers := oracle.translate_oracle_modifiers($6, true); -- Without subexpression specified, assume 0 which mean that the first -- position for the substring matching the whole pattern is returned. -- We need to enclose the pattern between parentheses. v_pattern := '(' || $2 || ')'; v_pos := (SELECT position((SELECT (regexp_matches(substr($1, $3), v_pattern, modifiers))[1] OFFSET $4 - 1 LIMIT 1) IN $1)); -- position() returns NULL when not found, we need to return 0 instead IF v_pos IS NOT NULL THEN IF $5 = 1 THEN v_len := (SELECT length((SELECT (regexp_matches(substr($1, $3), v_pattern, modifiers))[1] OFFSET $4-1 LIMIT 1))); v_pos := v_pos + v_len; END IF; RETURN v_pos; END IF; RETURN 0; END; $$ LANGUAGE plpgsql; -- REGEXP_INSTR( string text, pattern text, position int, occurence int, return_opt int, flags text, group int ) -> integer CREATE OR REPLACE FUNCTION oracle.regexp_instr(text, text, integer, integer, integer, text, integer) RETURNS integer AS $$ DECLARE v_pos integer := 0; v_pos_orig integer := $3; v_len integer := 0; modifiers text; occurrence integer := $4; idx integer := 1; v_curr_pos integer := 0; v_pattern text; v_subexpr integer := $7; BEGIN -- Check numeric arguments IF $3 < 1 THEN RAISE EXCEPTION 'argument ''position'' must be a number greater than 0'; END IF; IF $4 < 1 THEN RAISE EXCEPTION 'argument ''occurence'' must be a number greater than 0'; END IF; IF $7 < 0 THEN RAISE EXCEPTION 'argument ''group'' must be a positive number'; END IF; IF $5 != 0 AND $5 != 1 THEN RAISE EXCEPTION 'argument ''return_opt'' must be 0 or 1'; END IF; -- Translate Oracle regexp modifier into PostgreSQl ones modifiers := oracle.translate_oracle_modifiers($6, true); -- If subexpression value is 0 we need to enclose the pattern between parentheses. IF v_subexpr = 0 THEN v_pattern := '(' || $2 || ')'; v_subexpr := 1; ELSE v_pattern := $2; END IF; -- To get position of occurrence > 1 we need a more complex code LOOP v_curr_pos := v_curr_pos + v_len; v_pos := (SELECT position((SELECT (regexp_matches(substr($1, v_pos_orig), '('||$2||')', modifiers))[1] OFFSET 0 LIMIT 1) IN substr($1, v_pos_orig))); v_len := (SELECT length((SELECT (regexp_matches(substr($1, v_pos_orig), '('||$2||')', modifiers))[1] OFFSET 0 LIMIT 1))); EXIT WHEN v_len IS NULL; v_pos_orig := v_pos_orig + v_pos + v_len; v_curr_pos := v_curr_pos + v_pos; idx := idx + 1; EXIT WHEN idx > occurrence; END LOOP; v_pos := (SELECT position((SELECT (regexp_matches(substr($1, v_curr_pos), v_pattern, modifiers))[v_subexpr] OFFSET 0 LIMIT 1) IN substr($1, v_curr_pos))); IF v_pos IS NOT NULL THEN IF $5 = 1 THEN v_len := (SELECT length((SELECT (regexp_matches(substr($1, v_curr_pos), v_pattern, modifiers))[v_subexpr] OFFSET 0 LIMIT 1))); v_pos := v_pos + v_len; END IF; RETURN v_pos + v_curr_pos - 1; END IF; RETURN 0; END; $$ LANGUAGE plpgsql; -- REGEXP_SUBSTR( string text, pattern text ) -> text CREATE OR REPLACE FUNCTION oracle.regexp_substr(text, text) RETURNS text AS $$ DECLARE v_substr text; v_pattern text; BEGIN -- Without subexpression specified, assume 0 which mean that the first -- position for the substring matching the whole pattern is returned. -- We need to enclose the pattern between parentheses. v_pattern := '(' || $2 || ')'; -- Oracle default behavior is newline-sensitive, -- PostgreSQL not, so force 'p' modifier to affect -- newline-sensitivity but not ^ and $ search. v_substr := (SELECT (regexp_matches($1, v_pattern, 'pg'))[1] OFFSET 0 LIMIT 1); RETURN v_substr; END; $$ LANGUAGE plpgsql; -- REGEXP_SUBSTR( string text, pattern text, position int ) -> text CREATE OR REPLACE FUNCTION oracle.regexp_substr(text, text, int) RETURNS text AS $$ DECLARE v_substr text; v_pattern text; BEGIN -- Check numeric arguments IF $3 < 1 THEN RAISE EXCEPTION 'argument ''position'' must be a number greater than 0'; END IF; -- Without subexpression specified, assume 0 which mean that the first -- position for the substring matching the whole pattern is returned. -- We need to enclose the pattern between parentheses. v_pattern := '(' || $2 || ')'; -- Oracle default behavior is newline-sensitive, -- PostgreSQL not, so force 'p' modifier to affect -- newline-sensitivity but not ^ and $ search. v_substr := (SELECT (regexp_matches(substr($1, $3), v_pattern, 'pg'))[1] OFFSET 0 LIMIT 1); RETURN v_substr; END; $$ LANGUAGE plpgsql; -- REGEXP_SUBSTR( string text, pattern text, position int, occurence int ) -> text CREATE OR REPLACE FUNCTION oracle.regexp_substr(text, text, integer, integer) RETURNS text AS $$ DECLARE v_substr text; v_pattern text; BEGIN -- Check numeric arguments IF $3 < 1 THEN RAISE EXCEPTION 'argument ''position'' must be a number greater than 0'; END IF; IF $4 < 1 THEN RAISE EXCEPTION 'argument ''occurence'' must be a number greater than 0'; END IF; -- Without subexpression specified, assume 0 which mean that the first -- position for the substring matching the whole pattern is returned. -- We need to enclose the pattern between parentheses. v_pattern := '(' || $2 || ')'; -- Oracle default behavior is newline-sensitive, -- PostgreSQL not, so force 'p' modifier to affect -- newline-sensitivity but not ^ and $ search. v_substr := (SELECT (regexp_matches(substr($1, $3), v_pattern, 'pg'))[1] OFFSET $4 - 1 LIMIT 1); RETURN v_substr; END; $$ LANGUAGE plpgsql; -- REGEXP_SUBSTR( string text, pattern text, position int, occurence int, flags text ) -> text CREATE OR REPLACE FUNCTION oracle.regexp_substr(text, text, integer, integer, text) RETURNS text AS $$ DECLARE v_substr text; v_pattern text; modifiers text; BEGIN -- Check numeric arguments IF $3 < 1 THEN RAISE EXCEPTION 'argument ''position'' must be a number greater than 0'; END IF; IF $4 < 1 THEN RAISE EXCEPTION 'argument ''occurence'' must be a number greater than 0'; END IF; modifiers := oracle.translate_oracle_modifiers($5, true); -- Without subexpression specified, assume 0 which mean that the first -- position for the substring matching the whole pattern is returned. -- We need to enclose the pattern between parentheses. v_pattern := '(' || $2 || ')'; -- Oracle default behavior is newline-sensitive, -- PostgreSQL not, so force 'p' modifier to affect -- newline-sensitivity but not ^ and $ search. v_substr := (SELECT (regexp_matches(substr($1, $3), v_pattern, modifiers))[1] OFFSET $4 - 1 LIMIT 1); RETURN v_substr; END; $$ LANGUAGE plpgsql; -- REGEXP_SUBSTR( string text, pattern text, position int, occurence int, flags text, group int ) -> text CREATE OR REPLACE FUNCTION oracle.regexp_substr(text, text, integer, integer, text, int) RETURNS text AS $$ DECLARE v_substr text; v_pattern text; modifiers text; v_subexpr integer := $6; has_group integer; BEGIN -- Check numeric arguments IF $3 < 1 THEN RAISE EXCEPTION 'argument ''position'' must be a number greater than 0'; END IF; IF $4 < 1 THEN RAISE EXCEPTION 'argument ''occurence'' must be a number greater than 0'; END IF; IF v_subexpr < 0 THEN RAISE EXCEPTION 'argument ''group'' must be a positive number'; END IF; -- Check that with v_subexpr = 1 we have a capture group otherwise return NULL has_group := (SELECT count(*) FROM regexp_matches(v_pattern, '\(.*\)')); IF $6 = 1 AND has_group = 0 THEN RETURN NULL; END IF; modifiers := oracle.translate_oracle_modifiers($5, true); -- If subexpression value is 0 we need to enclose the pattern between parentheses. IF v_subexpr = 0 THEN v_pattern := '(' || $2 || ')'; v_subexpr := 1; ELSE v_pattern := $2; END IF; -- Oracle default behavior is newline-sensitive, -- PostgreSQL not, so force 'p' modifier to affect -- newline-sensitivity but not ^ and $ search. v_substr := (SELECT (regexp_matches(substr($1, $3), v_pattern, modifiers))[v_subexpr] OFFSET $4 - 1 LIMIT 1); RETURN v_substr; END; $$ LANGUAGE plpgsql; -- REGEXP_REPLACE( string text, pattern text, replace_string text ) -> text CREATE OR REPLACE FUNCTION oracle.regexp_replace(text, text, text) RETURNS text AS $$ -- Oracle default behavior is to replace all occurence -- whereas PostgreSQL only replace the first occurrence -- so we need to add 'g' modifier. SELECT pg_catalog.regexp_replace($1, $2, $3, 'g'); $$ LANGUAGE sql; -- REGEXP_REPLACE( string text, pattern text, replace_string text, position int ) -> text CREATE OR REPLACE FUNCTION oracle.regexp_replace(text, text, text, integer) RETURNS text AS $$ DECLARE v_replaced_str text; v_before text; BEGIN -- Check numeric arguments IF $4 < 1 THEN RAISE EXCEPTION 'argument ''position'' must be a number greater than 0'; END IF; v_before = substr($1, 1, $4 - 1); -- Oracle default behavior is to replace all occurence -- whereas PostgreSQL only replace the first occurrence -- so we need to add 'g' modifier. v_replaced_str := v_before || pg_catalog.regexp_replace(substr($1, $4), $2, $3, 'g'); RETURN v_replaced_str; END; $$ LANGUAGE plpgsql; -- REGEXP_REPLACE( string text, pattern text, replace_string text, position int, occurence int ) -> text CREATE OR REPLACE FUNCTION oracle.regexp_replace(text, text, text, integer, integer) RETURNS text AS $$ DECLARE v_replaced_str text; v_pos integer := $4; v_before text := ''; v_nummatch integer; BEGIN -- Check numeric arguments IF $4 < 1 THEN RAISE EXCEPTION 'argument ''position'' must be a number greater than 0'; END IF; IF $5 < 0 THEN RAISE EXCEPTION 'argument ''occurrence'' must be a positive number'; END IF; -- Check if the occurrence queried exceeds the number of occurrences IF $5 > 1 THEN v_nummatch := (SELECT count(*) FROM regexp_matches(substr($1, $4), $2, 'g')); IF $5 > v_nummatch THEN RETURN $1; END IF; -- Get the position of the occurrence we are looking for v_pos := oracle.regexp_instr($1, $2, $4, $5, 0, '', 1); IF v_pos = 0 THEN RETURN $1; END IF; END IF; -- Get the substring before this position we will need to restore it v_before := substr($1, 1, v_pos - 1); -- Replace all occurrences IF $5 = 0 THEN v_replaced_str := v_before || pg_catalog.regexp_replace(substr($1, v_pos), $2, $3, 'g'); ELSE -- Replace the first occurrence v_replaced_str := v_before || pg_catalog.regexp_replace(substr($1, v_pos), $2, $3); END IF; RETURN v_replaced_str; END; $$ LANGUAGE plpgsql; -- REGEXP_REPLACE( string text, pattern text, replace_string text, position int, occurence int, flags text ) -> text CREATE OR REPLACE FUNCTION oracle.regexp_replace(text, text, text, integer, integer, text) RETURNS text AS $$ DECLARE v_replaced_str text; v_pos integer := $4; v_nummatch integer; v_before text := ''; modifiers text := ''; BEGIN -- Check numeric arguments IF $4 < 1 THEN RAISE EXCEPTION 'argument ''position'' must be a number greater than 0'; END IF; IF $5 < 0 THEN RAISE EXCEPTION 'argument ''occurrence'' must be a positive number'; END IF; -- Set the modifiers IF $5 = 0 THEN modifiers := oracle.translate_oracle_modifiers($6, true); ELSE modifiers := oracle.translate_oracle_modifiers($6, false); END IF; -- Check if the occurrence queried exceeds the number of occurrences IF $5 > 1 THEN v_nummatch := (SELECT count(*) FROM regexp_matches(substr($1, $4), $2, $6||'g')); IF $5 > v_nummatch THEN RETURN $1; END IF; -- Get the position of the occurrence we are looking for v_pos := oracle.regexp_instr($1, $2, $4, $5, 0, $6, 1); IF v_pos = 0 THEN RETURN $1; END IF; END IF; -- Get the substring before this position we will need to restore it v_before := substr($1, 1, v_pos - 1); -- Replace occurrence(s) v_replaced_str := v_before || pg_catalog.regexp_replace(substr($1, v_pos), $2, $3, modifiers); RETURN v_replaced_str; END; $$ LANGUAGE plpgsql; orafce-VERSION_4_14_4/orafce--3.15--3.16.sql000066400000000000000000000003721501757153000175030ustar00rootroot00000000000000CREATE FUNCTION dbms_utility.get_time() RETURNS int AS 'MODULE_PATHNAME','dbms_utility_get_time' LANGUAGE C VOLATILE; COMMENT ON FUNCTION dbms_utility.get_time() IS 'Returns the number of hundredths of seconds that have elapsed since point in time'; orafce-VERSION_4_14_4/orafce--3.16--3.17.sql000066400000000000000000000525711501757153000175150ustar00rootroot00000000000000-- Translate Oracle regexp modifier into PostgreSQl ones -- Append the global modifier if $2 is true. Used internally -- by regexp_*() functions bellow. CREATE OR REPLACE FUNCTION oracle.translate_oracle_modifiers(text, bool) RETURNS text AS $$ DECLARE modifiers text := ''; BEGIN IF $1 IS NOT NULL THEN -- Check that we don't have modifier not supported by Oracle IF $1 ~ '[^icnsmx]' THEN -- Modifier 's' is not supported by Oracle but it is a synonym -- of 'n', we translate 'n' into 's' bellow. It is safe to allow it. RAISE EXCEPTION 'argument ''flags'' has unsupported modifier(s).'; END IF; -- Oracle 'n' modifier correspond to 's' POSIX modifier -- Oracle 'm' modifier correspond to 'n' POSIX modifier modifiers := translate($1, 'nm', 'sn'); END IF; IF $2 THEN modifiers := modifiers || 'g'; END IF; RETURN modifiers; END; $$ LANGUAGE plpgsql; -- REGEXP_LIKE( string text, pattern text) -> boolean -- If one of the param is NULL returns NULL, declared STRICT CREATE OR REPLACE FUNCTION oracle.regexp_like(text, text) RETURNS boolean AS $$ -- Oracle default behavior is newline-sensitive, -- PostgreSQL not, so force 'p' modifier to affect -- newline-sensitivity but not ^ and $ search. SELECT CASE WHEN (count(*) > 0) THEN true ELSE false END FROM regexp_matches($1, $2, 'p'); $$ LANGUAGE 'sql' STRICT; -- REGEXP_LIKE( string text, pattern text, flags text ) -> boolean CREATE OR REPLACE FUNCTION oracle.regexp_like(text, text, text) RETURNS boolean AS $$ DECLARE modifiers text; BEGIN -- Only modifier can be NULL IF $1 IS NULL OR $2 IS NULL THEN RETURN NULL; END IF; modifiers := oracle.translate_oracle_modifiers($3, false); IF (regexp_matches($1, $2, modifiers))[1] IS NOT NULL THEN RETURN true; END IF; RETURN false; END; $$ LANGUAGE plpgsql; -- REGEXP_COUNT( string text, pattern text ) -> integer CREATE OR REPLACE FUNCTION oracle.regexp_count(text, text) RETURNS integer AS $$ -- Oracle default behavior is newline-sensitive, -- PostgreSQL not, so force 'p' modifier to affect -- newline-sensitivity but not ^ and $ search. SELECT count(*)::integer FROM regexp_matches($1, $2, 'pg'); $$ LANGUAGE 'sql' STRICT; -- REGEXP_COUNT( string text, pattern text, position int ) -> integer CREATE OR REPLACE FUNCTION oracle.regexp_count(text, text, integer) RETURNS integer AS $$ DECLARE v_cnt integer; BEGIN -- Check numeric arguments IF $3 < 1 THEN RAISE EXCEPTION 'argument ''position'' must be a number greater than 0'; END IF; -- Oracle default behavior is newline-sensitive, -- PostgreSQL not, so force 'p' modifier to affect -- newline-sensitivity but not ^ and $ search. v_cnt := (SELECT count(*)::integer FROM regexp_matches(substr($1, $3), $2, 'pg')); RETURN v_cnt; END; $$ LANGUAGE plpgsql STRICT; -- REGEXP_COUNT( string text, pattern text, position int, flags text ) -> integer CREATE OR REPLACE FUNCTION oracle.regexp_count(text, text, integer, text) RETURNS integer AS $$ DECLARE modifiers text; v_cnt integer; BEGIN -- Only modifier can be NULL IF $1 IS NULL OR $2 IS NULL OR $3 IS NULL THEN RETURN NULL; END IF; -- Check numeric arguments IF $3 < 1 THEN RAISE EXCEPTION 'argument ''position'' must be a number greater than 0'; END IF; modifiers := oracle.translate_oracle_modifiers($4, true); v_cnt := (SELECT count(*)::integer FROM regexp_matches(substr($1, $3), $2, modifiers)); RETURN v_cnt; END; $$ LANGUAGE plpgsql; -- REGEXP_INSTR( string text, pattern text ) -> integer CREATE OR REPLACE FUNCTION oracle.regexp_instr(text, text) RETURNS integer AS $$ DECLARE v_pos integer; v_pattern text; BEGIN -- Without subexpression specified, assume 0 which mean that the first -- position for the substring matching the whole pattern is returned. -- We need to enclose the pattern between parentheses. v_pattern := '(' || $2 || ')'; -- Oracle default behavior is newline-sensitive, -- PostgreSQL not, so force 'p' modifier to affect -- newline-sensitivity but not ^ and $ search. v_pos := (SELECT position((SELECT (regexp_matches($1, v_pattern, 'pg'))[1] OFFSET 0 LIMIT 1) IN $1)); -- position() returns NULL when not found, we need to return 0 instead IF v_pos IS NOT NULL THEN RETURN v_pos; END IF; RETURN 0; END; $$ LANGUAGE plpgsql STRICT; -- REGEXP_INSTR( string text, pattern text, position int ) -> integer CREATE OR REPLACE FUNCTION oracle.regexp_instr(text, text, integer) RETURNS integer AS $$ DECLARE v_pos integer; v_pattern text; BEGIN IF $3 < 1 THEN RAISE EXCEPTION 'argument ''position'' must be a number greater than 0'; END IF; -- Without subexpression specified, assume 0 which mean that the first -- position for the substring matching the whole pattern is returned. -- We need to enclose the pattern between parentheses. v_pattern := '(' || $2 || ')'; -- Oracle default behavior is newline-sensitive, -- PostgreSQL not, so force 'p' modifier to affect -- newline-sensitivity but not ^ and $ search. v_pos := (SELECT position((SELECT (regexp_matches(substr($1, $3), v_pattern, 'pg'))[1] OFFSET 0 LIMIT 1) IN $1)); -- position() returns NULL when not found, we need to return 0 instead IF v_pos IS NOT NULL THEN RETURN v_pos; END IF; RETURN 0; END; $$ LANGUAGE plpgsql STRICT; -- REGEXP_INSTR( string text, pattern text, position int, occurence int ) -> integer CREATE OR REPLACE FUNCTION oracle.regexp_instr(text, text, integer, integer) RETURNS integer AS $$ DECLARE v_pos integer; v_pattern text; BEGIN IF $3 < 1 THEN RAISE EXCEPTION 'argument ''position'' must be a number greater than 0'; END IF; IF $4 < 1 THEN RAISE EXCEPTION 'argument ''occurence'' must be a number greater than 0'; END IF; -- Without subexpression specified, assume 0 which mean that the first -- position for the substring matching the whole pattern is returned. -- We need to enclose the pattern between parentheses. v_pattern := '(' || $2 || ')'; -- Oracle default behavior is newline-sensitive, -- PostgreSQL not, so force 'p' modifier to affect -- newline-sensitivity but not ^ and $ search. v_pos := (SELECT position((SELECT (regexp_matches(substr($1, $3), v_pattern, 'pg'))[1] OFFSET $4 - 1 LIMIT 1) IN $1)); -- position() returns NULL when not found, we need to return 0 instead IF v_pos IS NOT NULL THEN RETURN v_pos; END IF; RETURN 0; END; $$ LANGUAGE plpgsql STRICT; -- REGEXP_INSTR( string text, pattern text, position int, occurence int, return_opt int ) -> integer CREATE OR REPLACE FUNCTION oracle.regexp_instr(text, text, integer, integer, integer) RETURNS integer AS $$ DECLARE v_pos integer; v_len integer; v_pattern text; BEGIN IF $3 < 1 THEN RAISE EXCEPTION 'argument ''position'' must be a number greater than 0'; END IF; IF $4 < 1 THEN RAISE EXCEPTION 'argument ''occurence'' must be a number greater than 0'; END IF; IF $5 != 0 AND $5 != 1 THEN RAISE EXCEPTION 'argument ''return_opt'' must be 0 or 1'; END IF; -- Without subexpression specified, assume 0 which mean that the first -- Without subexpression specified, assume 0 which mean that the first -- position for the substring matching the whole pattern is returned. -- We need to enclose the pattern between parentheses. v_pattern := '(' || $2 || ')'; -- Oracle default behavior is newline-sensitive, -- PostgreSQL not, so force 'p' modifier to affect -- newline-sensitivity but not ^ and $ search. v_pos := (SELECT position((SELECT (regexp_matches(substr($1, $3), v_pattern, 'pg'))[1] OFFSET $4-1 LIMIT 1) IN $1)); -- position() returns NULL when not found, we need to return 0 instead IF v_pos IS NOT NULL THEN IF $5 = 1 THEN v_len := (SELECT length((SELECT (regexp_matches(substr($1, $3), v_pattern, 'pg'))[1] OFFSET $4 - 1 LIMIT 1))); v_pos := v_pos + v_len; END IF; RETURN v_pos; END IF; RETURN 0; END; $$ LANGUAGE plpgsql STRICT; -- REGEXP_INSTR( string text, pattern text, position int, occurence int, return_opt int, flags text ) -> integer CREATE OR REPLACE FUNCTION oracle.regexp_instr(text, text, integer, integer, integer, text) RETURNS integer AS $$ DECLARE v_pos integer; v_len integer; modifiers text; v_pattern text; BEGIN -- Only modifier can be NULL IF $1 IS NULL OR $2 IS NULL OR $3 IS NULL OR $4 IS NULL OR $5 IS NULL THEN RETURN NULL; END IF; -- Check numeric arguments IF $3 < 1 THEN RAISE EXCEPTION 'argument ''position'' must be a number greater than 0'; END IF; IF $4 < 1 THEN RAISE EXCEPTION 'argument ''occurence'' must be a number greater than 0'; END IF; IF $5 != 0 AND $5 != 1 THEN RAISE EXCEPTION 'argument ''return_opt'' must be 0 or 1'; END IF; modifiers := oracle.translate_oracle_modifiers($6, true); -- Without subexpression specified, assume 0 which mean that the first -- position for the substring matching the whole pattern is returned. -- We need to enclose the pattern between parentheses. v_pattern := '(' || $2 || ')'; v_pos := (SELECT position((SELECT (regexp_matches(substr($1, $3), v_pattern, modifiers))[1] OFFSET $4 - 1 LIMIT 1) IN $1)); -- position() returns NULL when not found, we need to return 0 instead IF v_pos IS NOT NULL THEN IF $5 = 1 THEN v_len := (SELECT length((SELECT (regexp_matches(substr($1, $3), v_pattern, modifiers))[1] OFFSET $4-1 LIMIT 1))); v_pos := v_pos + v_len; END IF; RETURN v_pos; END IF; RETURN 0; END; $$ LANGUAGE plpgsql; -- REGEXP_INSTR( string text, pattern text, position int, occurence int, return_opt int, flags text, group int ) -> integer CREATE OR REPLACE FUNCTION oracle.regexp_instr(text, text, integer, integer, integer, text, integer) RETURNS integer AS $$ DECLARE v_pos integer := 0; v_pos_orig integer := $3; v_len integer := 0; modifiers text; occurrence integer := $4; idx integer := 1; v_curr_pos integer := 0; v_pattern text; v_subexpr integer := $7; BEGIN -- Only modifier can be NULL IF $1 IS NULL OR $2 IS NULL OR $3 IS NULL OR $4 IS NULL OR $5 IS NULL OR $7 IS NULL THEN RETURN NULL; END IF; -- Check numeric arguments IF $3 < 1 THEN RAISE EXCEPTION 'argument ''position'' must be a number greater than 0'; END IF; IF $4 < 1 THEN RAISE EXCEPTION 'argument ''occurence'' must be a number greater than 0'; END IF; IF $7 < 0 THEN RAISE EXCEPTION 'argument ''group'' must be a positive number'; END IF; IF $5 != 0 AND $5 != 1 THEN RAISE EXCEPTION 'argument ''return_opt'' must be 0 or 1'; END IF; -- Translate Oracle regexp modifier into PostgreSQl ones modifiers := oracle.translate_oracle_modifiers($6, true); -- If subexpression value is 0 we need to enclose the pattern between parentheses. IF v_subexpr = 0 THEN v_pattern := '(' || $2 || ')'; v_subexpr := 1; ELSE v_pattern := $2; END IF; -- To get position of occurrence > 1 we need a more complex code LOOP v_curr_pos := v_curr_pos + v_len; v_pos := (SELECT position((SELECT (regexp_matches(substr($1, v_pos_orig), '('||$2||')', modifiers))[1] OFFSET 0 LIMIT 1) IN substr($1, v_pos_orig))); v_len := (SELECT length((SELECT (regexp_matches(substr($1, v_pos_orig), '('||$2||')', modifiers))[1] OFFSET 0 LIMIT 1))); EXIT WHEN v_len IS NULL; v_pos_orig := v_pos_orig + v_pos + v_len; v_curr_pos := v_curr_pos + v_pos; idx := idx + 1; EXIT WHEN idx > occurrence; END LOOP; v_pos := (SELECT position((SELECT (regexp_matches(substr($1, v_curr_pos), v_pattern, modifiers))[v_subexpr] OFFSET 0 LIMIT 1) IN substr($1, v_curr_pos))); IF v_pos IS NOT NULL THEN IF $5 = 1 THEN v_len := (SELECT length((SELECT (regexp_matches(substr($1, v_curr_pos), v_pattern, modifiers))[v_subexpr] OFFSET 0 LIMIT 1))); v_pos := v_pos + v_len; END IF; RETURN v_pos + v_curr_pos - 1; END IF; RETURN 0; END; $$ LANGUAGE plpgsql; -- REGEXP_SUBSTR( string text, pattern text ) -> text CREATE OR REPLACE FUNCTION oracle.regexp_substr(text, text) RETURNS text AS $$ DECLARE v_substr text; v_pattern text; BEGIN -- Without subexpression specified, assume 0 which mean that the first -- position for the substring matching the whole pattern is returned. -- We need to enclose the pattern between parentheses. v_pattern := '(' || $2 || ')'; -- Oracle default behavior is newline-sensitive, -- PostgreSQL not, so force 'p' modifier to affect -- newline-sensitivity but not ^ and $ search. v_substr := (SELECT (regexp_matches($1, v_pattern, 'pg'))[1] OFFSET 0 LIMIT 1); RETURN v_substr; END; $$ LANGUAGE plpgsql STRICT; -- REGEXP_SUBSTR( string text, pattern text, position int ) -> text CREATE OR REPLACE FUNCTION oracle.regexp_substr(text, text, int) RETURNS text AS $$ DECLARE v_substr text; v_pattern text; BEGIN -- Check numeric arguments IF $3 < 1 THEN RAISE EXCEPTION 'argument ''position'' must be a number greater than 0'; END IF; -- Without subexpression specified, assume 0 which mean that the first -- position for the substring matching the whole pattern is returned. -- We need to enclose the pattern between parentheses. v_pattern := '(' || $2 || ')'; -- Oracle default behavior is newline-sensitive, -- PostgreSQL not, so force 'p' modifier to affect -- newline-sensitivity but not ^ and $ search. v_substr := (SELECT (regexp_matches(substr($1, $3), v_pattern, 'pg'))[1] OFFSET 0 LIMIT 1); RETURN v_substr; END; $$ LANGUAGE plpgsql STRICT; -- REGEXP_SUBSTR( string text, pattern text, position int, occurence int ) -> text CREATE OR REPLACE FUNCTION oracle.regexp_substr(text, text, integer, integer) RETURNS text AS $$ DECLARE v_substr text; v_pattern text; BEGIN -- Check numeric arguments IF $3 < 1 THEN RAISE EXCEPTION 'argument ''position'' must be a number greater than 0'; END IF; IF $4 < 1 THEN RAISE EXCEPTION 'argument ''occurence'' must be a number greater than 0'; END IF; -- Without subexpression specified, assume 0 which mean that the first -- position for the substring matching the whole pattern is returned. -- We need to enclose the pattern between parentheses. v_pattern := '(' || $2 || ')'; -- Oracle default behavior is newline-sensitive, -- PostgreSQL not, so force 'p' modifier to affect -- newline-sensitivity but not ^ and $ search. v_substr := (SELECT (regexp_matches(substr($1, $3), v_pattern, 'pg'))[1] OFFSET $4 - 1 LIMIT 1); RETURN v_substr; END; $$ LANGUAGE plpgsql STRICT; -- REGEXP_SUBSTR( string text, pattern text, position int, occurence int, flags text ) -> text CREATE OR REPLACE FUNCTION oracle.regexp_substr(text, text, integer, integer, text) RETURNS text AS $$ DECLARE v_substr text; v_pattern text; modifiers text; BEGIN -- Only modifier can be NULL IF $1 IS NULL OR $2 IS NULL OR $3 IS NULL OR $4 IS NULL THEN RETURN NULL; END IF; -- Check numeric arguments IF $3 < 1 THEN RAISE EXCEPTION 'argument ''position'' must be a number greater than 0'; END IF; IF $4 < 1 THEN RAISE EXCEPTION 'argument ''occurence'' must be a number greater than 0'; END IF; modifiers := oracle.translate_oracle_modifiers($5, true); -- Without subexpression specified, assume 0 which mean that the first -- position for the substring matching the whole pattern is returned. -- We need to enclose the pattern between parentheses. v_pattern := '(' || $2 || ')'; -- Oracle default behavior is newline-sensitive, -- PostgreSQL not, so force 'p' modifier to affect -- newline-sensitivity but not ^ and $ search. v_substr := (SELECT (regexp_matches(substr($1, $3), v_pattern, modifiers))[1] OFFSET $4 - 1 LIMIT 1); RETURN v_substr; END; $$ LANGUAGE plpgsql; -- REGEXP_SUBSTR( string text, pattern text, position int, occurence int, flags text, group int ) -> text CREATE OR REPLACE FUNCTION oracle.regexp_substr(text, text, integer, integer, text, int) RETURNS text AS $$ DECLARE v_substr text; v_pattern text; modifiers text; v_subexpr integer := $6; has_group integer; BEGIN -- Only modifier can be NULL IF $1 IS NULL OR $2 IS NULL OR $3 IS NULL OR $4 IS NULL OR $6 IS NULL THEN RETURN NULL; END IF; -- Check numeric arguments IF $3 < 1 THEN RAISE EXCEPTION 'argument ''position'' must be a number greater than 0'; END IF; IF $4 < 1 THEN RAISE EXCEPTION 'argument ''occurence'' must be a number greater than 0'; END IF; IF v_subexpr < 0 THEN RAISE EXCEPTION 'argument ''group'' must be a positive number'; END IF; -- Check that with v_subexpr = 1 we have a capture group otherwise return NULL has_group := (SELECT count(*) FROM regexp_matches($2, '(?:[^\\]|^)\(', 'g')); IF $6 = 1 AND has_group = 0 THEN RETURN NULL; END IF; modifiers := oracle.translate_oracle_modifiers($5, true); -- If subexpression value is 0 we need to enclose the pattern between parentheses. IF v_subexpr = 0 THEN v_pattern := '(' || $2 || ')'; v_subexpr := 1; ELSE v_pattern := $2; END IF; -- Oracle default behavior is newline-sensitive, -- PostgreSQL not, so force 'p' modifier to affect -- newline-sensitivity but not ^ and $ search. v_substr := (SELECT (regexp_matches(substr($1, $3), v_pattern, modifiers))[v_subexpr] OFFSET $4 - 1 LIMIT 1); RETURN v_substr; END; $$ LANGUAGE plpgsql; -- REGEXP_REPLACE( string text, pattern text, replace_string text ) -> text CREATE OR REPLACE FUNCTION oracle.regexp_replace(text, text, text) RETURNS text AS $$ DECLARE str text; BEGIN IF $2 IS NULL AND $1 IS NOT NULL THEN RETURN $1; END IF; -- Oracle default behavior is to replace all occurence -- whereas PostgreSQL only replace the first occurrence -- so we need to add 'g' modifier. SELECT pg_catalog.regexp_replace($1, $2, $3, 'g') INTO str; RETURN str; END; $$ LANGUAGE plpgsql; -- REGEXP_REPLACE( string text, pattern text, replace_string text, position int ) -> text CREATE OR REPLACE FUNCTION oracle.regexp_replace(text, text, text, integer) RETURNS text AS $$ DECLARE v_replaced_str text; v_before text; BEGIN IF $1 IS NULL OR $3 IS NULL OR $4 IS NULL THEN RETURN NULL; END IF; IF $2 IS NULL THEN RETURN $1; END IF; -- Check numeric arguments IF $4 < 1 THEN RAISE EXCEPTION 'argument ''position'' must be a number greater than 0'; END IF; v_before = substr($1, 1, $4 - 1); -- Oracle default behavior is to replace all occurence -- whereas PostgreSQL only replace the first occurrence -- so we need to add 'g' modifier. v_replaced_str := v_before || pg_catalog.regexp_replace(substr($1, $4), $2, $3, 'g'); RETURN v_replaced_str; END; $$ LANGUAGE plpgsql; -- REGEXP_REPLACE( string text, pattern text, replace_string text, position int, occurence int ) -> text CREATE OR REPLACE FUNCTION oracle.regexp_replace(text, text, text, integer, integer) RETURNS text AS $$ DECLARE v_replaced_str text; v_pos integer := $4; v_before text := ''; v_nummatch integer; BEGIN IF $1 IS NULL OR $3 IS NULL OR $4 IS NULL OR $5 IS NULL THEN RETURN NULL; END IF; IF $2 IS NULL THEN RETURN $1; END IF; -- Check numeric arguments IF $4 < 1 THEN RAISE EXCEPTION 'argument ''position'' must be a number greater than 0'; END IF; IF $5 < 0 THEN RAISE EXCEPTION 'argument ''occurrence'' must be a positive number'; END IF; -- Check if the occurrence queried exceeds the number of occurrences IF $5 > 1 THEN v_nummatch := (SELECT count(*) FROM regexp_matches(substr($1, $4), $2, 'g')); IF $5 > v_nummatch THEN RETURN $1; END IF; -- Get the position of the occurrence we are looking for v_pos := oracle.regexp_instr($1, $2, $4, $5, 0, '', 1); IF v_pos = 0 THEN RETURN $1; END IF; END IF; -- Get the substring before this position we will need to restore it v_before := substr($1, 1, v_pos - 1); -- Replace all occurrences IF $5 = 0 THEN v_replaced_str := v_before || pg_catalog.regexp_replace(substr($1, v_pos), $2, $3, 'g'); ELSE -- Replace the first occurrence v_replaced_str := v_before || pg_catalog.regexp_replace(substr($1, v_pos), $2, $3); END IF; RETURN v_replaced_str; END; $$ LANGUAGE plpgsql; -- REGEXP_REPLACE( string text, pattern text, replace_string text, position int, occurence int, flags text ) -> text CREATE OR REPLACE FUNCTION oracle.regexp_replace(text, text, text, integer, integer, text) RETURNS text AS $$ DECLARE v_replaced_str text; v_pos integer := $4; v_nummatch integer; v_before text := ''; modifiers text := ''; BEGIN IF $1 IS NULL OR $3 IS NULL OR $4 IS NULL OR $5 IS NULL THEN RETURN NULL; END IF; IF $2 IS NULL THEN RETURN $1; END IF; -- Check numeric arguments IF $4 < 1 THEN RAISE EXCEPTION 'argument ''position'' must be a number greater than 0'; END IF; IF $5 < 0 THEN RAISE EXCEPTION 'argument ''occurrence'' must be a positive number'; END IF; -- Set the modifiers IF $5 = 0 THEN modifiers := oracle.translate_oracle_modifiers($6, true); ELSE modifiers := oracle.translate_oracle_modifiers($6, false); END IF; -- Check if the occurrence queried exceeds the number of occurrences IF $5 > 1 THEN v_nummatch := (SELECT count(*) FROM regexp_matches(substr($1, $4), $2, $6||'g')); IF $5 > v_nummatch THEN RETURN $1; END IF; -- Get the position of the occurrence we are looking for v_pos := oracle.regexp_instr($1, $2, $4, $5, 0, $6, 1); IF v_pos = 0 THEN RETURN $1; END IF; END IF; -- Get the substring before this position we will need to restore it v_before := substr($1, 1, v_pos - 1); -- Replace occurrence(s) v_replaced_str := v_before || pg_catalog.regexp_replace(substr($1, v_pos), $2, $3, modifiers); RETURN v_replaced_str; END; $$ LANGUAGE plpgsql; orafce-VERSION_4_14_4/orafce--3.17--3.18.sql000066400000000000000000000127651501757153000175200ustar00rootroot00000000000000---- -- Add LEAST/GREATEST declaration to return NULL on NULL input. -- PostgreSQL only returns NULL when all the parameters are NULL. ---- -- GREATEST CREATE FUNCTION oracle.greatest(integer, integer) RETURNS integer AS 'SELECT greatest($1, $2)' LANGUAGE SQL STRICT IMMUTABLE; CREATE FUNCTION oracle.greatest(integer, integer, integer) RETURNS integer AS 'SELECT greatest($1, $2, $3)' LANGUAGE SQL STRICT IMMUTABLE; CREATE FUNCTION oracle.greatest(smallint, smallint) RETURNS smallint AS 'SELECT greatest($1, $2)' LANGUAGE SQL STRICT IMMUTABLE; CREATE FUNCTION oracle.greatest(smallint, smallint, smallint) RETURNS smallint AS 'SELECT greatest($1, $2, $3)' LANGUAGE SQL STRICT IMMUTABLE; CREATE FUNCTION oracle.greatest(numeric, numeric) RETURNS numeric AS 'SELECT greatest($1, $2)' LANGUAGE SQL STRICT IMMUTABLE; CREATE FUNCTION oracle.greatest(numeric, numeric, numeric) RETURNS numeric AS 'SELECT greatest($1, $2, $3)' LANGUAGE SQL STRICT IMMUTABLE; CREATE FUNCTION oracle.greatest(bigint, bigint) RETURNS bigint AS 'SELECT greatest($1, $2)' LANGUAGE SQL STRICT IMMUTABLE; CREATE FUNCTION oracle.greatest(bigint, bigint, bigint) RETURNS bigint AS 'SELECT greatest($1, $2, $3)' LANGUAGE SQL STRICT IMMUTABLE; CREATE FUNCTION oracle.greatest(bpchar, bpchar) RETURNS bpchar AS 'SELECT greatest($1, $2)' LANGUAGE SQL STRICT IMMUTABLE; CREATE FUNCTION oracle.greatest(bpchar, bpchar, bpchar) RETURNS bpchar AS 'SELECT greatest($1, $2, $3)' LANGUAGE SQL STRICT IMMUTABLE; CREATE FUNCTION oracle.greatest(text, text) RETURNS text AS 'SELECT greatest($1, $2)' LANGUAGE SQL STRICT IMMUTABLE; CREATE FUNCTION oracle.greatest(text, text, text) RETURNS text AS 'SELECT greatest($1, $2, $3)' LANGUAGE SQL STRICT IMMUTABLE; CREATE FUNCTION oracle.greatest(date, date) RETURNS date AS 'SELECT greatest($1, $2)' LANGUAGE SQL STRICT IMMUTABLE; CREATE FUNCTION oracle.greatest(date, date, date) RETURNS date AS 'SELECT greatest($1, $2, $3)' LANGUAGE SQL STRICT IMMUTABLE; CREATE FUNCTION oracle.greatest(time, time) RETURNS time AS 'SELECT greatest($1, $2)' LANGUAGE SQL STRICT IMMUTABLE; CREATE FUNCTION oracle.greatest(time, time, time) RETURNS time AS 'SELECT greatest($1, $2, $3)' LANGUAGE SQL STRICT IMMUTABLE; CREATE FUNCTION oracle.greatest(timestamp, timestamp) RETURNS timestamp AS 'SELECT greatest($1, $2)' LANGUAGE SQL STRICT IMMUTABLE; CREATE FUNCTION oracle.greatest(timestamp, timestamp, timestamp) RETURNS timestamp AS 'SELECT greatest($1, $2, $3)' LANGUAGE SQL STRICT IMMUTABLE; CREATE FUNCTION oracle.greatest(timestamptz, timestamptz) RETURNS timestamptz AS 'SELECT greatest($1, $2)' LANGUAGE SQL STRICT IMMUTABLE; CREATE FUNCTION oracle.greatest(timestamptz, timestamptz, timestamptz) RETURNS timestamptz AS 'SELECT greatest($1, $2, $3)' LANGUAGE SQL STRICT IMMUTABLE; CREATE FUNCTION oracle.greatest(anynonarray, VARIADIC anyarray) RETURNS anynonarray AS 'MODULE_PATHNAME', 'ora_greatest' LANGUAGE C IMMUTABLE STRICT; -- LEAST CREATE FUNCTION oracle.least(integer, integer) RETURNS integer AS 'SELECT least($1, $2)' LANGUAGE SQL STRICT IMMUTABLE; CREATE FUNCTION oracle.least(integer, integer, integer) RETURNS integer AS 'SELECT least($1, $2, $3)' LANGUAGE SQL STRICT IMMUTABLE; CREATE FUNCTION oracle.least(smallint, smallint) RETURNS smallint AS 'SELECT least($1, $2)' LANGUAGE SQL STRICT IMMUTABLE; CREATE FUNCTION oracle.least(smallint, smallint, smallint) RETURNS smallint AS 'SELECT least($1, $2, $3)' LANGUAGE SQL STRICT IMMUTABLE; CREATE FUNCTION oracle.least(numeric, numeric) RETURNS numeric AS 'SELECT least($1, $2)' LANGUAGE SQL STRICT IMMUTABLE; CREATE FUNCTION oracle.least(numeric, numeric, numeric) RETURNS numeric AS 'SELECT least($1, $2, $3)' LANGUAGE SQL STRICT IMMUTABLE; CREATE FUNCTION oracle.least(bigint, bigint) RETURNS bigint AS 'SELECT least($1, $2)' LANGUAGE SQL STRICT IMMUTABLE; CREATE FUNCTION oracle.least(bigint, bigint, bigint) RETURNS bigint AS 'SELECT least($1, $2, $3)' LANGUAGE SQL STRICT IMMUTABLE; CREATE FUNCTION oracle.least(bpchar, bpchar) RETURNS bpchar AS 'SELECT least($1, $2)' LANGUAGE SQL STRICT IMMUTABLE; CREATE FUNCTION oracle.least(bpchar, bpchar, bpchar) RETURNS bpchar AS 'SELECT least($1, $2, $3)' LANGUAGE SQL STRICT IMMUTABLE; CREATE FUNCTION oracle.least(text, text) RETURNS text AS 'SELECT least($1, $2)' LANGUAGE SQL STRICT IMMUTABLE; CREATE FUNCTION oracle.least(text, text, text) RETURNS text AS 'SELECT least($1, $2, $3)' LANGUAGE SQL STRICT IMMUTABLE; CREATE FUNCTION oracle.least(date, date) RETURNS date AS 'SELECT least($1, $2)' LANGUAGE SQL STRICT IMMUTABLE; CREATE FUNCTION oracle.least(date, date, date) RETURNS date AS 'SELECT least($1, $2, $3)' LANGUAGE SQL STRICT IMMUTABLE; CREATE FUNCTION oracle.least(time, time) RETURNS time AS 'SELECT least($1, $2)' LANGUAGE SQL STRICT IMMUTABLE; CREATE FUNCTION oracle.least(time, time, time) RETURNS time AS 'SELECT least($1, $2, $3)' LANGUAGE SQL STRICT IMMUTABLE; CREATE FUNCTION oracle.least(timestamp, timestamp) RETURNS timestamp AS 'SELECT least($1, $2)' LANGUAGE SQL STRICT IMMUTABLE; CREATE FUNCTION oracle.least(timestamp, timestamp, timestamp) RETURNS timestamp AS 'SELECT least($1, $2, $3)' LANGUAGE SQL STRICT IMMUTABLE; CREATE FUNCTION oracle.least(timestamptz, timestamptz) RETURNS timestamptz AS 'SELECT least($1, $2)' LANGUAGE SQL STRICT IMMUTABLE; CREATE FUNCTION oracle.least(timestamptz, timestamptz, timestamptz) RETURNS timestamptz AS 'SELECT least($1, $2, $3)' LANGUAGE SQL STRICT IMMUTABLE; CREATE FUNCTION oracle.least(anynonarray, VARIADIC anyarray) RETURNS anynonarray AS 'MODULE_PATHNAME', 'ora_least' LANGUAGE C IMMUTABLE STRICT; orafce-VERSION_4_14_4/orafce--3.18--3.19.sql000066400000000000000000000011561501757153000175120ustar00rootroot00000000000000CREATE OR REPLACE FUNCTION pg_catalog.substrb(varchar2, integer, integer) RETURNS varchar2 AS 'MODULE_PATHNAME','oracle_substrb3' LANGUAGE C STRICT IMMUTABLE; CREATE OR REPLACE FUNCTION pg_catalog.substrb(varchar2, integer) RETURNS varchar2 AS 'MODULE_PATHNAME','oracle_substrb2' LANGUAGE C STRICT IMMUTABLE; DROP FUNCTION public.nvl2(anyelement, anyelement, anyelement); CREATE FUNCTION public.nvl2("any", anyelement, anyelement) RETURNS anyelement AS 'MODULE_PATHNAME','ora_nvl2' LANGUAGE C IMMUTABLE; CREATE FUNCTION public.nvl2("any", text, text) RETURNS text AS 'MODULE_PATHNAME','ora_nvl2' LANGUAGE C IMMUTABLE; orafce-VERSION_4_14_4/orafce--3.19--3.20.sql000066400000000000000000000120671501757153000175060ustar00rootroot00000000000000-- REGEXP_INSTR( string text, pattern text, position int, occurence int ) -> integer CREATE OR REPLACE FUNCTION oracle.regexp_instr(text, text, integer, integer) RETURNS integer LANGUAGE plpgsql STRICT AS $function$ DECLARE v_pos integer; v_pattern text; r record; start_pos integer DEFAULT 1; new_start integer; BEGIN IF $3 < 1 THEN RAISE EXCEPTION 'argument ''position'' must be a number greater than 0'; END IF; IF $4 < 1 THEN RAISE EXCEPTION 'argument ''occurence'' must be a number greater than 0'; END IF; -- Without subexpression specified, assume 0 which mean that the first -- position for the substring matching the whole pattern is returned. -- We need to enclose the pattern between parentheses. v_pattern := '(' || $2 || ')'; -- Oracle default behavior is newline-sensitive, -- PostgreSQL not, so force 'p' modifier to affect -- newline-sensitivity but not ^ and $ search. $1 := substr($1, $3); start_pos := $3; FOR r IN SELECT (regexp_matches($1, v_pattern, 'pg'))[1] LOOP v_pos := position(r.regexp_matches IN $1); IF $4 = 1 THEN RETURN v_pos + start_pos - 1; ELSE $4 := $4 - 1; END IF; new_start := v_pos + length(r.regexp_matches); $1 := substr($1, new_start); start_pos := start_pos + new_start - 1; END LOOP; RETURN 0; END; $function$; -- REGEXP_INSTR( string text, pattern text, position int, occurence int, return_opt int ) -> integer CREATE OR REPLACE FUNCTION oracle.regexp_instr(text, text, integer, integer, integer) RETURNS integer LANGUAGE plpgsql STRICT AS $function$ DECLARE v_pos integer; v_pattern text; r record; start_pos integer DEFAULT 1; new_start integer; pattern_match_len integer; BEGIN IF $3 < 1 THEN RAISE EXCEPTION 'argument ''position'' must be a number greater than 0'; END IF; IF $4 < 1 THEN RAISE EXCEPTION 'argument ''occurence'' must be a number greater than 0'; END IF; IF $5 != 0 AND $5 != 1 THEN RAISE EXCEPTION 'argument ''return_opt'' must be 0 or 1'; END IF; -- Without subexpression specified, assume 0 which mean that the first -- position for the substring matching the whole pattern is returned. -- We need to enclose the pattern between parentheses. v_pattern := '(' || $2 || ')'; -- Oracle default behavior is newline-sensitive, -- PostgreSQL not, so force 'p' modifier to affect -- newline-sensitivity but not ^ and $ search. $1 := substr($1, $3); start_pos := $3; FOR r IN SELECT (regexp_matches($1, v_pattern, 'pg'))[1] LOOP v_pos := position(r.regexp_matches IN $1); pattern_match_len = length(r.regexp_matches); IF $4 = 1 THEN IF $5 = 1 THEN new_start := v_pos + pattern_match_len; start_pos := start_pos + new_start - 1; RETURN start_pos; END IF; RETURN v_pos + start_pos - 1; ELSE $4 := $4 - 1; END IF; new_start := v_pos + pattern_match_len; $1 := substr($1, new_start); start_pos := start_pos + new_start - 1; END LOOP; RETURN 0; END; $function$; -- REGEXP_INSTR( string text, pattern text, position int, occurence int, return_opt int, flags text ) -> integer CREATE OR REPLACE FUNCTION oracle.regexp_instr(text, text, integer, integer, integer, text) RETURNS integer LANGUAGE plpgsql AS $function$ DECLARE v_pos integer; v_pattern text; r record; start_pos integer DEFAULT 1; new_start integer; pattern_match_len integer; modifiers text; BEGIN -- Only modifier can be NULL IF $1 IS NULL OR $2 IS NULL OR $3 IS NULL OR $4 IS NULL OR $5 IS NULL THEN RETURN NULL; END IF; -- Check numeric arguments IF $3 < 1 THEN RAISE EXCEPTION 'argument ''position'' must be a number greater than 0'; END IF; IF $4 < 1 THEN RAISE EXCEPTION 'argument ''occurence'' must be a number greater than 0'; END IF; IF $5 != 0 AND $5 != 1 THEN RAISE EXCEPTION 'argument ''return_opt'' must be 0 or 1'; END IF; -- Translate Oracle regexp modifier into PostgreSQL ones IF $6 IS NOT NULL THEN modifiers := oracle.translate_oracle_modifiers($6, true); ELSE modifiers := 'pg'; END IF; -- Without subexpression specified, assume 0 which mean that the first -- position for the substring matching the whole pattern is returned. -- We need to enclose the pattern between parentheses. v_pattern := '(' || $2 || ')'; -- Oracle default behavior is newline-sensitive, -- PostgreSQL not, so force 'p' modifier to affect -- newline-sensitivity but not ^ and $ search. $1 := substr($1, $3); start_pos := $3; FOR r IN SELECT (regexp_matches($1, v_pattern, modifiers))[1] LOOP v_pos := position(r.regexp_matches IN $1); pattern_match_len = length(r.regexp_matches); IF $4 = 1 THEN IF $5 = 1 THEN new_start := v_pos + pattern_match_len; start_pos := start_pos + new_start - 1; RETURN start_pos; END IF; RETURN v_pos + start_pos - 1; ELSE $4 := $4 - 1; END IF; new_start := v_pos + pattern_match_len; $1 := substr($1, new_start); start_pos := start_pos + new_start - 1; END LOOP; RETURN 0; END; $function$; orafce-VERSION_4_14_4/orafce--3.2--3.3.sql000066400000000000000000000055241501757153000173370ustar00rootroot00000000000000ALTER 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_4_14_4/orafce--3.20--3.21.sql000066400000000000000000000054301501757153000174730ustar00rootroot00000000000000-- REGEXP_INSTR( string text, pattern text ) -> integer CREATE OR REPLACE FUNCTION oracle.regexp_instr(text, text) RETURNS integer AS 'MODULE_PATHNAME','orafce_regexp_instr_no_start' LANGUAGE 'c' IMMUTABLE; -- REGEXP_INSTR( string text, pattern text, position int ) -> integer CREATE OR REPLACE FUNCTION oracle.regexp_instr(text, text, integer) RETURNS integer AS 'MODULE_PATHNAME','orafce_regexp_instr_no_n' LANGUAGE 'c' IMMUTABLE; -- REGEXP_INSTR( string text, pattern text, position int, occurence int ) -> integer CREATE OR REPLACE FUNCTION oracle.regexp_instr(text, text, integer, integer) RETURNS integer AS 'MODULE_PATHNAME','orafce_regexp_instr_no_endoption' LANGUAGE 'c' IMMUTABLE; -- REGEXP_INSTR( string text, pattern text, position int, occurence int, return_opt int ) -> integer CREATE OR REPLACE FUNCTION oracle.regexp_instr(text, text, integer, integer, integer) RETURNS integer AS 'MODULE_PATHNAME','orafce_regexp_instr_no_flags' LANGUAGE 'c' IMMUTABLE; -- REGEXP_INSTR( string text, pattern text, position int, occurence int, return_opt int, flags text ) -> integer CREATE OR REPLACE FUNCTION oracle.regexp_instr(text, text, integer, integer, integer, text) RETURNS integer AS 'MODULE_PATHNAME','orafce_regexp_instr_no_subexpr' LANGUAGE 'c' IMMUTABLE; -- REGEXP_INSTR( string text, pattern text, position int, occurence int, return_opt int, flags text, group int ) -> integer CREATE OR REPLACE FUNCTION oracle.regexp_instr(text, text, integer, integer, integer, text, integer) RETURNS integer AS 'MODULE_PATHNAME','orafce_regexp_instr' LANGUAGE 'c' IMMUTABLE; -- REGEXP_REPLACE( string text, pattern text, replace_string text ) -> text CREATE OR REPLACE FUNCTION oracle.regexp_replace(text, text, text) RETURNS text AS 'MODULE_PATHNAME','orafce_textregexreplace_noopt' LANGUAGE 'c' IMMUTABLE; -- REGEXP_REPLACE( string text, pattern text, replace_string text, position int ) -> text CREATE OR REPLACE FUNCTION oracle.regexp_replace(text, text, text, integer) RETURNS text AS 'MODULE_PATHNAME','orafce_textregexreplace_extended_no_n' LANGUAGE 'c' IMMUTABLE; -- REGEXP_REPLACE( string text, pattern text, replace_string text, position int, occurence int ) -> text CREATE OR REPLACE FUNCTION oracle.regexp_replace(text, text, text, integer, integer) RETURNS text AS 'MODULE_PATHNAME','orafce_textregexreplace_extended_no_flags' LANGUAGE 'c' IMMUTABLE; -- REGEXP_REPLACE( string text, pattern text, replace_string text, position int, occurence int, flags text ) -> text CREATE OR REPLACE FUNCTION oracle.regexp_replace(text, text, text, integer, integer, text) RETURNS text AS 'MODULE_PATHNAME','orafce_textregexreplace_extended' LANGUAGE 'c' IMMUTABLE; CREATE OR REPLACE FUNCTION oracle.regexp_replace(text, text, text, text) RETURNS text AS 'MODULE_PATHNAME','orafce_textregexreplace' LANGUAGE 'c' IMMUTABLE; orafce-VERSION_4_14_4/orafce--3.21--3.22.sql000066400000000000000000000445521501757153000175050ustar00rootroot00000000000000-- -- move objects from pg_catalog and from public schema to schema oracle -- DO $$ BEGIN IF EXISTS(SELECT * FROM pg_settings WHERE name = 'server_version_num' AND setting::int >= 120000) THEN EXECUTE $_$ALTER FUNCTION pg_catalog.trunc(date,text) SET SCHEMA oracle$_$; EXECUTE $_$ALTER FUNCTION pg_catalog.round(date,text) SET SCHEMA oracle$_$; EXECUTE $_$ALTER FUNCTION pg_catalog.next_day(date,text) SET SCHEMA oracle$_$; EXECUTE $_$ALTER FUNCTION pg_catalog.next_day(date,integer) SET SCHEMA oracle$_$; EXECUTE $_$ALTER FUNCTION pg_catalog.last_day(date) SET SCHEMA oracle$_$; EXECUTE $_$ALTER FUNCTION pg_catalog.months_between(date,date) SET SCHEMA oracle$_$; EXECUTE $_$ALTER FUNCTION pg_catalog.add_months(date,integer) SET SCHEMA oracle$_$; EXECUTE $_$ALTER FUNCTION pg_catalog.trunc(timestamp with time zone,text) SET SCHEMA oracle$_$; EXECUTE $_$ALTER FUNCTION pg_catalog.round(timestamp with time zone,text) SET SCHEMA oracle$_$; EXECUTE $_$ALTER FUNCTION pg_catalog.round(timestamp with time zone) SET SCHEMA oracle$_$; EXECUTE $_$ALTER FUNCTION pg_catalog.round(date) SET SCHEMA oracle$_$; EXECUTE $_$ALTER FUNCTION pg_catalog.trunc(timestamp with time zone) SET SCHEMA oracle$_$; EXECUTE $_$ALTER FUNCTION pg_catalog.trunc(date) SET SCHEMA oracle$_$; EXECUTE $_$ALTER FUNCTION pg_catalog.nlssort(text,text) SET SCHEMA oracle$_$; EXECUTE $_$ALTER FUNCTION pg_catalog.nlssort(text) SET SCHEMA oracle$_$; EXECUTE $_$ALTER FUNCTION pg_catalog.set_nls_sort(text) SET SCHEMA oracle$_$; EXECUTE $_$ALTER FUNCTION pg_catalog.instr(text,text,integer,integer) SET SCHEMA oracle$_$; EXECUTE $_$ALTER FUNCTION pg_catalog.instr(text,text,integer) SET SCHEMA oracle$_$; EXECUTE $_$ALTER FUNCTION pg_catalog.instr(text,text) SET SCHEMA oracle$_$; EXECUTE $_$ALTER FUNCTION pg_catalog.to_char(smallint) SET SCHEMA oracle$_$; EXECUTE $_$ALTER FUNCTION pg_catalog.to_char(integer) SET SCHEMA oracle$_$; EXECUTE $_$ALTER FUNCTION pg_catalog.to_char(bigint) SET SCHEMA oracle$_$; EXECUTE $_$ALTER FUNCTION pg_catalog.to_char(real) SET SCHEMA oracle$_$; EXECUTE $_$ALTER FUNCTION pg_catalog.to_char(double precision) SET SCHEMA oracle$_$; EXECUTE $_$ALTER FUNCTION pg_catalog.to_char(numeric) SET SCHEMA oracle$_$; EXECUTE $_$ALTER FUNCTION pg_catalog.to_number(text) SET SCHEMA oracle$_$; EXECUTE $_$ALTER FUNCTION pg_catalog.to_number(numeric) SET SCHEMA oracle$_$; EXECUTE $_$ALTER FUNCTION pg_catalog.to_number(numeric,numeric) SET SCHEMA oracle$_$; EXECUTE $_$ALTER FUNCTION pg_catalog.lnnvl(boolean) SET SCHEMA oracle$_$; EXECUTE $_$ALTER FUNCTION pg_catalog.listagg1_transfn(internal,text) SET SCHEMA oracle$_$; EXECUTE $_$ALTER FUNCTION pg_catalog.wm_concat_transfn(internal,text) SET SCHEMA oracle$_$; EXECUTE $_$ALTER FUNCTION pg_catalog.listagg2_transfn(internal,text,text) SET SCHEMA oracle$_$; EXECUTE $_$ALTER FUNCTION pg_catalog.listagg_finalfn(internal) SET SCHEMA oracle$_$; EXECUTE $_$ALTER FUNCTION pg_catalog.listagg(text) SET SCHEMA oracle$_$; EXECUTE $_$ALTER FUNCTION pg_catalog.wm_concat(text) SET SCHEMA oracle$_$; EXECUTE $_$ALTER FUNCTION pg_catalog.listagg(text,text) SET SCHEMA oracle$_$; EXECUTE $_$ALTER FUNCTION pg_catalog.median4_transfn(internal,real) SET SCHEMA oracle$_$; EXECUTE $_$ALTER FUNCTION pg_catalog.median4_finalfn(internal) SET SCHEMA oracle$_$; EXECUTE $_$ALTER FUNCTION pg_catalog.median8_transfn(internal,double precision) SET SCHEMA oracle$_$; EXECUTE $_$ALTER FUNCTION pg_catalog.median8_finalfn(internal) SET SCHEMA oracle$_$; EXECUTE $_$ALTER FUNCTION pg_catalog.median(real) SET SCHEMA oracle$_$; EXECUTE $_$ALTER FUNCTION pg_catalog.median(double precision) SET SCHEMA oracle$_$; EXECUTE $_$ALTER FUNCTION pg_catalog.substrb(varchar2,integer,integer) SET SCHEMA oracle$_$; EXECUTE $_$ALTER FUNCTION pg_catalog.substrb(varchar2,integer) SET SCHEMA oracle$_$; EXECUTE $_$ALTER FUNCTION pg_catalog.lengthb(varchar2) SET SCHEMA oracle$_$; EXECUTE $_$ALTER FUNCTION pg_catalog.strposb(varchar2,varchar2) SET SCHEMA oracle$_$; EXECUTE $_$ALTER FUNCTION pg_catalog.trunc(timestamp without time zone,text) SET SCHEMA oracle$_$; EXECUTE $_$ALTER FUNCTION pg_catalog.round(timestamp without time zone,text) SET SCHEMA oracle$_$; EXECUTE $_$ALTER FUNCTION pg_catalog.round(timestamp without time zone) SET SCHEMA oracle$_$; EXECUTE $_$ALTER FUNCTION pg_catalog.trunc(timestamp without time zone) SET SCHEMA oracle$_$; EXECUTE $_$ALTER FUNCTION pg_catalog.to_date(text) RENAME TO orafce__obsolete_to_date$_$; EXECUTE $_$ALTER FUNCTION pg_catalog.orafce__obsolete_to_date(text) SET SCHEMA oracle$_$; ELSE -- Pre PostgreSQL 12 doesn't allow ALTER FUNCTION pg_catalog.xx SET SCHEMA -- So we need to use dirty way ALTER FUNCTION pg_catalog.to_date(text) RENAME TO orafce__obsolete_to_date; INSERT INTO pg_depend SELECT 'pg_proc'::regclass, oid, 0, 'pg_namespace'::regclass, 'oracle'::regnamespace, 0, 'n' FROM pg_proc WHERE oid IN (SELECT objid FROM pg_depend WHERE refclassid = 'pg_extension'::regclass AND refobjid = (SELECT oid FROM pg_extension WHERE extname = 'orafce') AND classid = 'pg_proc'::regclass) AND pronamespace = 'pg_catalog'::regnamespace; UPDATE pg_proc SET pronamespace = 'oracle'::regnamespace WHERE oid IN (SELECT objid FROM pg_depend WHERE refclassid = 'pg_extension'::regclass AND refobjid = (SELECT oid FROM pg_extension WHERE extname = 'orafce') AND classid = 'pg_proc'::regclass) AND pronamespace = 'pg_catalog'::regnamespace; END IF; END; $$; ALTER FUNCTION public.to_multi_byte(text) SET SCHEMA oracle; ALTER FUNCTION public.to_single_byte(text) SET SCHEMA oracle; ALTER FUNCTION public.bitand(bigint,bigint) SET SCHEMA oracle; ALTER FUNCTION public.sinh(double precision) SET SCHEMA oracle; ALTER FUNCTION public.cosh(double precision) SET SCHEMA oracle; ALTER FUNCTION public.tanh(double precision) SET SCHEMA oracle; ALTER FUNCTION public.nanvl(real,real) SET SCHEMA oracle; ALTER FUNCTION public.nanvl(double precision,double precision) SET SCHEMA oracle; ALTER FUNCTION public.nanvl(numeric,numeric) SET SCHEMA oracle; ALTER FUNCTION public.nanvl(real,character varying) SET SCHEMA oracle; ALTER FUNCTION public.nanvl(double precision,character varying) SET SCHEMA oracle; ALTER FUNCTION public.nanvl(numeric,character varying) SET SCHEMA oracle; ALTER FUNCTION public.dump("any") SET SCHEMA oracle; ALTER FUNCTION public.dump("any",integer) SET SCHEMA oracle; ALTER FUNCTION public.nvl(anyelement,anyelement) SET SCHEMA oracle; ALTER FUNCTION public.nvl2("any",anyelement,anyelement) SET SCHEMA oracle; ALTER FUNCTION public.nvl2("any",text,text) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,text) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,text,text) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,text,anyelement,text) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,text,anyelement,text,text) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,text,anyelement,text,anyelement,text) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,text,anyelement,text,anyelement,text,text) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,character) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,character,character) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,character,anyelement,character) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,character,anyelement,character,character) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,character,anyelement,character,anyelement,character) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,character,anyelement,character,anyelement,character,character) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,integer) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,integer,integer) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,integer,anyelement,integer) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,integer,anyelement,integer,integer) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,integer,anyelement,integer,anyelement,integer) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,integer,anyelement,integer,anyelement,integer,integer) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,bigint) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,bigint,bigint) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,bigint,anyelement,bigint) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,bigint,anyelement,bigint,bigint) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,bigint,anyelement,bigint,anyelement,bigint) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,bigint,anyelement,bigint,anyelement,bigint,bigint) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,numeric) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,numeric,numeric) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,numeric,anyelement,numeric) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,numeric,anyelement,numeric,numeric) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,numeric,anyelement,numeric,anyelement,numeric) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,numeric,anyelement,numeric,anyelement,numeric,numeric) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,date) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,date,date) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,date,anyelement,date) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,date,anyelement,date,date) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,date,anyelement,date,anyelement,date) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,date,anyelement,date,anyelement,date,date) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,time without time zone) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,time without time zone,time without time zone) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,time without time zone,anyelement,time without time zone) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,time without time zone,anyelement,time without time zone,time without time zone) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,time without time zone,anyelement,time without time zone,anyelement,time without time zone) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,time without time zone,anyelement,time without time zone,anyelement,time without time zone,time without time zone) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,timestamp without time zone) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,timestamp without time zone,timestamp without time zone) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,timestamp without time zone,anyelement,timestamp without time zone) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,timestamp without time zone,anyelement,timestamp without time zone,timestamp without time zone) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,timestamp without time zone,anyelement,timestamp without time zone,anyelement,timestamp without time zone) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,timestamp without time zone,anyelement,timestamp without time zone,anyelement,timestamp without time zone,timestamp without time zone) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,timestamp with time zone) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,timestamp with time zone,timestamp with time zone) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,timestamp with time zone,anyelement,timestamp with time zone) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,timestamp with time zone,anyelement,timestamp with time zone,timestamp with time zone) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,timestamp with time zone,anyelement,timestamp with time zone,anyelement,timestamp with time zone) SET SCHEMA oracle; ALTER FUNCTION public.decode(anyelement,anyelement,timestamp with time zone,anyelement,timestamp with time zone,anyelement,timestamp with time zone,timestamp with time zone) SET SCHEMA oracle; ALTER FUNCTION public.dump(text) SET SCHEMA oracle; ALTER FUNCTION public.dump(text,integer) SET SCHEMA oracle; ALTER FUNCTION public.varchar2in(cstring,oid,integer) SET SCHEMA oracle; ALTER FUNCTION public.varchar2out(varchar2) SET SCHEMA oracle; ALTER FUNCTION public.varchar2_transform(internal) SET SCHEMA oracle; ALTER FUNCTION public.varchar2recv(internal,oid,integer) SET SCHEMA oracle; ALTER FUNCTION public.varchar2send(varchar2) SET SCHEMA oracle; ALTER FUNCTION public.varchar2typmodin(cstring[]) SET SCHEMA oracle; ALTER FUNCTION public.varchar2typmodout(integer) SET SCHEMA oracle; ALTER FUNCTION public.varchar2(varchar2,integer,boolean) SET SCHEMA oracle; ALTER FUNCTION public.nvarchar2in(cstring,oid,integer) SET SCHEMA oracle; ALTER FUNCTION public.nvarchar2out(nvarchar2) SET SCHEMA oracle; ALTER FUNCTION public.nvarchar2_transform(internal) SET SCHEMA oracle; ALTER FUNCTION public.nvarchar2recv(internal,oid,integer) SET SCHEMA oracle; ALTER FUNCTION public.nvarchar2send(nvarchar2) SET SCHEMA oracle; ALTER FUNCTION public.nvarchar2typmodin(cstring[]) SET SCHEMA oracle; ALTER FUNCTION public.nvarchar2typmodout(integer) SET SCHEMA oracle; ALTER FUNCTION public.nvarchar2(nvarchar2,integer,boolean) SET SCHEMA oracle; ALTER TYPE public.nvarchar2 SET SCHEMA oracle; ALTER TYPE public.varchar2 SET SCHEMA oracle; ALTER VIEW public.dual SET SCHEMA oracle; ALTER OPERATOR || (oracle.nvarchar2, oracle.nvarchar2) SET SCHEMA oracle; ALTER OPERATOR || (oracle.varchar2, oracle.varchar2) SET SCHEMA oracle; CREATE OR REPLACE FUNCTION oracle.to_number(numeric) RETURNS numeric AS $$ SELECT oracle.to_number($1::text); $$ LANGUAGE SQL IMMUTABLE; CREATE OR REPLACE FUNCTION oracle.to_number(numeric,numeric) RETURNS numeric AS $$ SELECT pg_catalog.to_number($1::text,$2::text); $$ LANGUAGE SQL IMMUTABLE; CREATE OR REPLACE FUNCTION oracle.sinh(float8) RETURNS float8 AS $$ SELECT (pg_catalog.exp($1) - pg_catalog.exp(-$1)) / 2; $$ LANGUAGE sql IMMUTABLE STRICT; CREATE OR REPLACE FUNCTION oracle.cosh(float8) RETURNS float8 AS $$ SELECT (pg_catalog.exp($1) + pg_catalog.exp(-$1)) / 2; $$ LANGUAGE sql IMMUTABLE STRICT; CREATE OR REPLACE FUNCTION oracle.tanh(float8) RETURNS float8 AS $$ SELECT oracle.sinh($1) / oracle.cosh($1); $$ LANGUAGE sql IMMUTABLE STRICT; CREATE OR REPLACE FUNCTION oracle.add_months(TIMESTAMP WITH TIME ZONE,INTEGER) RETURNS TIMESTAMP AS $$ SELECT (oracle.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 (pg_catalog.date_trunc('MONTH', $1) + INTERVAL '1 MONTH - 1 day' + $1::time)::oracle.date; $$ LANGUAGE SQL IMMUTABLE STRICT; CREATE OR REPLACE FUNCTION oracle.months_between(TIMESTAMP WITH TIME ZONE,TIMESTAMP WITH TIME ZONE) RETURNS NUMERIC AS $$ SELECT oracle.months_between($1::pg_catalog.date,$2::pg_catalog.date); $$ LANGUAGE SQL IMMUTABLE STRICT; CREATE OR REPLACE FUNCTION oracle.next_day(TIMESTAMP WITH TIME ZONE,INTEGER) RETURNS TIMESTAMP AS $$ SELECT (oracle.next_day($1::pg_catalog.date,$2) + $1::time)::oracle.date; $$ LANGUAGE SQL IMMUTABLE STRICT; CREATE OR REPLACE FUNCTION oracle.next_day(TIMESTAMP WITH TIME ZONE,TEXT) RETURNS TIMESTAMP AS $$ SELECT (oracle.next_day($1::pg_catalog.date,$2) + $1::time)::oracle.date; $$ LANGUAGE SQL IMMUTABLE STRICT; CREATE OR REPLACE FUNCTION oracle.to_date(TEXT) RETURNS oracle.date AS $$ SELECT oracle.orafce__obsolete_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 OR REPLACE FUNCTION oracle.nlssort(text) RETURNS bytea AS $$ SELECT oracle.nlssort($1, null); $$ LANGUAGE SQL IMMUTABLE STRICT; CREATE OR REPLACE FUNCTION oracle.round(value timestamp with time zone) RETURNS timestamp with time zone AS $$ SELECT oracle.round($1, 'DDD'); $$ LANGUAGE SQL IMMUTABLE STRICT; CREATE OR REPLACE FUNCTION oracle.trunc(value timestamp with time zone) RETURNS timestamp with time zone AS $$ SELECT oracle.trunc($1, 'DDD'); $$ LANGUAGE SQL IMMUTABLE STRICT; CREATE OR REPLACE FUNCTION oracle.round(value timestamp without time zone) RETURNS timestamp without time zone AS $$ SELECT oracle.round($1, 'DDD'); $$ LANGUAGE SQL IMMUTABLE STRICT; CREATE OR REPLACE FUNCTION oracle.trunc(value timestamp without time zone) RETURNS timestamp without time zone AS $$ SELECT oracle.trunc($1, 'DDD'); $$ LANGUAGE SQL IMMUTABLE STRICT; CREATE OR REPLACE FUNCTION oracle.mod(SMALLINT, SMALLINT) RETURNS SMALLINT AS $$ SELECT CASE $2 WHEN 0 THEN $1 ELSE pg_catalog.MOD($1, $2) END; $$ LANGUAGE SQL IMMUTABLE; CREATE OR REPLACE FUNCTION oracle.mod(INT, INT) RETURNS INT AS $$ SELECT CASE $2 WHEN 0 THEN $1 ELSE pg_catalog.MOD($1, $2) END; $$ LANGUAGE SQL IMMUTABLE; CREATE OR REPLACE FUNCTION oracle.mod(BIGINT, BIGINT) RETURNS BIGINT AS $$ SELECT CASE $2 WHEN 0 THEN $1 ELSE pg_catalog.MOD($1, $2) END; $$ LANGUAGE sql IMMUTABLE; CREATE OR REPLACE FUNCTION oracle.mod(NUMERIC, NUMERIC) RETURNS NUMERIC AS $$ SELECT CASE $2 WHEN 0 THEN $1 ELSE pg_catalog.MOD($1, $2) END; $$ LANGUAGE sql IMMUTABLE; orafce-VERSION_4_14_4/orafce--3.22--3.23.sql000066400000000000000000000021171501757153000174760ustar00rootroot00000000000000CREATE OR REPLACE FUNCTION oracle.mod(SMALLINT, SMALLINT) RETURNS SMALLINT AS $$ SELECT CASE $2 WHEN 0 THEN $1 ELSE pg_catalog.MOD($1, $2) END; $$ LANGUAGE SQL IMMUTABLE; CREATE OR REPLACE FUNCTION oracle.mod(INT, INT) RETURNS INT AS $$ SELECT CASE $2 WHEN 0 THEN $1 ELSE pg_catalog.MOD($1, $2) END; $$ LANGUAGE SQL IMMUTABLE; CREATE OR REPLACE FUNCTION oracle.mod(BIGINT, BIGINT) RETURNS BIGINT AS $$ SELECT CASE $2 WHEN 0 THEN $1 ELSE pg_catalog.MOD($1, $2) END; $$ LANGUAGE sql IMMUTABLE; CREATE OR REPLACE FUNCTION oracle.mod(NUMERIC, NUMERIC) RETURNS NUMERIC AS $$ SELECT CASE $2 WHEN 0 THEN $1 ELSE pg_catalog.MOD($1, $2) END; $$ LANGUAGE sql IMMUTABLE; DO $$ BEGIN IF EXISTS(SELECT * FROM pg_settings WHERE name = 'server_version_num' AND setting::int >= 90600) THEN EXECUTE $_$ALTER FUNCTION oracle.mod(SMALLINT, SMALLINT) PARALLEL SAFE$_$; EXECUTE $_$ALTER FUNCTION oracle.mod(INT, INT) PARALLEL SAFE$_$; EXECUTE $_$ALTER FUNCTION oracle.mod(BIGINT, BIGINT) PARALLEL SAFE$_$; EXECUTE $_$ALTER FUNCTION oracle.mod(NUMERIC, NUMERIC) PARALLEL SAFE$_$; END IF; END; $$; orafce-VERSION_4_14_4/orafce--3.23--3.24.sql000066400000000000000000000010751501757153000175020ustar00rootroot00000000000000DO $$ BEGIN IF EXISTS(SELECT * FROM pg_settings WHERE name = 'server_version_num' AND setting::int >= 130000) THEN EXECUTE $_$ALTER TYPE oracle.nvarchar2 SET (storage = extended)$_$; EXECUTE $_$ALTER TYPE oracle.varchar2 SET (storage = extended)$_$; ELSE UPDATE pg_type SET typstorage = 'x' WHERE typname = 'nvarchar2' AND typnamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'oracle'); UPDATE pg_type SET typstorage = 'x' WHERE typname = 'varchar2' AND typnamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'oracle'); END IF; END; $$; orafce-VERSION_4_14_4/orafce--3.24--3.25.sql000066400000000000000000000020131501757153000174750ustar00rootroot00000000000000CREATE OR REPLACE FUNCTION oracle.remainder(smallint, smallint) RETURNS smallint AS 'MODULE_PATHNAME','orafce_reminder_smallint' LANGUAGE C IMMUTABLE; CREATE OR REPLACE FUNCTION oracle.remainder(int, int) RETURNS int AS 'MODULE_PATHNAME','orafce_reminder_int' LANGUAGE C IMMUTABLE; CREATE OR REPLACE FUNCTION oracle.remainder(bigint, bigint) RETURNS bigint AS 'MODULE_PATHNAME','orafce_reminder_bigint' LANGUAGE C IMMUTABLE; CREATE OR REPLACE FUNCTION oracle.remainder(numeric, numeric) RETURNS numeric AS 'MODULE_PATHNAME','orafce_reminder_numeric' LANGUAGE C IMMUTABLE; DO $$ BEGIN IF EXISTS(SELECT * FROM pg_settings WHERE name = 'server_version_num' AND setting::int >= 90600) THEN EXECUTE $_$ALTER FUNCTION oracle.remainder(smallint, smallint) PARALLEL SAFE$_$; EXECUTE $_$ALTER FUNCTION oracle.remainder(int, int) PARALLEL SAFE$_$; EXECUTE $_$ALTER FUNCTION oracle.remainder(bigint, bigint) PARALLEL SAFE$_$; EXECUTE $_$ALTER FUNCTION oracle.remainder(numeric, numeric) PARALLEL SAFE$_$; END IF; END; $$; orafce-VERSION_4_14_4/orafce--3.25--4.0.sql000066400000000000000000000056041501757153000174210ustar00rootroot00000000000000CREATE SCHEMA dbms_sql; GRANT USAGE ON SCHEMA dbms_sql TO PUBLIC; CREATE FUNCTION dbms_sql.is_open(c int) RETURNS bool AS 'MODULE_PATHNAME', 'dbms_sql_is_open' LANGUAGE c; CREATE FUNCTION dbms_sql.open_cursor() RETURNS int AS 'MODULE_PATHNAME', 'dbms_sql_open_cursor' LANGUAGE c; CREATE PROCEDURE dbms_sql.close_cursor(c int) AS 'MODULE_PATHNAME', 'dbms_sql_close_cursor' LANGUAGE c; CREATE PROCEDURE dbms_sql.debug_cursor(c int) AS 'MODULE_PATHNAME', 'dbms_sql_debug_cursor' LANGUAGE c; CREATE PROCEDURE dbms_sql.parse(c int, stmt oracle.varchar2) AS 'MODULE_PATHNAME', 'dbms_sql_parse' LANGUAGE c; CREATE PROCEDURE dbms_sql.bind_variable(c int, name oracle.varchar2, value "any") AS 'MODULE_PATHNAME', 'dbms_sql_bind_variable' LANGUAGE c; CREATE FUNCTION dbms_sql.bind_variable_f(c int, name oracle.varchar2, value "any") RETURNS void AS 'MODULE_PATHNAME', 'dbms_sql_bind_variable_f' LANGUAGE c; CREATE PROCEDURE dbms_sql.bind_array(c int, name oracle.varchar2, value anyarray) AS 'MODULE_PATHNAME', 'dbms_sql_bind_array_3' LANGUAGE c; CREATE PROCEDURE dbms_sql.bind_array(c int, name oracle.varchar2, value anyarray, index1 int, index2 int) AS 'MODULE_PATHNAME', 'dbms_sql_bind_array_5' LANGUAGE c; CREATE PROCEDURE dbms_sql.define_column(c int, col int, value "any", column_size int DEFAULT -1) AS 'MODULE_PATHNAME', 'dbms_sql_define_column' LANGUAGE c; CREATE PROCEDURE dbms_sql.define_array(c int, col int, value "anyarray", cnt int, lower_bnd int) AS 'MODULE_PATHNAME', 'dbms_sql_define_array' LANGUAGE c; CREATE FUNCTION dbms_sql.execute(c int) RETURNS bigint AS 'MODULE_PATHNAME', 'dbms_sql_execute' LANGUAGE c; CREATE FUNCTION dbms_sql.fetch_rows(c int) RETURNS int AS 'MODULE_PATHNAME', 'dbms_sql_fetch_rows' LANGUAGE c; CREATE FUNCTION dbms_sql.execute_and_fetch(c int, exact bool DEFAULT false) RETURNS int AS 'MODULE_PATHNAME', 'dbms_sql_execute_and_fetch' LANGUAGE c; CREATE FUNCTION dbms_sql.last_row_count() RETURNS int AS 'MODULE_PATHNAME', 'dbms_sql_last_row_count' LANGUAGE c; CREATE PROCEDURE dbms_sql.column_value(c int, pos int, INOUT value anyelement) AS 'MODULE_PATHNAME', 'dbms_sql_column_value' LANGUAGE c; CREATE FUNCTION dbms_sql.column_value_f(c int, pos int, value anyelement) RETURNS anyelement AS 'MODULE_PATHNAME', 'dbms_sql_column_value_f' LANGUAGE c; CREATE TYPE dbms_sql.desc_rec AS ( col_type int, col_max_len int, col_name text, col_name_len int, col_schema text, col_schema_len int, col_precision int, col_scale int, col_charsetid int, col_charsetform int, col_null_ok boolean, col_type_name text, col_type_name_len int); CREATE FUNCTION dbms_sql.describe_columns_f(c int, OUT col_cnt int, OUT desc_t dbms_sql.desc_rec[]) AS 'MODULE_PATHNAME', 'dbms_sql_describe_columns_f' LANGUAGE c; CREATE PROCEDURE dbms_sql.describe_columns(c int, INOUT col_cnt int, INOUT desc_t dbms_sql.desc_rec[]) AS 'MODULE_PATHNAME', 'dbms_sql_describe_columns_f' LANGUAGE c; orafce-VERSION_4_14_4/orafce--3.3--3.4.sql000066400000000000000000000005551501757153000173400ustar00rootroot00000000000000/* * 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_4_14_4/orafce--3.4--3.5.sql000066400000000000000000000004371501757153000173410ustar00rootroot00000000000000update 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_4_14_4/orafce--3.5--3.6.sql000066400000000000000000000162531501757153000173460ustar00rootroot00000000000000CREATE 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_4_14_4/orafce--3.6--3.7.sql000066400000000000000000000034671501757153000173530ustar00rootroot00000000000000-- 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; drop view oracle.user_tables; create view oracle.user_tables as select table_name from information_schema.tables where table_type = 'BASE TABLE'; -- 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_4_14_4/orafce--3.7--3.8.sql000066400000000000000000000010321501757153000173370ustar00rootroot00000000000000-- 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_4_14_4/orafce--3.8--3.9.sql000066400000000000000000000011711501757153000173450ustar00rootroot00000000000000drop 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_4_14_4/orafce--3.9--3.10.sql000066400000000000000000000001021501757153000174070ustar00rootroot00000000000000ALTER TABLE utl_file.utl_file_dir ADD COLUMN dirname text UNIQUE; orafce-VERSION_4_14_4/orafce--4.0--4.1.sql000066400000000000000000000000761501757153000173320ustar00rootroot00000000000000SELECT pg_extension_config_dump('utl_file.utl_file_dir', ''); orafce-VERSION_4_14_4/orafce--4.1--4.2.sql000066400000000000000000000001711501757153000173300ustar00rootroot00000000000000 CREATE OR REPLACE FUNCTION oracle.sys_guid() RETURNS bytea AS 'MODULE_PATHNAME','orafce_sys_guid' LANGUAGE C VOLATILE; orafce-VERSION_4_14_4/orafce--4.10--4.11.sql000066400000000000000000000010051501757153000174650ustar00rootroot00000000000000CREATE FUNCTION oracle.sys_extract_utc(timestamp with time zone) RETURNS timestamp without time zone AS 'MODULE_PATHNAME','orafce_sys_extract_utc' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION oracle.sysdate() IS 'Extract timestamp at utc time zone'; CREATE FUNCTION oracle.sys_extract_utc(oracle.date) RETURNS oracle.date AS 'MODULE_PATHNAME','orafce_sys_extract_utc_oracle_date' LANGUAGE C STABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION oracle.sysdate() IS 'Extract timestamp at utc time zone'; orafce-VERSION_4_14_4/orafce--4.11--4.12.sql000066400000000000000000000004641501757153000174770ustar00rootroot00000000000000CREATE OR REPLACE FUNCTION oracle.to_date (TEXT, TEXT) RETURNS oracle.date AS $$ SELECT CASE WHEN upper($2) = 'J' THEN substr((pg_catalog.to_date($1, $2) + '400 days'::interval)::text, 1, 19)::oracle.date ELSE TO_TIMESTAMP($1,$2)::oracle.date END; $$ LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE; orafce-VERSION_4_14_4/orafce--4.12--4.13.sql000066400000000000000000000012571501757153000175020ustar00rootroot00000000000000-- remove obsolete signature of dbms_alert.defered_signal DO $$ BEGIN IF EXISTS (SELECT * FROM pg_proc p JOIN pg_namespace n ON p.pronamespace = n.oid WHERE n.nspname = 'dbms_alert' AND p.proname = 'defered_signal') THEN DROP FUNCTION dbms_alert.defered_signal(); END IF; END; $$; CREATE FUNCTION oracle.orafce__obsolete_to_date(str text, fmt text) RETURNS timestamp AS 'MODULE_PATHNAME','ora_to_date' LANGUAGE C STABLE STRICT PARALLEL SAFE; CREATE OR REPLACE FUNCTION oracle.to_date(TEXT, TEXT) RETURNS oracle.date AS $$ SELECT oracle.orafce__obsolete_to_date($1, $2)::oracle.date; $$ LANGUAGE SQL STABLE STRICT PARALLEL SAFE; orafce-VERSION_4_14_4/orafce--4.13--4.14.sql000066400000000000000000000005271501757153000175030ustar00rootroot00000000000000CREATE OR REPLACE FUNCTION oracle.nvl(double precision, int) RETURNS double precision AS $$ SELECT coalesce($1, $2) $$ LANGUAGE sql IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.to_date(integer, TEXT) RETURNS oracle.date AS $$ SELECT oracle.orafce__obsolete_to_date($1::text, $2)::oracle.date; $$ LANGUAGE SQL STABLE STRICT PARALLEL SAFE; orafce-VERSION_4_14_4/orafce--4.14--4.15.sql000066400000000000000000000001011501757153000174710ustar00rootroot00000000000000alter function dbms_alert.signal ( text, text) security invoker; orafce-VERSION_4_14_4/orafce--4.15.sql000066400000000000000000004253131501757153000170500ustar00rootroot00000000000000/* orafce--3.25.sql */ -- complain if script is sourced in psql, rather than via CREATE EXTENSION \echo Use "CREATE EXTENSION orafce" to load this file. \quit CREATE SCHEMA oracle; CREATE FUNCTION oracle.trunc(value date, fmt text) RETURNS date AS 'MODULE_PATHNAME','ora_date_trunc' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION oracle.trunc(date,text) IS 'truncate date according to the specified format'; CREATE FUNCTION oracle.round(value date, fmt text) RETURNS date AS 'MODULE_PATHNAME','ora_date_round' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION oracle.round(date, text) IS 'round dates according to the specified format'; CREATE FUNCTION oracle.next_day(value date, weekday text) RETURNS date AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION oracle.next_day (date, text) IS 'returns the first weekday that is greater than a date value'; CREATE FUNCTION oracle.next_day(value date, weekday integer) RETURNS date AS 'MODULE_PATHNAME', 'next_day_by_index' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION oracle.next_day (date, integer) IS 'returns the first weekday that is greater than a date value'; CREATE FUNCTION oracle.last_day(value date) RETURNS date AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION oracle.last_day(date) IS 'returns last day of the month based on a date value'; CREATE FUNCTION oracle.months_between(date1 date, date2 date) RETURNS numeric AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION oracle.months_between(date, date) IS 'returns the number of months between date1 and date2'; CREATE FUNCTION oracle.add_months(day date, value int) RETURNS date AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION oracle.add_months(date, int) IS 'returns date plus n months'; CREATE FUNCTION oracle.trunc(value timestamp with time zone, fmt text) RETURNS timestamp with time zone AS 'MODULE_PATHNAME', 'ora_timestamptz_trunc' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION oracle.trunc(timestamp with time zone, text) IS 'truncate date according to the specified format'; CREATE FUNCTION oracle.round(value timestamp with time zone, fmt text) RETURNS timestamp with time zone AS 'MODULE_PATHNAME','ora_timestamptz_round' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION oracle.round(timestamp with time zone, text) IS 'round dates according to the specified format'; CREATE FUNCTION oracle.round(value timestamp with time zone) RETURNS timestamp with time zone AS $$ SELECT oracle.round($1, 'DDD'); $$ LANGUAGE SQL IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION oracle.round(timestamp with time zone) IS 'will round dates according to the specified format'; CREATE FUNCTION oracle.round(value date) RETURNS date AS $$ SELECT $1; $$ LANGUAGE SQL IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION oracle.round(value date)IS 'will round dates according to the specified format'; CREATE FUNCTION oracle.trunc(value timestamp with time zone) RETURNS timestamp with time zone AS $$ SELECT oracle.trunc($1, 'DDD'); $$ LANGUAGE SQL IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION oracle.trunc(timestamp with time zone) IS 'truncate date according to the specified format'; CREATE FUNCTION oracle.trunc(value date) RETURNS date AS $$ SELECT $1; $$ LANGUAGE SQL IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION oracle.trunc(date) IS 'truncate date according to the specified format'; CREATE FUNCTION oracle.nlssort(text, text) RETURNS bytea AS 'MODULE_PATHNAME', 'ora_nlssort' LANGUAGE C IMMUTABLE; COMMENT ON FUNCTION oracle.nlssort(text, text) IS ''; CREATE FUNCTION oracle.nlssort(text) RETURNS bytea AS $$ SELECT oracle.nlssort($1, null); $$ LANGUAGE SQL IMMUTABLE STRICT; COMMENT ON FUNCTION oracle.nlssort(text)IS ''; CREATE FUNCTION oracle.set_nls_sort(text) RETURNS void AS 'MODULE_PATHNAME', 'ora_set_nls_sort' LANGUAGE C IMMUTABLE STRICT; COMMENT ON FUNCTION oracle.set_nls_sort(text) IS ''; CREATE FUNCTION oracle.instr(str text, patt text, start int, nth int) RETURNS int AS 'MODULE_PATHNAME','plvstr_instr4' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION oracle.instr(text, text, int, int) IS 'Search pattern in string'; CREATE FUNCTION oracle.instr(str text, patt text, start int) RETURNS int AS 'MODULE_PATHNAME','plvstr_instr3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION oracle.instr(text, text, int) IS 'Search pattern in string'; CREATE FUNCTION oracle.instr(str text, patt text) RETURNS int AS 'MODULE_PATHNAME','plvstr_instr2' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION oracle.instr(text, text) IS 'Search pattern in string'; CREATE FUNCTION oracle.to_char(num smallint) RETURNS text AS 'MODULE_PATHNAME','orafce_to_char_int4' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION oracle.to_char(smallint) IS 'Convert number to string'; CREATE FUNCTION oracle.to_char(num int) RETURNS text AS 'MODULE_PATHNAME','orafce_to_char_int4' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION oracle.to_char(int) IS 'Convert number to string'; CREATE FUNCTION oracle.to_char(num bigint) RETURNS text AS 'MODULE_PATHNAME','orafce_to_char_int8' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION oracle.to_char(bigint) IS 'Convert number to string'; CREATE FUNCTION oracle.to_char(num real) RETURNS text AS 'MODULE_PATHNAME','orafce_to_char_float4' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION oracle.to_char(real) IS 'Convert number to string'; CREATE FUNCTION oracle.to_char(num double precision) RETURNS text AS 'MODULE_PATHNAME','orafce_to_char_float8' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION oracle.to_char(double precision) IS 'Convert number to string'; CREATE FUNCTION oracle.to_char(num numeric) RETURNS text AS 'MODULE_PATHNAME','orafce_to_char_numeric' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION oracle.to_char(numeric) IS 'Convert number to string'; CREATE FUNCTION oracle.to_number(str text) RETURNS numeric AS 'MODULE_PATHNAME','orafce_to_number' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION oracle.to_number(text) IS 'Convert string to number'; CREATE OR REPLACE FUNCTION oracle.to_number(numeric) RETURNS numeric AS $$ SELECT oracle.to_number($1::text); $$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE; CREATE OR REPLACE FUNCTION oracle.to_number(numeric,numeric) RETURNS numeric AS $$ SELECT pg_catalog.to_number($1::text,$2::text); $$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.orafce__obsolete_to_date(str text) RETURNS timestamp AS 'MODULE_PATHNAME','ora_to_date' LANGUAGE C STABLE STRICT PARALLEL SAFE; CREATE FUNCTION oracle.orafce__obsolete_to_date(str text, fmt text) RETURNS timestamp AS 'MODULE_PATHNAME','ora_to_date' LANGUAGE C STABLE STRICT PARALLEL SAFE; CREATE FUNCTION oracle.to_multi_byte(str text) RETURNS text AS 'MODULE_PATHNAME','orafce_to_multi_byte' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION oracle.to_multi_byte(text) IS 'Convert all single-byte characters to their corresponding multibyte characters'; CREATE FUNCTION oracle.to_single_byte(str text) RETURNS text AS 'MODULE_PATHNAME','orafce_to_single_byte' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION oracle.to_single_byte(text) IS 'Convert characters to their corresponding single-byte characters if possible'; CREATE FUNCTION oracle.bitand(bigint, bigint) RETURNS bigint AS $$ SELECT $1 & $2; $$ LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE; CREATE FUNCTION oracle.sinh(float8) RETURNS float8 AS $$ SELECT (exp($1) - exp(-$1)) / 2; $$ LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE; CREATE FUNCTION oracle.cosh(float8) RETURNS float8 AS $$ SELECT (exp($1) + exp(-$1)) / 2; $$ LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE; CREATE FUNCTION oracle.tanh(float8) RETURNS float8 AS $$ SELECT oracle.sinh($1) / oracle.cosh($1); $$ LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE; CREATE FUNCTION oracle.nanvl(float4, float4) RETURNS float4 AS $$ SELECT CASE WHEN $1 = 'NaN' THEN $2 ELSE $1 END; $$ LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE; CREATE FUNCTION oracle.nanvl(float8, float8) RETURNS float8 AS $$ SELECT CASE WHEN $1 = 'NaN' THEN $2 ELSE $1 END; $$ LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE; CREATE FUNCTION oracle.nanvl(numeric, numeric) RETURNS numeric AS $$ SELECT CASE WHEN $1 = 'NaN' THEN $2 ELSE $1 END; $$ LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE; CREATE FUNCTION oracle.nanvl(float4, varchar) RETURNS float4 AS $$ SELECT CASE WHEN $1 = 'NaN' THEN $2::float4 ELSE $1 END; $$ LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE; CREATE FUNCTION oracle.nanvl(float8, varchar) RETURNS float8 AS $$ SELECT CASE WHEN $1 = 'NaN' THEN $2::float8 ELSE $1 END; $$ LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE; CREATE FUNCTION oracle.nanvl(numeric, varchar) RETURNS numeric AS $$ SELECT CASE WHEN $1 = 'NaN' THEN $2::numeric ELSE $1 END; $$ LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE; CREATE FUNCTION oracle.dump("any") RETURNS varchar AS 'MODULE_PATHNAME', 'orafce_dump' LANGUAGE C; CREATE FUNCTION oracle.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 oracle.lnnvl(bool) RETURNS bool AS 'MODULE_PATHNAME','ora_lnnvl' LANGUAGE C IMMUTABLE PARALLEL SAFE; COMMENT ON FUNCTION oracle.lnnvl(bool) IS ''; -- can't overwrite PostgreSQL functions!!!! CREATE FUNCTION oracle.substr(str text, start int) RETURNS text AS 'MODULE_PATHNAME','oracle_substr2' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; 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 PARALLEL SAFE; 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 PARALLEL SAFE; 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 PARALLEL SAFE; CREATE OR REPLACE FUNCTION oracle.substr(varchar,numeric) RETURNS text AS $$ SELECT oracle.substr($1,trunc($2)::int); $$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE; 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 PARALLEL SAFE; CREATE OR REPLACE FUNCTION oracle.mod(smallint, smallint) RETURNS SMALLINT AS $$ SELECT CASE $2 WHEN 0 THEN $1 ELSE pg_catalog.MOD($1, $2) END; $$ LANGUAGE SQL IMMUTABLE; CREATE OR REPLACE FUNCTION oracle.mod(int, int) RETURNS INT AS $$ SELECT CASE $2 WHEN 0 THEN $1 ELSE pg_catalog.MOD($1, $2) END; $$ LANGUAGE SQL IMMUTABLE; CREATE OR REPLACE FUNCTION oracle.mod(bigint, bigint) RETURNS BIGINT AS $$ SELECT CASE $2 WHEN 0 THEN $1 ELSE pg_catalog.MOD($1, $2) END; $$ LANGUAGE sql IMMUTABLE; CREATE OR REPLACE FUNCTION oracle.mod(numeric, numeric) RETURNS NUMERIC AS $$ SELECT CASE $2 WHEN 0 THEN $1 ELSE pg_catalog.MOD($1, $2) END; $$ LANGUAGE sql IMMUTABLE; CREATE OR REPLACE FUNCTION oracle.remainder(smallint, smallint) RETURNS smallint AS 'MODULE_PATHNAME','orafce_reminder_smallint' LANGUAGE C IMMUTABLE STRICT; CREATE OR REPLACE FUNCTION oracle.remainder(int, int) RETURNS int AS 'MODULE_PATHNAME','orafce_reminder_int' LANGUAGE C IMMUTABLE STRICT; CREATE OR REPLACE FUNCTION oracle.remainder(bigint, bigint) RETURNS bigint AS 'MODULE_PATHNAME','orafce_reminder_bigint' LANGUAGE C IMMUTABLE STRICT; CREATE OR REPLACE FUNCTION oracle.remainder(numeric, numeric) RETURNS numeric AS 'MODULE_PATHNAME','orafce_reminder_numeric' LANGUAGE C IMMUTABLE STRICT; ALTER FUNCTION oracle.mod(smallint, smallint) PARALLEL SAFE; ALTER FUNCTION oracle.mod(int, int) PARALLEL SAFE; ALTER FUNCTION oracle.mod(bigint, bigint) PARALLEL SAFE; ALTER FUNCTION oracle.mod(numeric, numeric) PARALLEL SAFE; ALTER FUNCTION oracle.remainder(smallint, smallint) PARALLEL SAFE; ALTER FUNCTION oracle.remainder(int, int) PARALLEL SAFE; ALTER FUNCTION oracle.remainder(bigint, bigint) PARALLEL SAFE; ALTER FUNCTION oracle.remainder(numeric, numeric) PARALLEL SAFE; --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 PARALLEL SAFE; CREATE OR REPLACE FUNCTION oracle.subtract(oracle.date, integer) RETURNS timestamp AS $$ SELECT $1 - interval '1 day' * $2; $$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE; CREATE OR REPLACE FUNCTION oracle.add_days_to_timestamp(oracle.date,bigint) RETURNS timestamp AS $$ SELECT $1 + interval '1 day' * $2; $$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE; CREATE OR REPLACE FUNCTION oracle.subtract(oracle.date, bigint) RETURNS timestamp AS $$ SELECT $1 - interval '1 day' * $2; $$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE; CREATE OR REPLACE FUNCTION oracle.add_days_to_timestamp(oracle.date,smallint) RETURNS timestamp AS $$ SELECT $1 + interval '1 day' * $2; $$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE; CREATE OR REPLACE FUNCTION oracle.subtract(oracle.date, smallint) RETURNS timestamp AS $$ SELECT $1 - interval '1 day' * $2; $$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE; CREATE OR REPLACE FUNCTION oracle.add_days_to_timestamp(oracle.date,numeric) RETURNS timestamp AS $$ SELECT $1 + interval '1 day' * $2; $$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE; CREATE OR REPLACE FUNCTION oracle.subtract(oracle.date, numeric) RETURNS timestamp AS $$ SELECT $1 - interval '1 day' * $2; $$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE; 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 PARALLEL SAFE; 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 (oracle.add_months($1::pg_catalog.date, $2) + $1::time)::oracle.date; $$ LANGUAGE SQL IMMUTABLE STRICT PARALLEL SAFE; 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 PARALLEL SAFE; CREATE FUNCTION oracle.months_between(TIMESTAMP WITH TIME ZONE,TIMESTAMP WITH TIME ZONE) RETURNS NUMERIC AS $$ SELECT oracle.months_between($1::pg_catalog.date,$2::pg_catalog.date); $$ LANGUAGE SQL IMMUTABLE STRICT PARALLEL SAFE; CREATE FUNCTION oracle.next_day(TIMESTAMP WITH TIME ZONE,INTEGER) RETURNS TIMESTAMP AS $$ SELECT (oracle.next_day($1::pg_catalog.date,$2) + $1::time)::oracle.date; $$ LANGUAGE SQL IMMUTABLE STRICT PARALLEL SAFE; CREATE FUNCTION oracle.next_day(TIMESTAMP WITH TIME ZONE,TEXT) RETURNS TIMESTAMP AS $$ SELECT (oracle.next_day($1::pg_catalog.date,$2) + $1::time)::oracle.date; $$ LANGUAGE SQL IMMUTABLE STRICT PARALLEL SAFE; CREATE FUNCTION oracle.to_date(TEXT) RETURNS oracle.date AS $$ SELECT oracle.orafce__obsolete_to_date($1)::oracle.date; $$ LANGUAGE SQL STABLE STRICT PARALLEL SAFE; CREATE FUNCTION oracle.to_date(TEXT, TEXT) RETURNS oracle.date AS $$ SELECT oracle.orafce__obsolete_to_date($1, $2)::oracle.date; $$ LANGUAGE SQL STABLE STRICT PARALLEL SAFE; CREATE FUNCTION oracle.to_date(integer, TEXT) RETURNS oracle.date AS $$ SELECT oracle.orafce__obsolete_to_date($1::text, $2)::oracle.date; $$ LANGUAGE SQL STABLE STRICT PARALLEL SAFE; CREATE FUNCTION oracle.to_char(timestamp) RETURNS TEXT AS 'MODULE_PATHNAME','orafce_to_char_timestamp' LANGUAGE C STABLE STRICT PARALLEL SAFE; 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 PARALLEL SAFE; 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 PARALLEL SAFE; 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 PARALLEL SAFE; COMMENT ON FUNCTION oracle.dbtimezone() IS 'Ruturns server time zone (orafce.timezone)'; CREATE FUNCTION oracle.sys_extract_utc(timestamp with time zone) RETURNS timestamp without time zone AS 'MODULE_PATHNAME','orafce_sys_extract_utc' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION oracle.sysdate() IS 'Extract timestamp at utc time zone'; CREATE FUNCTION oracle.sys_extract_utc(oracle.date) RETURNS oracle.date AS 'MODULE_PATHNAME','orafce_sys_extract_utc_oracle_date' LANGUAGE C STABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION oracle.sysdate() IS 'Extract timestamp at utc time zone'; -- emulation of dual table CREATE VIEW oracle.dual AS SELECT 'X'::varchar AS dummy; REVOKE ALL ON oracle.dual FROM PUBLIC; GRANT SELECT, REFERENCES ON oracle.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 oracle.nvl(anyelement, anyelement) RETURNS anyelement AS 'MODULE_PATHNAME','ora_nvl' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.nvl2("any", anyelement, anyelement) RETURNS anyelement AS 'MODULE_PATHNAME','ora_nvl2' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.nvl2("any", text, text) RETURNS text AS 'MODULE_PATHNAME','ora_nvl2' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, text) RETURNS text AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, text, text) RETURNS text AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, text, anyelement, text) RETURNS text AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, text, anyelement, text, text) RETURNS text AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, text, anyelement, text, anyelement, text) RETURNS text AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, text, anyelement, text, anyelement, text, text) RETURNS text AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, bpchar) RETURNS bpchar AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, bpchar, bpchar) RETURNS bpchar AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, bpchar, anyelement, bpchar) RETURNS bpchar AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, bpchar, anyelement, bpchar, bpchar) RETURNS bpchar AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, bpchar, anyelement, bpchar, anyelement, bpchar) RETURNS bpchar AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, bpchar, anyelement, bpchar, anyelement, bpchar, bpchar) RETURNS bpchar AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, integer) RETURNS integer AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, integer, integer) RETURNS integer AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, integer, anyelement, integer) RETURNS integer AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, integer, anyelement, integer, integer) RETURNS integer AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, integer, anyelement, integer, anyelement, integer) RETURNS integer AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, integer, anyelement, integer, anyelement, integer, integer) RETURNS integer AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, bigint) RETURNS bigint AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, bigint, bigint) RETURNS bigint AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, bigint, anyelement, bigint) RETURNS bigint AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, bigint, anyelement, bigint, bigint) RETURNS bigint AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, bigint, anyelement, bigint, anyelement, bigint) RETURNS bigint AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, bigint, anyelement, bigint, anyelement, bigint, bigint) RETURNS bigint AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, numeric) RETURNS numeric AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, numeric, numeric) RETURNS numeric AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, numeric, anyelement, numeric) RETURNS numeric AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, numeric, anyelement, numeric, numeric) RETURNS numeric AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, numeric, anyelement, numeric, anyelement, numeric) RETURNS numeric AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, numeric, anyelement, numeric, anyelement, numeric, numeric) RETURNS numeric AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, date) RETURNS date AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, date, date) RETURNS date AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, date, anyelement, date) RETURNS date AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, date, anyelement, date, date) RETURNS date AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, date, anyelement, date, anyelement, date) RETURNS date AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, date, anyelement, date, anyelement, date, date) RETURNS date AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, time) RETURNS time AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, time, time) RETURNS time AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, time, anyelement, time) RETURNS time AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, time, anyelement, time, time) RETURNS time AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, time, anyelement, time, anyelement, time) RETURNS time AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, time, anyelement, time, anyelement, time, time) RETURNS time AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, timestamp) RETURNS timestamp AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, timestamp, timestamp) RETURNS timestamp AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, timestamp, anyelement, timestamp) RETURNS timestamp AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, timestamp, anyelement, timestamp, timestamp) RETURNS timestamp AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, timestamp, anyelement, timestamp, anyelement, timestamp) RETURNS timestamp AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, timestamp, anyelement, timestamp, anyelement, timestamp, timestamp) RETURNS timestamp AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, timestamptz) RETURNS timestamptz AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, timestamptz, timestamptz) RETURNS timestamptz AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, timestamptz, anyelement, timestamptz) RETURNS timestamptz AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, timestamptz, anyelement, timestamptz, timestamptz) RETURNS timestamptz AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, timestamptz, anyelement, timestamptz, anyelement, timestamptz) RETURNS timestamptz AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.decode(anyelement, anyelement, timestamptz, anyelement, timestamptz, anyelement, timestamptz, timestamptz) RETURNS timestamptz AS 'MODULE_PATHNAME', 'ora_decode' LANGUAGE C IMMUTABLE PARALLEL SAFE; 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 PARALLEL SAFE; 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 PARALLEL SAFE; 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 PARALLEL SAFE; 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 PARALLEL SAFE; 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 PARALLEL SAFE; 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.waitany(OUT name text, OUT message text, OUT status integer) RETURNS record AS 'MODULE_PATHNAME','dbms_alert_waitany_maxwait' LANGUAGE C VOLATILE; COMMENT ON FUNCTION dbms_alert.waitany(OUT text, OUT text, OUT integer) IS 'Wait for any signal'; CREATE FUNCTION dbms_alert.waitone(name text, OUT message text, OUT status integer) RETURNS record AS 'MODULE_PATHNAME','dbms_alert_waitone_maxwait' LANGUAGE C VOLATILE; COMMENT ON FUNCTION dbms_alert.waitone(text, OUT text, OUT integer) 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.signal(_event text, _message text) RETURNS void AS 'MODULE_PATHNAME','dbms_alert_signal' LANGUAGE C; 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 FUNCTION dbms_utility.get_time() RETURNS int AS 'MODULE_PATHNAME','dbms_utility_get_time' LANGUAGE C VOLATILE; COMMENT ON FUNCTION dbms_utility.get_time() IS 'Returns the number of hundredths of seconds that have elapsed since point in time'; 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; 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; 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, dirname text unique); REVOKE ALL ON utl_file.utl_file_dir FROM PUBLIC; /* allow only read on utl_file.utl_file_dir to unprivileged users */ GRANT SELECT ON TABLE utl_file.utl_file_dir TO 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 a 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 a 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 VOLATILE; 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 oracle.dump(text) RETURNS varchar AS 'MODULE_PATHNAME', 'orafce_dump' LANGUAGE C; CREATE FUNCTION oracle.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 oracle.listagg1_transfn(internal, text) RETURNS internal AS 'MODULE_PATHNAME','orafce_listagg1_transfn' LANGUAGE C IMMUTABLE; CREATE FUNCTION oracle.wm_concat_transfn(internal, text) RETURNS internal AS 'MODULE_PATHNAME','orafce_wm_concat_transfn' LANGUAGE C IMMUTABLE; CREATE FUNCTION oracle.listagg2_transfn(internal, text, text) RETURNS internal AS 'MODULE_PATHNAME','orafce_listagg2_transfn' LANGUAGE C IMMUTABLE; CREATE FUNCTION oracle.listagg_finalfn(internal) RETURNS text AS 'MODULE_PATHNAME','orafce_listagg_finalfn' LANGUAGE C IMMUTABLE; CREATE AGGREGATE oracle.listagg(text) ( SFUNC=oracle.listagg1_transfn, STYPE=internal, FINALFUNC=oracle.listagg_finalfn ); /* * Undocumented function wm_concat - removed from * Oracle 12c. */ CREATE AGGREGATE oracle.wm_concat(text) ( SFUNC=oracle.wm_concat_transfn, STYPE=internal, FINALFUNC=oracle.listagg_finalfn ); CREATE AGGREGATE oracle.listagg(text, text) ( SFUNC=oracle.listagg2_transfn, STYPE=internal, FINALFUNC=oracle.listagg_finalfn ); CREATE FUNCTION oracle.median4_transfn(internal, real) RETURNS internal AS 'MODULE_PATHNAME','orafce_median4_transfn' LANGUAGE C IMMUTABLE; CREATE FUNCTION oracle.median4_finalfn(internal) RETURNS real AS 'MODULE_PATHNAME','orafce_median4_finalfn' LANGUAGE C IMMUTABLE; CREATE FUNCTION oracle.median8_transfn(internal, double precision) RETURNS internal AS 'MODULE_PATHNAME','orafce_median8_transfn' LANGUAGE C IMMUTABLE; CREATE FUNCTION oracle.median8_finalfn(internal) RETURNS double precision AS 'MODULE_PATHNAME','orafce_median8_finalfn' LANGUAGE C IMMUTABLE; CREATE AGGREGATE oracle.median(real) ( SFUNC=oracle.median4_transfn, STYPE=internal, FINALFUNC=oracle.median4_finalfn ); CREATE AGGREGATE oracle.median(double precision) ( SFUNC=oracle.median8_transfn, STYPE=internal, FINALFUNC=oracle.median8_finalfn ); -- oracle.varchar2 type support CREATE FUNCTION oracle.varchar2in(cstring,oid,integer) RETURNS oracle.varchar2 AS 'MODULE_PATHNAME','varchar2in' LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.varchar2out(oracle.varchar2) RETURNS CSTRING AS 'MODULE_PATHNAME','varchar2out' LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.varchar2_transform(internal) RETURNS internal AS 'MODULE_PATHNAME','orafce_varchar_transform' LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.varchar2recv(internal,oid,integer) RETURNS oracle.varchar2 AS 'MODULE_PATHNAME','varchar2recv' LANGUAGE C STRICT STABLE PARALLEL SAFE; CREATE FUNCTION oracle.varchar2send(oracle.varchar2) RETURNS bytea AS 'varcharsend' LANGUAGE internal STRICT STABLE PARALLEL SAFE; CREATE FUNCTION oracle.varchar2typmodin(cstring[]) RETURNS integer AS 'varchartypmodin' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.varchar2typmodout(integer) RETURNS CSTRING AS 'varchartypmodout' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.varchar2(oracle.varchar2,integer,boolean) RETURNS oracle.varchar2 AS 'MODULE_PATHNAME','varchar2' LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE; /* CREATE TYPE */ CREATE TYPE oracle.varchar2 ( internallength = VARIABLE, input = oracle.varchar2in, output = oracle.varchar2out, receive = oracle.varchar2recv, send = oracle.varchar2send, category = 'S', typmod_in = oracle.varchar2typmodin, typmod_out = oracle.varchar2typmodout, collatable = true, storage = extended ); CREATE FUNCTION oracle.orafce_concat2(oracle.varchar2, oracle.varchar2) RETURNS oracle.varchar2 AS 'MODULE_PATHNAME','orafce_concat2' LANGUAGE C STABLE PARALLEL SAFE; /* CREATE CAST */ CREATE CAST (oracle.varchar2 AS text) WITHOUT FUNCTION AS IMPLICIT; CREATE CAST (text AS oracle.varchar2) WITHOUT FUNCTION AS IMPLICIT; CREATE CAST (oracle.varchar2 AS char) WITHOUT FUNCTION AS IMPLICIT; CREATE CAST (char AS oracle.varchar2) WITHOUT FUNCTION AS IMPLICIT; CREATE CAST (oracle.varchar2 AS varchar) WITHOUT FUNCTION AS IMPLICIT; CREATE CAST (varchar AS oracle.varchar2) WITHOUT FUNCTION AS IMPLICIT; CREATE CAST (oracle.varchar2 AS oracle.varchar2) WITH FUNCTION oracle.varchar2(oracle.varchar2,integer,boolean) AS IMPLICIT; CREATE CAST (oracle.varchar2 AS real) WITH INOUT AS IMPLICIT; CREATE CAST (real AS oracle.varchar2) WITH INOUT AS IMPLICIT; CREATE CAST (oracle.varchar2 AS double precision) WITH INOUT AS IMPLICIT; CREATE CAST (double precision AS oracle.varchar2) WITH INOUT AS IMPLICIT; CREATE CAST (oracle.varchar2 AS integer) WITH INOUT AS IMPLICIT; CREATE CAST (integer AS oracle.varchar2) WITH INOUT AS IMPLICIT; CREATE CAST (oracle.varchar2 AS smallint) WITH INOUT AS IMPLICIT; CREATE CAST (smallint AS oracle.varchar2) WITH INOUT AS IMPLICIT; CREATE CAST (oracle.varchar2 AS bigint) WITH INOUT AS IMPLICIT; CREATE CAST (bigint AS oracle.varchar2) WITH INOUT AS IMPLICIT; CREATE CAST (oracle.varchar2 AS numeric) WITH INOUT AS IMPLICIT; CREATE CAST (numeric AS oracle.varchar2) WITH INOUT AS IMPLICIT; CREATE CAST (oracle.varchar2 AS date) WITH INOUT AS IMPLICIT; CREATE CAST (date AS oracle.varchar2) WITH INOUT AS IMPLICIT; CREATE CAST (oracle.varchar2 AS timestamp) WITH INOUT AS IMPLICIT; CREATE CAST (timestamp AS oracle.varchar2) WITH INOUT AS IMPLICIT; CREATE CAST (oracle.varchar2 AS interval) WITH INOUT AS IMPLICIT; CREATE CAST (interval AS oracle.varchar2) WITH INOUT AS IMPLICIT; do $$ BEGIN IF EXISTS(SELECT * FROM pg_settings WHERE name = 'server_version_num' AND setting::int >= 120000) THEN EXECUTE $_$ALTER FUNCTION oracle.varchar2(oracle.varchar2, integer, boolean) SUPPORT oracle.varchar2_transform$_$; ELSE UPDATE pg_proc SET protransform= 'oracle.varchar2_transform'::regproc::oid WHERE proname='varchar2'; INSERT INTO pg_depend (classid, objid, objsubid, refclassid, refobjid, refobjsubid, deptype) VALUES('pg_proc'::regclass::oid, 'oracle.varchar2'::regproc::oid, 0, 'pg_proc'::regclass::oid, 'oracle.varchar2_transform'::regproc::oid, 0, 'n'); END IF; END $$; -- string functions for varchar2 type -- these are 'byte' versions of corresponsing text/varchar functions CREATE OR REPLACE FUNCTION oracle.substrb(oracle.varchar2, integer, integer) RETURNS oracle.varchar2 AS 'MODULE_PATHNAME','oracle_substrb3' LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE; COMMENT ON FUNCTION oracle.substrb(oracle.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 oracle.substrb(oracle.varchar2, integer) RETURNS oracle.varchar2 AS 'MODULE_PATHNAME','oracle_substrb2' LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE; COMMENT ON FUNCTION oracle.substrb(oracle.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 oracle.lengthb(oracle.varchar2) RETURNS integer AS 'byteaoctetlen' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE; COMMENT ON FUNCTION oracle.lengthb(oracle.varchar2) IS 'returns byte length of the input varchar2 string'; CREATE OR REPLACE FUNCTION oracle.strposb(oracle.varchar2, oracle.varchar2) RETURNS integer AS 'byteapos' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE; COMMENT ON FUNCTION oracle.strposb(oracle.varchar2, oracle.varchar2) IS 'returns the byte position of a specified string in the input varchar2 string'; -- oracle.nvarchar2 type support CREATE FUNCTION oracle.nvarchar2in(cstring,oid,integer) RETURNS oracle.nvarchar2 AS 'MODULE_PATHNAME','nvarchar2in' LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.nvarchar2out(oracle.nvarchar2) RETURNS CSTRING AS 'MODULE_PATHNAME','nvarchar2out' LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.nvarchar2_transform(internal) RETURNS internal AS 'MODULE_PATHNAME','orafce_varchar_transform' LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.nvarchar2recv(internal,oid,integer) RETURNS oracle.nvarchar2 AS 'MODULE_PATHNAME','nvarchar2recv' LANGUAGE C STRICT STABLE PARALLEL SAFE; CREATE FUNCTION oracle.nvarchar2send(oracle.nvarchar2) RETURNS bytea AS 'varcharsend' LANGUAGE internal STRICT STABLE PARALLEL SAFE; CREATE FUNCTION oracle.nvarchar2typmodin(cstring[]) RETURNS integer AS 'varchartypmodin' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.nvarchar2typmodout(integer) RETURNS CSTRING AS 'varchartypmodout' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.nvarchar2(oracle.nvarchar2,integer,boolean) RETURNS oracle.nvarchar2 AS 'MODULE_PATHNAME','nvarchar2' LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE; /* CREATE TYPE */ CREATE TYPE oracle.nvarchar2 ( internallength = VARIABLE, input = oracle.nvarchar2in, output = oracle.nvarchar2out, receive = oracle.nvarchar2recv, send = oracle.nvarchar2send, category = 'S', typmod_in = oracle.nvarchar2typmodin, typmod_out = oracle.nvarchar2typmodout, collatable = true, storage = extended ); CREATE FUNCTION oracle.orafce_concat2(oracle.nvarchar2, oracle.nvarchar2) RETURNS oracle.nvarchar2 AS 'MODULE_PATHNAME','orafce_concat2' LANGUAGE C IMMUTABLE PARALLEL SAFE; /* CREATE CAST */ CREATE CAST (oracle.nvarchar2 AS text) WITHOUT FUNCTION AS IMPLICIT; CREATE CAST (text AS oracle.nvarchar2) WITHOUT FUNCTION AS IMPLICIT; CREATE CAST (oracle.nvarchar2 AS char) WITHOUT FUNCTION AS IMPLICIT; CREATE CAST (char AS oracle.nvarchar2) WITHOUT FUNCTION AS IMPLICIT; CREATE CAST (oracle.nvarchar2 AS varchar) WITHOUT FUNCTION AS IMPLICIT; CREATE CAST (varchar AS oracle.nvarchar2) WITHOUT FUNCTION AS IMPLICIT; CREATE CAST (oracle.nvarchar2 AS oracle.nvarchar2) WITH FUNCTION oracle.nvarchar2(oracle.nvarchar2, integer, boolean) AS IMPLICIT; CREATE CAST (oracle.nvarchar2 AS real) WITH INOUT AS IMPLICIT; CREATE CAST (real AS oracle.nvarchar2) WITH INOUT AS IMPLICIT; CREATE CAST (oracle.nvarchar2 AS double precision) WITH INOUT AS IMPLICIT; CREATE CAST (double precision AS oracle.nvarchar2) WITH INOUT AS IMPLICIT; CREATE CAST (oracle.nvarchar2 AS integer) WITH INOUT AS IMPLICIT; CREATE CAST (integer AS oracle.nvarchar2) WITH INOUT AS IMPLICIT; CREATE CAST (oracle.nvarchar2 AS smallint) WITH INOUT AS IMPLICIT; CREATE CAST (smallint AS oracle.nvarchar2) WITH INOUT AS IMPLICIT; CREATE CAST (oracle.nvarchar2 AS bigint) WITH INOUT AS IMPLICIT; CREATE CAST (bigint AS oracle.nvarchar2) WITH INOUT AS IMPLICIT; CREATE CAST (oracle.nvarchar2 AS numeric) WITH INOUT AS IMPLICIT; CREATE CAST (numeric AS oracle.nvarchar2) WITH INOUT AS IMPLICIT; CREATE CAST (oracle.nvarchar2 AS date) WITH INOUT AS IMPLICIT; CREATE CAST (date AS oracle.nvarchar2) WITH INOUT AS IMPLICIT; CREATE CAST (oracle.nvarchar2 AS timestamp) WITH INOUT AS IMPLICIT; CREATE CAST (timestamp AS oracle.nvarchar2) WITH INOUT AS IMPLICIT; CREATE CAST (oracle.nvarchar2 AS interval) WITH INOUT AS IMPLICIT; CREATE CAST (interval AS oracle.nvarchar2) WITH INOUT AS IMPLICIT; do $$ BEGIN IF EXISTS(SELECT * FROM pg_settings WHERE name = 'server_version_num' AND setting::int >= 120000) THEN EXECUTE $_$ALTER FUNCTION oracle.nvarchar2(oracle.nvarchar2, integer, boolean) SUPPORT oracle.nvarchar2_transform$_$; ELSE UPDATE pg_proc SET protransform= 'oracle.nvarchar2_transform'::regproc::oid WHERE proname='nvarchar2'; INSERT INTO pg_depend (classid, objid, objsubid, refclassid, refobjid, refobjsubid, deptype) VALUES('pg_proc'::regclass::oid, 'oracle.nvarchar2'::regproc::oid, 0, 'pg_proc'::regclass::oid, 'oracle.nvarchar2_transform'::regproc::oid, 0, 'n'); END IF; END $$; /* * Note - a procedure keyword is depraceted from PostgreSQL 11, but it used * because older release doesn't know function. * */ CREATE OPERATOR oracle.|| (procedure = oracle.orafce_concat2, leftarg = oracle.varchar2, rightarg = oracle.varchar2); CREATE OPERATOR oracle.|| (procedure = oracle.orafce_concat2, leftarg = oracle.nvarchar2, rightarg = oracle.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 PARALLEL SAFE ; CREATE FUNCTION oracle.lpad(char, integer, text) RETURNS text AS 'MODULE_PATHNAME','orafce_lpad' LANGUAGE 'c' STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.lpad(char, integer, oracle.varchar2) RETURNS text AS 'MODULE_PATHNAME','orafce_lpad' LANGUAGE 'c' STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.lpad(char, integer, oracle.nvarchar2) RETURNS text AS 'MODULE_PATHNAME','orafce_lpad' LANGUAGE 'c' STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.lpad(char, integer) RETURNS text AS $$ SELECT oracle.lpad($1, $2, ' '::text); $$ LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.lpad(text, integer, char) RETURNS text AS 'MODULE_PATHNAME','orafce_lpad' LANGUAGE 'c' STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.lpad(oracle.varchar2, integer, char) RETURNS text AS 'MODULE_PATHNAME','orafce_lpad' LANGUAGE 'c' STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.lpad(oracle.nvarchar2, integer, char) RETURNS text AS 'MODULE_PATHNAME','orafce_lpad' LANGUAGE 'c' STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.lpad(text, integer, text) RETURNS text AS 'MODULE_PATHNAME','orafce_lpad' LANGUAGE 'c' STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.lpad(text, integer, oracle.varchar2) RETURNS text AS 'MODULE_PATHNAME','orafce_lpad' LANGUAGE 'c' STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.lpad(text, integer, oracle.nvarchar2) RETURNS text AS 'MODULE_PATHNAME','orafce_lpad' LANGUAGE 'c' STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.lpad(text, integer) RETURNS text AS $$ SELECT oracle.lpad($1, $2, ' '::text); $$ LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.lpad(oracle.varchar2, integer, text) RETURNS text AS 'MODULE_PATHNAME','orafce_lpad' LANGUAGE 'c' STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.lpad(oracle.varchar2, integer, oracle.varchar2) RETURNS text AS 'MODULE_PATHNAME','orafce_lpad' LANGUAGE 'c' STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.lpad(oracle.varchar2, integer, oracle.nvarchar2) RETURNS text AS 'MODULE_PATHNAME','orafce_lpad' LANGUAGE 'c' STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.lpad(oracle.varchar2, integer) RETURNS text AS $$ SELECT oracle.lpad($1, $2, ' '::text); $$ LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.lpad(oracle.nvarchar2, integer, text) RETURNS text AS 'MODULE_PATHNAME','orafce_lpad' LANGUAGE 'c' STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.lpad(oracle.nvarchar2, integer, oracle.varchar2) RETURNS text AS 'MODULE_PATHNAME','orafce_lpad' LANGUAGE 'c' STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.lpad(oracle.nvarchar2, integer, oracle.nvarchar2) RETURNS text AS 'MODULE_PATHNAME','orafce_lpad' LANGUAGE 'c' STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.lpad(oracle.nvarchar2, integer) RETURNS text AS $$ SELECT oracle.lpad($1, $2, ' '::text); $$ LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE ; /* 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 PARALLEL SAFE ; CREATE FUNCTION oracle.rpad(char, integer, text) RETURNS text AS 'MODULE_PATHNAME','orafce_rpad' LANGUAGE 'c' STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.rpad(char, integer, oracle.varchar2) RETURNS text AS 'MODULE_PATHNAME','orafce_rpad' LANGUAGE 'c' STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.rpad(char, integer, oracle.nvarchar2) RETURNS text AS 'MODULE_PATHNAME','orafce_rpad' LANGUAGE 'c' STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.rpad(char, integer) RETURNS text AS $$ SELECT oracle.rpad($1, $2, ' '::text); $$ LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.rpad(text, integer, char) RETURNS text AS 'MODULE_PATHNAME','orafce_rpad' LANGUAGE 'c' STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.rpad(oracle.varchar2, integer, char) RETURNS text AS 'MODULE_PATHNAME','orafce_rpad' LANGUAGE 'c' STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.rpad(oracle.nvarchar2, integer, char) RETURNS text AS 'MODULE_PATHNAME','orafce_rpad' LANGUAGE 'c' STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.rpad(text, integer, text) RETURNS text AS 'MODULE_PATHNAME','orafce_rpad' LANGUAGE 'c' STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.rpad(text, integer, oracle.varchar2) RETURNS text AS 'MODULE_PATHNAME','orafce_rpad' LANGUAGE 'c' STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.rpad(text, integer, oracle.nvarchar2) RETURNS text AS 'MODULE_PATHNAME','orafce_rpad' LANGUAGE 'c' STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.rpad(text, integer) RETURNS text AS $$ SELECT oracle.rpad($1, $2, ' '::text); $$ LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.rpad(oracle.varchar2, integer, text) RETURNS text AS 'MODULE_PATHNAME','orafce_rpad' LANGUAGE 'c' STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.rpad(oracle.varchar2, integer, oracle.varchar2) RETURNS text AS 'MODULE_PATHNAME','orafce_rpad' LANGUAGE 'c' STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.rpad(oracle.varchar2, integer, oracle.nvarchar2) RETURNS text AS 'MODULE_PATHNAME','orafce_rpad' LANGUAGE 'c' STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.rpad(oracle.varchar2, integer) RETURNS text AS $$ SELECT oracle.rpad($1, $2, ' '::text); $$ LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.rpad(oracle.nvarchar2, integer, text) RETURNS text AS 'MODULE_PATHNAME','orafce_rpad' LANGUAGE 'c' STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.rpad(oracle.nvarchar2, integer, oracle.varchar2) RETURNS text AS 'MODULE_PATHNAME','orafce_rpad' LANGUAGE 'c' STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.rpad(oracle.nvarchar2, integer, oracle.nvarchar2) RETURNS text AS 'MODULE_PATHNAME','orafce_rpad' LANGUAGE 'c' STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.rpad(oracle.nvarchar2, integer) RETURNS text AS $$ SELECT oracle.rpad($1, $2, ' '::text); $$ LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE ; /* 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 PARALLEL SAFE ; CREATE FUNCTION oracle.ltrim(char, text) RETURNS text AS 'ltrim' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.ltrim(char, oracle.varchar2) RETURNS text AS 'ltrim' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.ltrim(char, oracle.nvarchar2) RETURNS text AS 'ltrim' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.ltrim(char) RETURNS text AS $$ SELECT oracle.ltrim($1, ' '::text) $$ LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.ltrim(text, char) RETURNS text AS 'ltrim' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.ltrim(text, text) RETURNS text AS 'ltrim' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.ltrim(text, oracle.varchar2) RETURNS text AS 'ltrim' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.ltrim(text, oracle.nvarchar2) RETURNS text AS 'ltrim' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.ltrim(text) RETURNS text AS $$ SELECT oracle.ltrim($1, ' '::text) $$ LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.ltrim(oracle.varchar2, char) RETURNS text AS 'ltrim' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.ltrim(oracle.varchar2, text) RETURNS text AS 'ltrim' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.ltrim(oracle.varchar2, oracle.varchar2) RETURNS text AS 'ltrim' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.ltrim(oracle.varchar2, oracle.nvarchar2) RETURNS text AS 'ltrim' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.ltrim(oracle.varchar2) RETURNS text AS $$ SELECT oracle.ltrim($1, ' '::text) $$ LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.ltrim(oracle.nvarchar2, char) RETURNS text AS 'ltrim' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.ltrim(oracle.nvarchar2, text) RETURNS text AS 'ltrim' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.ltrim(oracle.nvarchar2, oracle.varchar2) RETURNS text AS 'ltrim' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.ltrim(oracle.nvarchar2, oracle.nvarchar2) RETURNS text AS 'ltrim' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.ltrim(oracle.nvarchar2) RETURNS text AS $$ SELECT oracle.ltrim($1, ' '::text) $$ LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE ; /* RTRIM family */ CREATE FUNCTION oracle.rtrim(char, char) RETURNS text AS 'rtrim' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.rtrim(char, text) RETURNS text AS 'rtrim' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.rtrim(char, oracle.varchar2) RETURNS text AS 'rtrim' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.rtrim(char, oracle.nvarchar2) RETURNS text AS 'rtrim' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.rtrim(char) RETURNS text AS $$ SELECT oracle.rtrim($1, ' '::text) $$ LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.rtrim(text, char) RETURNS text AS 'rtrim' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.rtrim(text, text) RETURNS text AS 'rtrim' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.rtrim(text, oracle.varchar2) RETURNS text AS 'rtrim' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.rtrim(text, oracle.nvarchar2) RETURNS text AS 'rtrim' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.rtrim(text) RETURNS text AS $$ SELECT oracle.rtrim($1, ' '::text) $$ LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.rtrim(oracle.varchar2, char) RETURNS text AS 'rtrim' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.rtrim(oracle.varchar2, text) RETURNS text AS 'rtrim' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.rtrim(oracle.varchar2, oracle.varchar2) RETURNS text AS 'rtrim' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.rtrim(oracle.varchar2, oracle.nvarchar2) RETURNS text AS 'rtrim' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.rtrim(oracle.varchar2) RETURNS text AS $$ SELECT oracle.rtrim($1, ' '::text) $$ LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.rtrim(oracle.nvarchar2, char) RETURNS text AS 'rtrim' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.rtrim(oracle.nvarchar2, text) RETURNS text AS 'rtrim' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.rtrim(oracle.nvarchar2, oracle.varchar2) RETURNS text AS 'rtrim' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.rtrim(oracle.nvarchar2, oracle.nvarchar2) RETURNS text AS 'rtrim' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.rtrim(oracle.nvarchar2) RETURNS text AS $$ SELECT oracle.rtrim($1, ' '::text) $$ LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE ; /* BTRIM family */ CREATE FUNCTION oracle.btrim(char, char) RETURNS text AS 'btrim' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.btrim(char, text) RETURNS text AS 'btrim' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.btrim(char, oracle.varchar2) RETURNS text AS 'btrim' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.btrim(char, oracle.nvarchar2) RETURNS text AS 'btrim' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.btrim(char) RETURNS text AS $$ SELECT oracle.btrim($1, ' '::text) $$ LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.btrim(text, char) RETURNS text AS 'btrim' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.btrim(text, text) RETURNS text AS 'btrim' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.btrim(text, oracle.varchar2) RETURNS text AS 'btrim' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.btrim(text, oracle.nvarchar2) RETURNS text AS 'btrim' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.btrim(text) RETURNS text AS $$ SELECT oracle.btrim($1, ' '::text) $$ LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.btrim(oracle.varchar2, char) RETURNS text AS 'btrim' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.btrim(oracle.varchar2, text) RETURNS text AS 'btrim' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.btrim(oracle.varchar2, oracle.varchar2) RETURNS text AS 'btrim' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.btrim(oracle.varchar2, oracle.nvarchar2) RETURNS text AS 'btrim' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.btrim(oracle.varchar2) RETURNS text AS $$ SELECT oracle.btrim($1, ' '::text) $$ LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.btrim(oracle.nvarchar2, char) RETURNS text AS 'btrim' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.btrim(oracle.nvarchar2, text) RETURNS text AS 'btrim' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.btrim(oracle.nvarchar2, oracle.varchar2) RETURNS text AS 'btrim' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.btrim(oracle.nvarchar2, oracle.nvarchar2) RETURNS text AS 'btrim' LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE ; CREATE FUNCTION oracle.btrim(oracle.nvarchar2) RETURNS text AS $$ SELECT oracle.btrim($1, ' '::text) $$ LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE ; /* LENGTH */ CREATE FUNCTION oracle.length(char) RETURNS integer AS 'MODULE_PATHNAME','orafce_bpcharlen' LANGUAGE 'c' STRICT IMMUTABLE PARALLEL SAFE ; 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 oracle.trunc(value timestamp without time zone, fmt text) RETURNS timestamp without time zone AS 'MODULE_PATHNAME', 'ora_timestamp_trunc' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION oracle.trunc(timestamp without time zone, text) IS 'truncate date according to the specified format'; CREATE FUNCTION oracle.round(value timestamp without time zone, fmt text) RETURNS timestamp without time zone AS 'MODULE_PATHNAME','ora_timestamp_round' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION oracle.round(timestamp with time zone, text) IS 'round dates according to the specified format'; CREATE FUNCTION oracle.round(value timestamp without time zone) RETURNS timestamp without time zone AS $$ SELECT oracle.round($1, 'DDD'); $$ LANGUAGE SQL IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION oracle.round(timestamp without time zone) IS 'will round dates according to the specified format'; CREATE FUNCTION oracle.trunc(value timestamp without time zone) RETURNS timestamp without time zone AS $$ SELECT oracle.trunc($1, 'DDD'); $$ LANGUAGE SQL IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION oracle.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 PARALLEL SAFE; CREATE OR REPLACE FUNCTION oracle.trunc(double precision, int) RETURNS numeric AS $$SELECT pg_catalog.trunc($1::numeric, $2)$$ LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE; CREATE OR REPLACE FUNCTION oracle.round(float4, int) RETURNS numeric AS $$SELECT pg_catalog.round($1::numeric, $2)$$ LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE; CREATE OR REPLACE FUNCTION oracle.trunc(float4, int) RETURNS numeric AS $$SELECT pg_catalog.trunc($1::numeric, $2)$$ LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE; 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 PARALLEL SAFE; 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 PARALLEL SAFE; 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 PARALLEL SAFE; 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 PARALLEL SAFE; CREATE OR REPLACE FUNCTION oracle.nvl(bigint, int) RETURNS bigint AS $$ SELECT coalesce($1, $2) $$ LANGUAGE sql IMMUTABLE PARALLEL SAFE; CREATE OR REPLACE FUNCTION oracle.nvl(numeric, int) RETURNS numeric AS $$ SELECT coalesce($1, $2) $$ LANGUAGE sql IMMUTABLE PARALLEL SAFE; CREATE OR REPLACE FUNCTION oracle.nvl(int, int) RETURNS int AS $$ SELECT coalesce($1, $2) $$ LANGUAGE sql IMMUTABLE PARALLEL SAFE; CREATE OR REPLACE FUNCTION oracle.nvl(double precision, int) RETURNS double precision AS $$ SELECT coalesce($1, $2) $$ LANGUAGE sql IMMUTABLE PARALLEL SAFE; CREATE OR REPLACE FUNCTION oracle.numtodsinterval(double precision, text) RETURNS interval AS $$ SELECT $1 * ('1' || $2)::interval $$ LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE; CREATE OR REPLACE FUNCTION oracle.replace_empty_strings() RETURNS TRIGGER AS 'MODULE_PATHNAME','orafce_replace_empty_strings' LANGUAGE 'c'; CREATE OR REPLACE FUNCTION oracle.replace_null_strings() RETURNS TRIGGER AS 'MODULE_PATHNAME','orafce_replace_null_strings' LANGUAGE 'c'; CREATE OR REPLACE FUNCTION oracle.unistr(text) RETURNS text AS 'MODULE_PATHNAME','orafce_unistr' LANGUAGE 'c' PARALLEL SAFE; -- Translate Oracle regexp modifier into PostgreSQl ones -- Append the global modifier if $2 is true. Used internally -- by regexp_*() functions bellow. CREATE OR REPLACE FUNCTION oracle.translate_oracle_modifiers(text, bool) RETURNS text AS $$ DECLARE modifiers text := ''; BEGIN IF $1 IS NOT NULL THEN -- Check that we don't have modifier not supported by Oracle IF $1 ~ '[^icnsmx]' THEN -- Modifier 's' is not supported by Oracle but it is a synonym -- of 'n', we translate 'n' into 's' bellow. It is safe to allow it. RAISE EXCEPTION 'argument ''flags'' has unsupported modifier(s).'; END IF; -- Oracle 'n' modifier correspond to 's' POSIX modifier -- Oracle 'm' modifier correspond to 'n' POSIX modifier modifiers := translate($1, 'nm', 'sn'); END IF; IF $2 THEN modifiers := modifiers || 'g'; END IF; RETURN modifiers; END; $$ LANGUAGE plpgsql; -- REGEXP_LIKE( string text, pattern text) -> boolean -- If one of the param is NULL returns NULL, declared STRICT CREATE OR REPLACE FUNCTION oracle.regexp_like(text, text) RETURNS boolean AS $$ -- Oracle default behavior is newline-sensitive, -- PostgreSQL not, so force 'p' modifier to affect -- newline-sensitivity but not ^ and $ search. SELECT CASE WHEN (count(*) > 0) THEN true ELSE false END FROM regexp_matches($1, $2, 'p'); $$ LANGUAGE 'sql' STRICT IMMUTABLE PARALLEL SAFE; -- REGEXP_LIKE( string text, pattern text, flags text ) -> boolean CREATE OR REPLACE FUNCTION oracle.regexp_like(text, text, text) RETURNS boolean AS $$ DECLARE modifiers text; BEGIN -- Only modifier can be NULL IF $1 IS NULL OR $2 IS NULL THEN RETURN NULL; END IF; modifiers := oracle.translate_oracle_modifiers($3, false); IF (regexp_matches($1, $2, modifiers))[1] IS NOT NULL THEN RETURN true; END IF; RETURN false; END; $$ LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE; -- regexp_count_pattern_fix: replace any occurence of a dot into a [^\n] pattern. CREATE OR REPLACE FUNCTION oracle.regexp_count_pattern_fix(text) RETURNS text AS $$ DECLARE v_pattern text; BEGIN -- Replace any occurences of a dot by [^\n] -- to have the same behavior as Oracle v_pattern := regexp_replace($1, '\\\.', '#ESCDOT#', 'g'); v_pattern := regexp_replace(v_pattern, '\.', '[^\n]', 'g'); v_pattern := regexp_replace(v_pattern, '#ESCDOT#', '\.', 'g'); RETURN v_pattern; END; $$ LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE; -- REGEXP_COUNT( string text, pattern text ) -> integer CREATE OR REPLACE FUNCTION oracle.regexp_count(text, text) RETURNS integer AS $$ -- Oracle default behavior is newline-sensitive, -- PostgreSQL not, so force 'p' modifier to affect -- newline-sensitivity but not ^ and $ search. SELECT count(*)::integer FROM regexp_matches($1, oracle.regexp_count_pattern_fix($2), 'sg'); $$ LANGUAGE 'sql' STRICT IMMUTABLE PARALLEL SAFE; -- REGEXP_COUNT( string text, pattern text, position int ) -> integer CREATE OR REPLACE FUNCTION oracle.regexp_count(text, text, integer) RETURNS integer AS $$ DECLARE v_cnt integer; v_pattern text; BEGIN -- Check numeric arguments IF $3 < 1 THEN RAISE EXCEPTION 'argument ''position'' must be a number greater than 0'; END IF; v_pattern := '(' || oracle.regexp_count_pattern_fix($2) || ')'; -- Oracle default behavior is newline-sensitive, -- PostgreSQL not, so force 's' modifier to affect -- newline-sensitivity but not ^ and $ search. v_cnt := (SELECT count(*)::integer FROM regexp_matches(substr($1, $3), v_pattern, 'sg')); RETURN v_cnt; END; $$ LANGUAGE plpgsql STRICT IMMUTABLE PARALLEL SAFE; -- REGEXP_COUNT( string text, pattern text, position int ) -> integer CREATE OR REPLACE FUNCTION oracle.regexp_count(text, text, integer) RETURNS integer AS $$ DECLARE v_cnt integer; BEGIN -- Check numeric arguments IF $3 < 1 THEN RAISE EXCEPTION 'argument ''position'' must be a number greater than 0'; END IF; -- Oracle default behavior is newline-sensitive, -- PostgreSQL not, so force 'p' modifier to affect -- newline-sensitivity but not ^ and $ search. v_cnt := (SELECT count(*)::integer FROM regexp_matches(substr($1, $3), oracle.regexp_count_pattern_fix($2), 'sg')); RETURN v_cnt; END; $$ LANGUAGE plpgsql STRICT IMMUTABLE PARALLEL SAFE; -- REGEXP_COUNT( string text, pattern text, position int, flags text ) -> integer CREATE OR REPLACE FUNCTION oracle.regexp_count(text, text, integer, text) RETURNS integer AS $$ DECLARE modifiers text; v_cnt integer; BEGIN -- Only modifier can be NULL IF $1 IS NULL OR $2 IS NULL OR $3 IS NULL THEN RETURN NULL; END IF; -- Check numeric arguments IF $3 < 1 THEN RAISE EXCEPTION 'argument ''position'' must be a number greater than 0'; END IF; modifiers := oracle.translate_oracle_modifiers($4, true); v_cnt := (SELECT count(*)::integer FROM regexp_matches(substr($1, $3), $2, modifiers)); RETURN v_cnt; END; $$ LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE; -- REGEXP_INSTR( string text, pattern text ) -> integer CREATE OR REPLACE FUNCTION oracle.regexp_instr(text, text) RETURNS integer AS 'MODULE_PATHNAME','orafce_regexp_instr_no_start' LANGUAGE 'c' IMMUTABLE PARALLEL SAFE; -- REGEXP_INSTR( string text, pattern text, position int ) -> integer CREATE OR REPLACE FUNCTION oracle.regexp_instr(text, text, integer) RETURNS integer AS 'MODULE_PATHNAME','orafce_regexp_instr_no_n' LANGUAGE 'c' IMMUTABLE PARALLEL SAFE; -- REGEXP_INSTR( string text, pattern text, position int, occurence int ) -> integer CREATE OR REPLACE FUNCTION oracle.regexp_instr(text, text, integer, integer) RETURNS integer AS 'MODULE_PATHNAME','orafce_regexp_instr_no_endoption' LANGUAGE 'c' IMMUTABLE PARALLEL SAFE; -- REGEXP_INSTR( string text, pattern text, position int, occurence int, return_opt int ) -> integer CREATE OR REPLACE FUNCTION oracle.regexp_instr(text, text, integer, integer, integer) RETURNS integer AS 'MODULE_PATHNAME','orafce_regexp_instr_no_flags' LANGUAGE 'c' IMMUTABLE PARALLEL SAFE; -- REGEXP_INSTR( string text, pattern text, position int, occurence int, return_opt int, flags text ) -> integer CREATE OR REPLACE FUNCTION oracle.regexp_instr(text, text, integer, integer, integer, text) RETURNS integer AS 'MODULE_PATHNAME','orafce_regexp_instr_no_subexpr' LANGUAGE 'c' IMMUTABLE PARALLEL SAFE; -- REGEXP_INSTR( string text, pattern text, position int, occurence int, return_opt int, flags text, group int ) -> integer CREATE OR REPLACE FUNCTION oracle.regexp_instr(text, text, integer, integer, integer, text, integer) RETURNS integer AS 'MODULE_PATHNAME','orafce_regexp_instr' LANGUAGE 'c' IMMUTABLE PARALLEL SAFE; -- REGEXP_SUBSTR( string text, pattern text ) -> text CREATE OR REPLACE FUNCTION oracle.regexp_substr(text, text) RETURNS text AS $$ DECLARE v_substr text; v_pattern text; BEGIN -- Without subexpression specified, assume 0 which mean that the first -- position for the substring matching the whole pattern is returned. -- We need to enclose the pattern between parentheses. v_pattern := '(' || oracle.regexp_count_pattern_fix($2) || ')'; -- Oracle default behavior is newline-sensitive, -- PostgreSQL not, so force 'p' modifier to affect -- newline-sensitivity but not ^ and $ search. v_substr := (SELECT (regexp_matches($1, v_pattern, 'sg'))[1] OFFSET 0 LIMIT 1); RETURN v_substr; END; $$ LANGUAGE plpgsql STRICT IMMUTABLE PARALLEL SAFE; -- REGEXP_SUBSTR( string text, pattern text, position int ) -> text CREATE OR REPLACE FUNCTION oracle.regexp_substr(text, text, int) RETURNS text AS $$ DECLARE v_substr text; v_pattern text; BEGIN -- Check numeric arguments IF $3 < 1 THEN RAISE EXCEPTION 'argument ''position'' must be a number greater than 0'; END IF; -- Without subexpression specified, assume 0 which mean that the first -- position for the substring matching the whole pattern is returned. -- We need to enclose the pattern between parentheses. v_pattern := '(' || oracle.regexp_count_pattern_fix($2) || ')'; -- Oracle default behavior is newline-sensitive, -- PostgreSQL not, so force 'p' modifier to affect -- newline-sensitivity but not ^ and $ search. v_substr := (SELECT (regexp_matches(substr($1, $3), v_pattern, 'sg'))[1] OFFSET 0 LIMIT 1); RETURN v_substr; END; $$ LANGUAGE plpgsql STRICT IMMUTABLE PARALLEL SAFE; -- REGEXP_SUBSTR( string text, pattern text, position int, occurence int ) -> text CREATE OR REPLACE FUNCTION oracle.regexp_substr(text, text, integer, integer) RETURNS text AS $$ DECLARE v_substr text; v_pattern text; BEGIN -- Check numeric arguments IF $3 < 1 THEN RAISE EXCEPTION 'argument ''position'' must be a number greater than 0'; END IF; IF $4 < 1 THEN RAISE EXCEPTION 'argument ''occurence'' must be a number greater than 0'; END IF; -- Without subexpression specified, assume 0 which mean that the first -- position for the substring matching the whole pattern is returned. -- We need to enclose the pattern between parentheses. v_pattern := '(' || oracle.regexp_count_pattern_fix($2) || ')'; -- Oracle default behavior is newline-sensitive, -- PostgreSQL not, so force 'p' modifier to affect -- newline-sensitivity but not ^ and $ search. v_substr := (SELECT (regexp_matches(substr($1, $3), v_pattern, 'sg'))[1] OFFSET $4 - 1 LIMIT 1); RETURN v_substr; END; $$ LANGUAGE plpgsql STRICT IMMUTABLE PARALLEL SAFE; -- REGEXP_SUBSTR( string text, pattern text, position int, occurence int, flags text ) -> text CREATE OR REPLACE FUNCTION oracle.regexp_substr(text, text, integer, integer, text) RETURNS text AS $$ DECLARE v_substr text; v_pattern text; modifiers text; BEGIN -- Only modifier can be NULL IF $1 IS NULL OR $2 IS NULL OR $3 IS NULL OR $4 IS NULL THEN RETURN NULL; END IF; -- Check numeric arguments IF $3 < 1 THEN RAISE EXCEPTION 'argument ''position'' must be a number greater than 0'; END IF; IF $4 < 1 THEN RAISE EXCEPTION 'argument ''occurence'' must be a number greater than 0'; END IF; modifiers := oracle.translate_oracle_modifiers($5, true); -- Without subexpression specified, assume 0 which mean that the first -- position for the substring matching the whole pattern is returned. -- We need to enclose the pattern between parentheses. v_pattern := '(' || $2 || ')'; -- Oracle default behavior is newline-sensitive, -- PostgreSQL not, so force 'p' modifier to affect -- newline-sensitivity but not ^ and $ search. v_substr := (SELECT (regexp_matches(substr($1, $3), v_pattern, modifiers))[1] OFFSET $4 - 1 LIMIT 1); RETURN v_substr; END; $$ LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE; -- REGEXP_SUBSTR( string text, pattern text, position int, occurence int, flags text, group int ) -> text CREATE OR REPLACE FUNCTION oracle.regexp_substr(text, text, integer, integer, text, int) RETURNS text AS $$ DECLARE v_substr text; v_pattern text; modifiers text; v_subexpr integer := $6; has_group integer; BEGIN -- Only modifier can be NULL IF $1 IS NULL OR $2 IS NULL OR $3 IS NULL OR $4 IS NULL OR $6 IS NULL THEN RETURN NULL; END IF; -- Check numeric arguments IF $3 < 1 THEN RAISE EXCEPTION 'argument ''position'' must be a number greater than 0'; END IF; IF $4 < 1 THEN RAISE EXCEPTION 'argument ''occurence'' must be a number greater than 0'; END IF; IF v_subexpr < 0 THEN RAISE EXCEPTION 'argument ''group'' must be a positive number'; END IF; -- Check that with v_subexpr = 1 we have a capture group otherwise return NULL has_group := (SELECT count(*) FROM regexp_matches($2, '(?:[^\\]|^)\(', 'g')); IF $6 = 1 AND has_group = 0 THEN RETURN NULL; END IF; modifiers := oracle.translate_oracle_modifiers($5, true); -- If subexpression value is 0 we need to enclose the pattern between parentheses. IF v_subexpr = 0 THEN v_pattern := '(' || $2 || ')'; v_subexpr := 1; ELSE v_pattern := $2; END IF; -- Oracle default behavior is newline-sensitive, -- PostgreSQL not, so force 'p' modifier to affect -- newline-sensitivity but not ^ and $ search. v_substr := (SELECT (regexp_matches(substr($1, $3), v_pattern, modifiers))[v_subexpr] OFFSET $4 - 1 LIMIT 1); RETURN v_substr; END; $$ LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE; -- REGEXP_REPLACE( string text, pattern text, replace_string text ) -> text CREATE OR REPLACE FUNCTION oracle.regexp_replace(text, text, text) RETURNS text AS 'MODULE_PATHNAME','orafce_textregexreplace_noopt' LANGUAGE 'c' IMMUTABLE PARALLEL SAFE; -- REGEXP_REPLACE( string text, pattern text, replace_string text, position int ) -> text CREATE OR REPLACE FUNCTION oracle.regexp_replace(text, text, text, integer) RETURNS text AS 'MODULE_PATHNAME','orafce_textregexreplace_extended_no_n' LANGUAGE 'c' IMMUTABLE PARALLEL SAFE; -- REGEXP_REPLACE( string text, pattern text, replace_string text, position int, occurence int ) -> text CREATE OR REPLACE FUNCTION oracle.regexp_replace(text, text, text, integer, integer) RETURNS text AS 'MODULE_PATHNAME','orafce_textregexreplace_extended_no_flags' LANGUAGE 'c' IMMUTABLE PARALLEL SAFE; -- REGEXP_REPLACE( string text, pattern text, replace_string text, position int, occurence int, flags text ) -> text CREATE OR REPLACE FUNCTION oracle.regexp_replace(text, text, text, integer, integer, text) RETURNS text AS 'MODULE_PATHNAME','orafce_textregexreplace_extended' LANGUAGE 'c' IMMUTABLE PARALLEL SAFE; CREATE OR REPLACE FUNCTION oracle.regexp_replace(text, text, text, text) RETURNS text AS 'MODULE_PATHNAME','orafce_textregexreplace' LANGUAGE 'c' IMMUTABLE PARALLEL SAFE; ---- -- Add LEAST/GREATEST declaration to return NULL on NULL input. -- PostgreSQL only returns NULL when all the parameters are NULL. ---- -- GREATEST CREATE FUNCTION oracle.greatest(integer, integer) RETURNS integer AS 'SELECT greatest($1, $2)' LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.greatest(integer, integer, integer) RETURNS integer AS 'SELECT greatest($1, $2, $3)' LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.greatest(smallint, smallint) RETURNS smallint AS 'SELECT greatest($1, $2)' LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.greatest(smallint, smallint, smallint) RETURNS smallint AS 'SELECT greatest($1, $2, $3)' LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.greatest(numeric, numeric) RETURNS numeric AS 'SELECT greatest($1, $2)' LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.greatest(numeric, numeric, numeric) RETURNS numeric AS 'SELECT greatest($1, $2, $3)' LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.greatest(bigint, bigint) RETURNS bigint AS 'SELECT greatest($1, $2)' LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.greatest(bigint, bigint, bigint) RETURNS bigint AS 'SELECT greatest($1, $2, $3)' LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.greatest(bpchar, bpchar) RETURNS bpchar AS 'SELECT greatest($1, $2)' LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.greatest(bpchar, bpchar, bpchar) RETURNS bpchar AS 'SELECT greatest($1, $2, $3)' LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.greatest(text, text) RETURNS text AS 'SELECT greatest($1, $2)' LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.greatest(text, text, text) RETURNS text AS 'SELECT greatest($1, $2, $3)' LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.greatest(date, date) RETURNS date AS 'SELECT greatest($1, $2)' LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.greatest(date, date, date) RETURNS date AS 'SELECT greatest($1, $2, $3)' LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.greatest(time, time) RETURNS time AS 'SELECT greatest($1, $2)' LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.greatest(time, time, time) RETURNS time AS 'SELECT greatest($1, $2, $3)' LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.greatest(timestamp, timestamp) RETURNS timestamp AS 'SELECT greatest($1, $2)' LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.greatest(timestamp, timestamp, timestamp) RETURNS timestamp AS 'SELECT greatest($1, $2, $3)' LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.greatest(timestamptz, timestamptz) RETURNS timestamptz AS 'SELECT greatest($1, $2)' LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.greatest(timestamptz, timestamptz, timestamptz) RETURNS timestamptz AS 'SELECT greatest($1, $2, $3)' LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.greatest(anynonarray, VARIADIC anyarray) RETURNS anynonarray AS 'MODULE_PATHNAME', 'ora_greatest' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; -- LEAST CREATE FUNCTION oracle.least(integer, integer) RETURNS integer AS 'SELECT least($1, $2)' LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.least(integer, integer, integer) RETURNS integer AS 'SELECT least($1, $2, $3)' LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.least(smallint, smallint) RETURNS smallint AS 'SELECT least($1, $2)' LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.least(smallint, smallint, smallint) RETURNS smallint AS 'SELECT least($1, $2, $3)' LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.least(numeric, numeric) RETURNS numeric AS 'SELECT least($1, $2)' LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.least(numeric, numeric, numeric) RETURNS numeric AS 'SELECT least($1, $2, $3)' LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.least(bigint, bigint) RETURNS bigint AS 'SELECT least($1, $2)' LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.least(bigint, bigint, bigint) RETURNS bigint AS 'SELECT least($1, $2, $3)' LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.least(bpchar, bpchar) RETURNS bpchar AS 'SELECT least($1, $2)' LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.least(bpchar, bpchar, bpchar) RETURNS bpchar AS 'SELECT least($1, $2, $3)' LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.least(text, text) RETURNS text AS 'SELECT least($1, $2)' LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.least(text, text, text) RETURNS text AS 'SELECT least($1, $2, $3)' LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.least(date, date) RETURNS date AS 'SELECT least($1, $2)' LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.least(date, date, date) RETURNS date AS 'SELECT least($1, $2, $3)' LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.least(time, time) RETURNS time AS 'SELECT least($1, $2)' LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.least(time, time, time) RETURNS time AS 'SELECT least($1, $2, $3)' LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.least(timestamp, timestamp) RETURNS timestamp AS 'SELECT least($1, $2)' LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.least(timestamp, timestamp, timestamp) RETURNS timestamp AS 'SELECT least($1, $2, $3)' LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.least(timestamptz, timestamptz) RETURNS timestamptz AS 'SELECT least($1, $2)' LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.least(timestamptz, timestamptz, timestamptz) RETURNS timestamptz AS 'SELECT least($1, $2, $3)' LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE; CREATE FUNCTION oracle.least(anynonarray, VARIADIC anyarray) RETURNS anynonarray AS 'MODULE_PATHNAME', 'ora_least' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; CREATE SCHEMA dbms_sql; GRANT USAGE ON SCHEMA dbms_sql TO PUBLIC; CREATE FUNCTION dbms_sql.is_open(c int) RETURNS bool AS 'MODULE_PATHNAME', 'dbms_sql_is_open' LANGUAGE c; CREATE FUNCTION dbms_sql.open_cursor() RETURNS int AS 'MODULE_PATHNAME', 'dbms_sql_open_cursor' LANGUAGE c; CREATE PROCEDURE dbms_sql.close_cursor(c int) AS 'MODULE_PATHNAME', 'dbms_sql_close_cursor' LANGUAGE c; CREATE PROCEDURE dbms_sql.debug_cursor(c int) AS 'MODULE_PATHNAME', 'dbms_sql_debug_cursor' LANGUAGE c; CREATE PROCEDURE dbms_sql.parse(c int, stmt oracle.varchar2) AS 'MODULE_PATHNAME', 'dbms_sql_parse' LANGUAGE c; CREATE PROCEDURE dbms_sql.bind_variable(c int, name oracle.varchar2, value "any") AS 'MODULE_PATHNAME', 'dbms_sql_bind_variable' LANGUAGE c; CREATE FUNCTION dbms_sql.bind_variable_f(c int, name oracle.varchar2, value "any") RETURNS void AS 'MODULE_PATHNAME', 'dbms_sql_bind_variable_f' LANGUAGE c; CREATE PROCEDURE dbms_sql.bind_array(c int, name oracle.varchar2, value anyarray) AS 'MODULE_PATHNAME', 'dbms_sql_bind_array_3' LANGUAGE c; CREATE PROCEDURE dbms_sql.bind_array(c int, name oracle.varchar2, value anyarray, index1 int, index2 int) AS 'MODULE_PATHNAME', 'dbms_sql_bind_array_5' LANGUAGE c; CREATE PROCEDURE dbms_sql.define_column(c int, col int, value "any", column_size int DEFAULT -1) AS 'MODULE_PATHNAME', 'dbms_sql_define_column' LANGUAGE c; CREATE PROCEDURE dbms_sql.define_array(c int, col int, value "anyarray", cnt int, lower_bnd int) AS 'MODULE_PATHNAME', 'dbms_sql_define_array' LANGUAGE c; CREATE FUNCTION dbms_sql.execute(c int) RETURNS bigint AS 'MODULE_PATHNAME', 'dbms_sql_execute' LANGUAGE c; CREATE FUNCTION dbms_sql.fetch_rows(c int) RETURNS int AS 'MODULE_PATHNAME', 'dbms_sql_fetch_rows' LANGUAGE c; CREATE FUNCTION dbms_sql.execute_and_fetch(c int, exact bool DEFAULT false) RETURNS int AS 'MODULE_PATHNAME', 'dbms_sql_execute_and_fetch' LANGUAGE c; CREATE FUNCTION dbms_sql.last_row_count() RETURNS int AS 'MODULE_PATHNAME', 'dbms_sql_last_row_count' LANGUAGE c; CREATE PROCEDURE dbms_sql.column_value(c int, pos int, INOUT value anyelement) AS 'MODULE_PATHNAME', 'dbms_sql_column_value' LANGUAGE c; CREATE FUNCTION dbms_sql.column_value_f(c int, pos int, value anyelement) RETURNS anyelement AS 'MODULE_PATHNAME', 'dbms_sql_column_value_f' LANGUAGE c; CREATE TYPE dbms_sql.desc_rec AS ( col_type int, col_max_len int, col_name text, col_name_len int, col_schema text, col_schema_len int, col_precision int, col_scale int, col_charsetid int, col_charsetform int, col_null_ok boolean, col_type_name text, col_type_name_len int); CREATE FUNCTION dbms_sql.describe_columns_f(c int, OUT col_cnt int, OUT desc_t dbms_sql.desc_rec[]) AS 'MODULE_PATHNAME', 'dbms_sql_describe_columns_f' LANGUAGE c; CREATE PROCEDURE dbms_sql.describe_columns(c int, INOUT col_cnt int, INOUT desc_t dbms_sql.desc_rec[]) AS 'MODULE_PATHNAME', 'dbms_sql_describe_columns_f' LANGUAGE c; SELECT pg_extension_config_dump('utl_file.utl_file_dir', ''); CREATE OR REPLACE FUNCTION oracle.sys_guid() RETURNS bytea AS 'MODULE_PATHNAME','orafce_sys_guid' LANGUAGE C VOLATILE; CREATE FUNCTION oracle.to_char(str text) RETURNS text AS $$ select str; $$ LANGUAGE SQL IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION oracle.to_char(text) IS 'Convert string to string'; DO $$ BEGIN IF NOT EXISTS(SELECT * FROM pg_roles where rolname = 'orafce_set_umask') THEN CREATE ROLE orafce_set_umask INHERIT NOLOGIN; END IF; END; $$; orafce-VERSION_4_14_4/orafce--4.2--4.3.sql000066400000000000000000000000771501757153000173370ustar00rootroot00000000000000ALTER FUNCTION dbms_random.string(opt text, len int) VOLATILE; orafce-VERSION_4_14_4/orafce--4.3--4.4.sql000066400000000000000000000031651501757153000173420ustar00rootroot00000000000000ALTER FUNCTION oracle.regexp_like(text,text) IMMUTABLE; ALTER FUNCTION oracle.regexp_like(text,text,text) IMMUTABLE; ALTER FUNCTION oracle.regexp_count(text,text) IMMUTABLE; ALTER FUNCTION oracle.regexp_count(text,text,integer) IMMUTABLE; ALTER FUNCTION oracle.regexp_count(text,text,integer,text) IMMUTABLE; ALTER FUNCTION oracle.regexp_instr(text,text) IMMUTABLE PARALLEL SAFE; ALTER FUNCTION oracle.regexp_instr(text,text,integer) IMMUTABLE PARALLEL SAFE; ALTER FUNCTION oracle.regexp_instr(text,text,integer,integer) IMMUTABLE PARALLEL SAFE; ALTER FUNCTION oracle.regexp_instr(text,text,integer,integer,integer) IMMUTABLE PARALLEL SAFE; ALTER FUNCTION oracle.regexp_instr(text,text,integer,integer,integer,text) IMMUTABLE PARALLEL SAFE; ALTER FUNCTION oracle.regexp_instr(text,text,integer,integer,integer,text,integer) IMMUTABLE PARALLEL SAFE; ALTER FUNCTION oracle.regexp_substr(text,text) IMMUTABLE; ALTER FUNCTION oracle.regexp_substr(text,text,integer) IMMUTABLE; ALTER FUNCTION oracle.regexp_substr(text,text,integer,integer) IMMUTABLE; ALTER FUNCTION oracle.regexp_substr(text,text,integer,integer,text) IMMUTABLE; ALTER FUNCTION oracle.regexp_substr(text,text,integer,integer,text,integer) IMMUTABLE; ALTER FUNCTION oracle.regexp_replace(text,text,text) IMMUTABLE PARALLEL SAFE; ALTER FUNCTION oracle.regexp_replace(text,text,text,integer) IMMUTABLE PARALLEL SAFE; ALTER FUNCTION oracle.regexp_replace(text,text,text,integer,integer) IMMUTABLE PARALLEL SAFE; ALTER FUNCTION oracle.regexp_replace(text,text,text,integer,integer,text) IMMUTABLE PARALLEL SAFE; ALTER FUNCTION oracle.regexp_replace(text,text,text,text) IMMUTABLE PARALLEL SAFE; orafce-VERSION_4_14_4/orafce--4.4--4.5.sql000066400000000000000000000000001501757153000173250ustar00rootroot00000000000000orafce-VERSION_4_14_4/orafce--4.5--4.6.sql000066400000000000000000000010361501757153000173410ustar00rootroot00000000000000CREATE FUNCTION dbms_alert.waitany(OUT name text, OUT message text, OUT status integer) RETURNS record AS 'MODULE_PATHNAME','dbms_alert_waitany_maxwait' LANGUAGE C VOLATILE; COMMENT ON FUNCTION dbms_alert.waitany(OUT text, OUT text, OUT integer) IS 'Wait for any signal'; CREATE FUNCTION dbms_alert.waitone(name text, OUT message text, OUT status integer) RETURNS record AS 'MODULE_PATHNAME','dbms_alert_waitone_maxwait' LANGUAGE C VOLATILE; COMMENT ON FUNCTION dbms_alert.waitone(text, OUT text, OUT integer) IS 'Wait for specific signal'; orafce-VERSION_4_14_4/orafce--4.6--4.7.sql000066400000000000000000000003401501757153000173400ustar00rootroot00000000000000ALTER FUNCTION oracle.remainder(smallint, smallint) STRICT; ALTER FUNCTION oracle.remainder(int, int) STRICT; ALTER FUNCTION oracle.remainder(bigint, bigint) STRICT; ALTER FUNCTION oracle.remainder(numeric, numeric) STRICT; orafce-VERSION_4_14_4/orafce--4.7--4.8.sql000066400000000000000000000601251501757153000173510ustar00rootroot00000000000000ALTER FUNCTION oracle.btrim(char) PARALLEL SAFE; ALTER FUNCTION oracle.btrim(char, char) PARALLEL SAFE; ALTER FUNCTION oracle.btrim(char, text) PARALLEL SAFE; ALTER FUNCTION oracle.btrim(char, oracle.varchar2) PARALLEL SAFE; ALTER FUNCTION oracle.btrim(char, oracle.nvarchar2) PARALLEL SAFE; ALTER FUNCTION oracle.btrim(text) PARALLEL SAFE; ALTER FUNCTION oracle.btrim(text, char) PARALLEL SAFE; ALTER FUNCTION oracle.btrim(text, text) PARALLEL SAFE; ALTER FUNCTION oracle.btrim(text, oracle.varchar2) PARALLEL SAFE; ALTER FUNCTION oracle.btrim(text, oracle.nvarchar2) PARALLEL SAFE; ALTER FUNCTION oracle.btrim(oracle.varchar2) PARALLEL SAFE; ALTER FUNCTION oracle.btrim(oracle.varchar2, char) PARALLEL SAFE; ALTER FUNCTION oracle.btrim(oracle.varchar2, text) PARALLEL SAFE; ALTER FUNCTION oracle.btrim(oracle.varchar2, oracle.varchar2) PARALLEL SAFE; ALTER FUNCTION oracle.btrim(oracle.varchar2, oracle.nvarchar2) PARALLEL SAFE; ALTER FUNCTION oracle.btrim(oracle.nvarchar2) PARALLEL SAFE; ALTER FUNCTION oracle.btrim(oracle.nvarchar2, char) PARALLEL SAFE; ALTER FUNCTION oracle.btrim(oracle.nvarchar2, text) PARALLEL SAFE; ALTER FUNCTION oracle.btrim(oracle.nvarchar2, oracle.varchar2) PARALLEL SAFE; ALTER FUNCTION oracle.btrim(oracle.nvarchar2, oracle.nvarchar2) PARALLEL SAFE; ALTER FUNCTION oracle.ltrim(char, char) PARALLEL SAFE; ALTER FUNCTION oracle.ltrim(char, text) PARALLEL SAFE; ALTER FUNCTION oracle.ltrim(char, oracle.varchar2) PARALLEL SAFE; ALTER FUNCTION oracle.ltrim(char, oracle.nvarchar2) PARALLEL SAFE; ALTER FUNCTION oracle.ltrim(char) PARALLEL SAFE; ALTER FUNCTION oracle.ltrim(text, char) PARALLEL SAFE; ALTER FUNCTION oracle.ltrim(text, text) PARALLEL SAFE; ALTER FUNCTION oracle.ltrim(text, oracle.varchar2) PARALLEL SAFE; ALTER FUNCTION oracle.ltrim(text, oracle.nvarchar2) PARALLEL SAFE; ALTER FUNCTION oracle.ltrim(text) PARALLEL SAFE; ALTER FUNCTION oracle.ltrim(oracle.varchar2, char) PARALLEL SAFE; ALTER FUNCTION oracle.ltrim(oracle.varchar2, text) PARALLEL SAFE; ALTER FUNCTION oracle.ltrim(oracle.varchar2, oracle.varchar2) PARALLEL SAFE; ALTER FUNCTION oracle.ltrim(oracle.varchar2, oracle.nvarchar2) PARALLEL SAFE; ALTER FUNCTION oracle.ltrim(oracle.varchar2) PARALLEL SAFE; ALTER FUNCTION oracle.ltrim(oracle.nvarchar2, char) PARALLEL SAFE; ALTER FUNCTION oracle.ltrim(oracle.nvarchar2, text) PARALLEL SAFE; ALTER FUNCTION oracle.ltrim(oracle.nvarchar2, oracle.varchar2) PARALLEL SAFE; ALTER FUNCTION oracle.ltrim(oracle.nvarchar2, oracle.nvarchar2) PARALLEL SAFE; ALTER FUNCTION oracle.ltrim(oracle.nvarchar2) PARALLEL SAFE; ALTER FUNCTION oracle.rtrim(char, char) PARALLEL SAFE; ALTER FUNCTION oracle.rtrim(char, text) PARALLEL SAFE; ALTER FUNCTION oracle.rtrim(char, oracle.varchar2) PARALLEL SAFE; ALTER FUNCTION oracle.rtrim(char, oracle.nvarchar2) PARALLEL SAFE; ALTER FUNCTION oracle.rtrim(char) PARALLEL SAFE; ALTER FUNCTION oracle.rtrim(text, char) PARALLEL SAFE; ALTER FUNCTION oracle.rtrim(text, text) PARALLEL SAFE; ALTER FUNCTION oracle.rtrim(text, oracle.varchar2) PARALLEL SAFE; ALTER FUNCTION oracle.rtrim(text, oracle.nvarchar2) PARALLEL SAFE; ALTER FUNCTION oracle.rtrim(text) PARALLEL SAFE; ALTER FUNCTION oracle.rtrim(oracle.varchar2, char) PARALLEL SAFE; ALTER FUNCTION oracle.rtrim(oracle.varchar2, text) PARALLEL SAFE; ALTER FUNCTION oracle.rtrim(oracle.varchar2, oracle.varchar2) PARALLEL SAFE; ALTER FUNCTION oracle.rtrim(oracle.varchar2, oracle.nvarchar2) PARALLEL SAFE; ALTER FUNCTION oracle.rtrim(oracle.varchar2) PARALLEL SAFE; ALTER FUNCTION oracle.rtrim(oracle.nvarchar2, char) PARALLEL SAFE; ALTER FUNCTION oracle.rtrim(oracle.nvarchar2, text) PARALLEL SAFE; ALTER FUNCTION oracle.rtrim(oracle.nvarchar2, oracle.varchar2) PARALLEL SAFE; ALTER FUNCTION oracle.rtrim(oracle.nvarchar2, oracle.nvarchar2) PARALLEL SAFE; ALTER FUNCTION oracle.rtrim(oracle.nvarchar2) PARALLEL SAFE; ALTER FUNCTION oracle.lpad(char, integer, char) PARALLEL SAFE; ALTER FUNCTION oracle.lpad(char, integer, text) PARALLEL SAFE; ALTER FUNCTION oracle.lpad(char, integer, oracle.varchar2) PARALLEL SAFE; ALTER FUNCTION oracle.lpad(char, integer, oracle.nvarchar2) PARALLEL SAFE; ALTER FUNCTION oracle.lpad(char, integer) PARALLEL SAFE; ALTER FUNCTION oracle.lpad(text, integer, char) PARALLEL SAFE; ALTER FUNCTION oracle.lpad(oracle.varchar2, integer, char) PARALLEL SAFE; ALTER FUNCTION oracle.lpad(oracle.nvarchar2, integer, char) PARALLEL SAFE; ALTER FUNCTION oracle.lpad(text, integer, text) PARALLEL SAFE; ALTER FUNCTION oracle.lpad(text, integer, oracle.varchar2) PARALLEL SAFE; ALTER FUNCTION oracle.lpad(text, integer, oracle.nvarchar2) PARALLEL SAFE; ALTER FUNCTION oracle.lpad(text, integer) PARALLEL SAFE; ALTER FUNCTION oracle.lpad(oracle.varchar2, integer, text) PARALLEL SAFE; ALTER FUNCTION oracle.lpad(oracle.varchar2, integer, oracle.varchar2) PARALLEL SAFE; ALTER FUNCTION oracle.lpad(oracle.varchar2, integer, oracle.nvarchar2) PARALLEL SAFE; ALTER FUNCTION oracle.lpad(oracle.varchar2, integer) PARALLEL SAFE; ALTER FUNCTION oracle.lpad(oracle.nvarchar2, integer, text) PARALLEL SAFE; ALTER FUNCTION oracle.lpad(oracle.nvarchar2, integer, oracle.varchar2) PARALLEL SAFE; ALTER FUNCTION oracle.lpad(oracle.nvarchar2, integer, oracle.nvarchar2) PARALLEL SAFE; ALTER FUNCTION oracle.lpad(oracle.nvarchar2, integer) PARALLEL SAFE; ALTER FUNCTION oracle.lpad(int, int, int) PARALLEL SAFE; ALTER FUNCTION oracle.lpad(bigint, int, int) PARALLEL SAFE; ALTER FUNCTION oracle.lpad(smallint, int, int) PARALLEL SAFE; ALTER FUNCTION oracle.lpad(numeric, int, int) PARALLEL SAFE; ALTER FUNCTION oracle.rpad(text, integer) PARALLEL SAFE; ALTER FUNCTION oracle.rpad(character, integer) PARALLEL SAFE; ALTER FUNCTION oracle.rpad(oracle.varchar2, integer) PARALLEL SAFE; ALTER FUNCTION oracle.rpad(oracle.nvarchar2, integer) PARALLEL SAFE; ALTER FUNCTION oracle.rpad(text, integer, text) PARALLEL SAFE; ALTER FUNCTION oracle.rpad(text, integer, character) PARALLEL SAFE; ALTER FUNCTION oracle.rpad(text, integer, oracle.varchar2) PARALLEL SAFE; ALTER FUNCTION oracle.rpad(text, integer, oracle.nvarchar2) PARALLEL SAFE; ALTER FUNCTION oracle.rpad(character, integer, text) PARALLEL SAFE; ALTER FUNCTION oracle.rpad(character, integer, character) PARALLEL SAFE; ALTER FUNCTION oracle.rpad(character, integer, oracle.varchar2) PARALLEL SAFE; ALTER FUNCTION oracle.rpad(character, integer, oracle.nvarchar2) PARALLEL SAFE; ALTER FUNCTION oracle.rpad(oracle.varchar2, integer, text) PARALLEL SAFE; ALTER FUNCTION oracle.rpad(oracle.varchar2, integer, character) PARALLEL SAFE; ALTER FUNCTION oracle.rpad(oracle.varchar2, integer, oracle.varchar2) PARALLEL SAFE; ALTER FUNCTION oracle.rpad(oracle.varchar2, integer, oracle.nvarchar2) PARALLEL SAFE; ALTER FUNCTION oracle.rpad(oracle.nvarchar2, integer, text) PARALLEL SAFE; ALTER FUNCTION oracle.rpad(oracle.nvarchar2, integer, character) PARALLEL SAFE; ALTER FUNCTION oracle.rpad(oracle.nvarchar2, integer, oracle.varchar2) PARALLEL SAFE; ALTER FUNCTION oracle.rpad(oracle.nvarchar2, integer, oracle.nvarchar2) PARALLEL SAFE; ALTER FUNCTION oracle.to_char(num bigint) PARALLEL SAFE; ALTER FUNCTION oracle.to_char(num smallint) PARALLEL SAFE; ALTER FUNCTION oracle.to_char(num integer) PARALLEL SAFE; ALTER FUNCTION oracle.to_char(num real) PARALLEL SAFE; ALTER FUNCTION oracle.to_char(num double precision) PARALLEL SAFE; ALTER FUNCTION oracle.to_char(timestamp without time zone) PARALLEL SAFE; ALTER FUNCTION oracle.to_char(num numeric) PARALLEL SAFE; ALTER FUNCTION oracle.to_number(str text) PARALLEL SAFE; ALTER FUNCTION oracle.to_number(numeric) PARALLEL SAFE; ALTER FUNCTION oracle.to_number(numeric,numeric) PARALLEL SAFE; CREATE FUNCTION oracle.to_char(str text) RETURNS text AS $$ select str; $$ LANGUAGE SQL IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION oracle.to_char(text) IS 'Convert string to string'; ALTER FUNCTION oracle.round(double precision, integer) PARALLEL SAFE; ALTER FUNCTION oracle.round(real, integer) PARALLEL SAFE; ALTER FUNCTION oracle.round(value date) PARALLEL SAFE; ALTER FUNCTION oracle.round(value date, fmt text) PARALLEL SAFE; ALTER FUNCTION oracle.round(value timestamp with time zone) PARALLEL SAFE; ALTER FUNCTION oracle.round(value timestamp with time zone, fmt text) PARALLEL SAFE; ALTER FUNCTION oracle.round(value timestamp without time zone) PARALLEL SAFE; ALTER FUNCTION oracle.round(value timestamp without time zone, fmt text) PARALLEL SAFE; ALTER FUNCTION oracle.instr(str text, patt text, start int, nth int) PARALLEL SAFE; ALTER FUNCTION oracle.instr(str text, patt text, start int) PARALLEL SAFE; ALTER FUNCTION oracle.instr(str text, patt text) PARALLEL SAFE; ALTER FUNCTION oracle.substr(str text, start integer) PARALLEL SAFE; ALTER FUNCTION oracle.substr(character varying, numeric) PARALLEL SAFE; ALTER FUNCTION oracle.substr(numeric, numeric) PARALLEL SAFE; ALTER FUNCTION oracle.substr(str text, start integer, len integer) PARALLEL SAFE; ALTER FUNCTION oracle.substr(character varying, numeric, numeric) PARALLEL SAFE; ALTER FUNCTION oracle.substr(numeric, numeric, numeric) PARALLEL SAFE; ALTER FUNCTION oracle.length(char) PARALLEL SAFE; ALTER FUNCTION oracle.lengthb(oracle.varchar2) PARALLEL SAFE; ALTER FUNCTION oracle.subtract(oracle.date, bigint) PARALLEL SAFE; ALTER FUNCTION oracle.subtract(oracle.date, smallint) PARALLEL SAFE; ALTER FUNCTION oracle.subtract(oracle.date, integer) PARALLEL SAFE; ALTER FUNCTION oracle.subtract(oracle.date, numeric) PARALLEL SAFE; ALTER FUNCTION oracle.subtract(oracle.date, oracle.date) PARALLEL SAFE; ALTER FUNCTION oracle.trunc(double precision, integer) PARALLEL SAFE; ALTER FUNCTION oracle.trunc(real, integer) PARALLEL SAFE; ALTER FUNCTION oracle.trunc(value date) PARALLEL SAFE; ALTER FUNCTION oracle.trunc(value date, fmt text) PARALLEL SAFE; ALTER FUNCTION oracle.trunc(value timestamp with time zone) PARALLEL SAFE; ALTER FUNCTION oracle.trunc(value timestamp with time zone, fmt text) PARALLEL SAFE; ALTER FUNCTION oracle.trunc(value timestamp without time zone) PARALLEL SAFE; ALTER FUNCTION oracle.trunc(value timestamp without time zone, fmt text) PARALLEL SAFE; ALTER FUNCTION oracle.add_days_to_timestamp(oracle.date,integer) PARALLEL SAFE; ALTER FUNCTION oracle.add_days_to_timestamp(oracle.date,bigint) PARALLEL SAFE; ALTER FUNCTION oracle.add_days_to_timestamp(oracle.date,smallint) PARALLEL SAFE; ALTER FUNCTION oracle.add_days_to_timestamp(oracle.date,numeric) PARALLEL SAFE; ALTER FUNCTION oracle.next_day(value date, weekday text) PARALLEL SAFE; ALTER FUNCTION oracle.next_day(value date, weekday integer) PARALLEL SAFE; ALTER FUNCTION oracle.next_day(TIMESTAMP WITH TIME ZONE,INTEGER) PARALLEL SAFE; ALTER FUNCTION oracle.next_day(TIMESTAMP WITH TIME ZONE,TEXT) PARALLEL SAFE; ALTER FUNCTION oracle.add_months(day date, value int) PARALLEL SAFE; ALTER FUNCTION oracle.add_months(TIMESTAMP WITH TIME ZONE,INTEGER) PARALLEL SAFE; ALTER FUNCTION oracle.last_day(value date) PARALLEL SAFE; ALTER FUNCTION oracle.last_day(TIMESTAMPTZ) PARALLEL SAFE; ALTER FUNCTION oracle.months_between(date1 date, date2 date) PARALLEL SAFE; ALTER FUNCTION oracle.months_between(TIMESTAMP WITH TIME ZONE,TIMESTAMP WITH TIME ZONE) PARALLEL SAFE; ALTER FUNCTION oracle.numtodsinterval(double precision, text) PARALLEL SAFE; ALTER FUNCTION oracle.sysdate() PARALLEL SAFE; ALTER FUNCTION oracle.bitand(bigint, bigint) PARALLEL SAFE; ALTER FUNCTION oracle.dbtimezone() PARALLEL SAFE; ALTER FUNCTION oracle.sessiontimezone() PARALLEL SAFE; ALTER FUNCTION oracle.strposb(oracle.varchar2, oracle.varchar2) PARALLEL SAFE; ALTER FUNCTION oracle.to_multi_byte(str text) PARALLEL SAFE; ALTER FUNCTION oracle.to_single_byte(str text) PARALLEL SAFE; ALTER FUNCTION oracle.sinh(float8) PARALLEL SAFE; ALTER FUNCTION oracle.cosh(float8) PARALLEL SAFE; ALTER FUNCTION oracle.tanh(float8) PARALLEL SAFE; ALTER FUNCTION oracle.to_date(TEXT) PARALLEL SAFE; ALTER FUNCTION oracle.to_date(TEXT,TEXT) PARALLEL SAFE; ALTER FUNCTION oracle.orafce__obsolete_to_date(str text) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, bigint) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, bigint, anyelement, bigint) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, bigint, anyelement, bigint, anyelement, bigint) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, bigint, anyelement, bigint, anyelement, bigint, bigint) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, bigint, anyelement, bigint, bigint) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, bigint, bigint) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, character) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, character, anyelement, character) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, character, anyelement, character, anyelement, character) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, character, anyelement, character, anyelement, character, character) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, character, anyelement, character, character) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, character, character) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, date) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, date, anyelement, date) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, date, anyelement, date, anyelement, date) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, date, anyelement, date, anyelement, date, date) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, date, anyelement, date, date) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, date, date) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, integer) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, integer, anyelement, integer) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, integer, anyelement, integer, anyelement, integer) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, integer, anyelement, integer, anyelement, integer, integer) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, integer, anyelement, integer, integer) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, integer, integer) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, numeric) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, numeric, anyelement, numeric) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, numeric, anyelement, numeric, anyelement, numeric) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, numeric, anyelement, numeric, anyelement, numeric, numeric) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, numeric, anyelement, numeric, numeric) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, numeric, numeric) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, text) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, text, anyelement, text) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, text, anyelement, text, anyelement, text) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, text, anyelement, text, anyelement, text, text) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, text, anyelement, text, text) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, text, text) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, time without time zone) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, time without time zone, anyelement, time without time zone) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, time without time zone, anyelement, time without time zone, anyelement, time without time zone) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, time without time zone, anyelement, time without time zone, anyelement, time without time zone, time without time zone) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, time without time zone, anyelement, time without time zone, time without time zone) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, time without time zone, time without time zone) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, timestamp with time zone) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, timestamp with time zone, anyelement, timestamp with time zone) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, timestamp with time zone, anyelement, timestamp with time zone, anyelement, timestamp with time zone) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, timestamp with time zone, anyelement, timestamp with time zone, anyelement, timestamp with time zone, timestamp with time zone) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, timestamp with time zone, anyelement, timestamp with time zone, timestamp with time zone) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, timestamp with time zone, timestamp with time zone) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, timestamp without time zone) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, timestamp without time zone, anyelement, timestamp without time zone) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, timestamp without time zone, anyelement, timestamp without time zone, anyelement, timestamp without time zone) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, timestamp without time zone, anyelement, timestamp without time zone, anyelement, timestamp without time zone, timestamp without time zone) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, timestamp without time zone, anyelement, timestamp without time zone, timestamp without time zone) PARALLEL SAFE; ALTER FUNCTION oracle.decode(anyelement, anyelement, timestamp without time zone, timestamp without time zone) PARALLEL SAFE; ALTER FUNCTION oracle.nvl(anyelement, anyelement) PARALLEL SAFE; ALTER FUNCTION oracle.nvl(bigint, integer) PARALLEL SAFE; ALTER FUNCTION oracle.nvl(integer, integer) PARALLEL SAFE; ALTER FUNCTION oracle.nvl(numeric, integer) PARALLEL SAFE; ALTER FUNCTION oracle.nvl2("any", anyelement, anyelement) PARALLEL SAFE; ALTER FUNCTION oracle.nvl2("any", text, text) PARALLEL SAFE; ALTER FUNCTION oracle.nvarchar2(oracle.nvarchar2,integer,boolean) PARALLEL SAFE; ALTER FUNCTION oracle.nvarchar2in(cstring,oid,integer) PARALLEL SAFE; ALTER FUNCTION oracle.nvarchar2out(oracle.nvarchar2) PARALLEL SAFE; ALTER FUNCTION oracle.nvarchar2_transform(internal) PARALLEL SAFE; ALTER FUNCTION oracle.nvarchar2recv(internal,oid,integer) PARALLEL SAFE; ALTER FUNCTION oracle.nvarchar2send(oracle.nvarchar2) PARALLEL SAFE; ALTER FUNCTION oracle.nvarchar2typmodin(cstring[]) PARALLEL SAFE; ALTER FUNCTION oracle.nvarchar2typmodout(integer) PARALLEL SAFE; ALTER FUNCTION oracle.varchar2(oracle.varchar2, integer, boolean) PARALLEL SAFE; ALTER FUNCTION oracle.varchar2_transform(internal) PARALLEL SAFE; ALTER FUNCTION oracle.varchar2in(cstring, oid, integer) PARALLEL SAFE; ALTER FUNCTION oracle.varchar2out(oracle.varchar2) PARALLEL SAFE; ALTER FUNCTION oracle.varchar2recv(internal, oid, integer) PARALLEL SAFE; ALTER FUNCTION oracle.varchar2send(oracle.varchar2) PARALLEL SAFE; ALTER FUNCTION oracle.varchar2typmodin(cstring[]) PARALLEL SAFE; ALTER FUNCTION oracle.varchar2typmodout(integer) PARALLEL SAFE; ALTER FUNCTION oracle.orafce_concat2(oracle.varchar2, oracle.varchar2) PARALLEL SAFE; ALTER FUNCTION oracle.orafce_concat2(oracle.nvarchar2, oracle.nvarchar2) PARALLEL SAFE; ALTER FUNCTION oracle.unistr(text) PARALLEL SAFE; ALTER FUNCTION oracle.substrb(oracle.varchar2, integer, integer) PARALLEL SAFE; ALTER FUNCTION oracle.substrb(oracle.varchar2, integer) PARALLEL SAFE; ALTER FUNCTION oracle.greatest(anynonarray, VARIADIC anyarray) PARALLEL SAFE; ALTER FUNCTION oracle.greatest(bigint, bigint) PARALLEL SAFE; ALTER FUNCTION oracle.greatest(bigint, bigint, bigint) PARALLEL SAFE; ALTER FUNCTION oracle.greatest(character, character) PARALLEL SAFE; ALTER FUNCTION oracle.greatest(character, character, character) PARALLEL SAFE; ALTER FUNCTION oracle.greatest(date, date) PARALLEL SAFE; ALTER FUNCTION oracle.greatest(date, date, date) PARALLEL SAFE; ALTER FUNCTION oracle.greatest(integer, integer) PARALLEL SAFE; ALTER FUNCTION oracle.greatest(integer, integer, integer) PARALLEL SAFE; ALTER FUNCTION oracle.greatest(numeric, numeric) PARALLEL SAFE; ALTER FUNCTION oracle.greatest(numeric, numeric, numeric) PARALLEL SAFE; ALTER FUNCTION oracle.greatest(smallint, smallint) PARALLEL SAFE; ALTER FUNCTION oracle.greatest(smallint, smallint, smallint) PARALLEL SAFE; ALTER FUNCTION oracle.greatest(text, text) PARALLEL SAFE; ALTER FUNCTION oracle.greatest(text, text, text) PARALLEL SAFE; ALTER FUNCTION oracle.greatest(time without time zone, time without time zone) PARALLEL SAFE; ALTER FUNCTION oracle.greatest(time without time zone, time without time zone, time without time zone) PARALLEL SAFE; ALTER FUNCTION oracle.greatest(timestamp with time zone, timestamp with time zone) PARALLEL SAFE; ALTER FUNCTION oracle.greatest(timestamp with time zone, timestamp with time zone, timestamp with time zone) PARALLEL SAFE; ALTER FUNCTION oracle.greatest(timestamp without time zone, timestamp without time zone) PARALLEL SAFE; ALTER FUNCTION oracle.greatest(timestamp without time zone, timestamp without time zone, timestamp without time zone) PARALLEL SAFE; ALTER FUNCTION oracle.least(anynonarray, VARIADIC anyarray) PARALLEL SAFE; ALTER FUNCTION oracle.least(bigint, bigint) PARALLEL SAFE; ALTER FUNCTION oracle.least(bigint, bigint, bigint) PARALLEL SAFE; ALTER FUNCTION oracle.least(character, character) PARALLEL SAFE; ALTER FUNCTION oracle.least(character, character, character) PARALLEL SAFE; ALTER FUNCTION oracle.least(date, date) PARALLEL SAFE; ALTER FUNCTION oracle.least(date, date, date) PARALLEL SAFE; ALTER FUNCTION oracle.least(integer, integer) PARALLEL SAFE; ALTER FUNCTION oracle.least(integer, integer, integer) PARALLEL SAFE; ALTER FUNCTION oracle.least(numeric, numeric) PARALLEL SAFE; ALTER FUNCTION oracle.least(numeric, numeric, numeric) PARALLEL SAFE; ALTER FUNCTION oracle.least(smallint, smallint) PARALLEL SAFE; ALTER FUNCTION oracle.least(smallint, smallint, smallint) PARALLEL SAFE; ALTER FUNCTION oracle.least(text, text) PARALLEL SAFE; ALTER FUNCTION oracle.least(text, text, text) PARALLEL SAFE; ALTER FUNCTION oracle.least(time without time zone, time without time zone) PARALLEL SAFE; ALTER FUNCTION oracle.least(time without time zone, time without time zone, time without time zone) PARALLEL SAFE; ALTER FUNCTION oracle.least(timestamp with time zone, timestamp with time zone) PARALLEL SAFE; ALTER FUNCTION oracle.least(timestamp with time zone, timestamp with time zone, timestamp with time zone) PARALLEL SAFE; ALTER FUNCTION oracle.least(timestamp without time zone, timestamp without time zone) PARALLEL SAFE; ALTER FUNCTION oracle.least(timestamp without time zone, timestamp without time zone, timestamp without time zone) PARALLEL SAFE; ALTER FUNCTION oracle.lnnvl(boolean) PARALLEL SAFE; ALTER FUNCTION oracle.nanvl(double precision, character varying) PARALLEL SAFE; ALTER FUNCTION oracle.nanvl(double precision, double precision) PARALLEL SAFE; ALTER FUNCTION oracle.nanvl(numeric, character varying) PARALLEL SAFE; ALTER FUNCTION oracle.nanvl(numeric, numeric) PARALLEL SAFE; ALTER FUNCTION oracle.nanvl(real, character varying) PARALLEL SAFE; ALTER FUNCTION oracle.nanvl(real, real) PARALLEL SAFE; ALTER FUNCTION oracle.regexp_count(text, text) PARALLEL SAFE; ALTER FUNCTION oracle.regexp_count(text, text, integer) PARALLEL SAFE; ALTER FUNCTION oracle.regexp_count(text, text, integer, text) PARALLEL SAFE; ALTER FUNCTION oracle.regexp_like(text, text) PARALLEL SAFE; ALTER FUNCTION oracle.regexp_like(text, text, text) PARALLEL SAFE; ALTER FUNCTION oracle.regexp_substr(text, text) PARALLEL SAFE; ALTER FUNCTION oracle.regexp_substr(text, text, integer) PARALLEL SAFE; ALTER FUNCTION oracle.regexp_substr(text, text, integer, integer) PARALLEL SAFE; ALTER FUNCTION oracle.regexp_substr(text, text, integer, integer, text) PARALLEL SAFE; ALTER FUNCTION oracle.regexp_substr(text, text, integer, integer, text, integer) PARALLEL SAFE; orafce-VERSION_4_14_4/orafce--4.8--4.9.sql000066400000000000000000000131451501757153000173530ustar00rootroot00000000000000-- regexp_count_pattern_fix: replace any occurence of a dot into a [^\n] pattern. CREATE OR REPLACE FUNCTION oracle.regexp_count_pattern_fix(text) RETURNS text AS $$ DECLARE v_pattern text; BEGIN -- Replace any occurences of a dot by [^\n] -- to have the same behavior as Oracle v_pattern := regexp_replace($1, '\\\.', '#ESCDOT#', 'g'); v_pattern := regexp_replace(v_pattern, '\.', '[^\n]', 'g'); v_pattern := regexp_replace(v_pattern, '#ESCDOT#', '\.', 'g'); RETURN v_pattern; END; $$ LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE; -- REGEXP_COUNT( string text, pattern text ) -> integer CREATE OR REPLACE FUNCTION oracle.regexp_count(text, text) RETURNS integer AS $$ -- Oracle default behavior is newline-sensitive, -- PostgreSQL not, so force 'p' modifier to affect -- newline-sensitivity but not ^ and $ search. SELECT count(*)::integer FROM regexp_matches($1, oracle.regexp_count_pattern_fix($2), 'sg'); $$ LANGUAGE 'sql' STRICT IMMUTABLE PARALLEL SAFE; -- REGEXP_COUNT( string text, pattern text, position int ) -> integer CREATE OR REPLACE FUNCTION oracle.regexp_count(text, text, integer) RETURNS integer AS $$ DECLARE v_cnt integer; v_pattern text; BEGIN -- Check numeric arguments IF $3 < 1 THEN RAISE EXCEPTION 'argument ''position'' must be a number greater than 0'; END IF; v_pattern := '(' || oracle.regexp_count_pattern_fix($2) || ')'; -- Oracle default behavior is newline-sensitive, -- PostgreSQL not, so force 's' modifier to affect -- newline-sensitivity but not ^ and $ search. v_cnt := (SELECT count(*)::integer FROM regexp_matches(substr($1, $3), v_pattern, 'sg')); RETURN v_cnt; END; $$ LANGUAGE plpgsql STRICT IMMUTABLE PARALLEL SAFE; -- REGEXP_COUNT( string text, pattern text, position int ) -> integer CREATE OR REPLACE FUNCTION oracle.regexp_count(text, text, integer) RETURNS integer AS $$ DECLARE v_cnt integer; BEGIN -- Check numeric arguments IF $3 < 1 THEN RAISE EXCEPTION 'argument ''position'' must be a number greater than 0'; END IF; -- Oracle default behavior is newline-sensitive, -- PostgreSQL not, so force 'p' modifier to affect -- newline-sensitivity but not ^ and $ search. v_cnt := (SELECT count(*)::integer FROM regexp_matches(substr($1, $3), oracle.regexp_count_pattern_fix($2), 'sg')); RETURN v_cnt; END; $$ LANGUAGE plpgsql STRICT IMMUTABLE PARALLEL SAFE; -- REGEXP_COUNT( string text, pattern text, position int, flags text ) -> integer CREATE OR REPLACE FUNCTION oracle.regexp_count(text, text, integer, text) RETURNS integer AS $$ DECLARE modifiers text; v_cnt integer; BEGIN -- Only modifier can be NULL IF $1 IS NULL OR $2 IS NULL OR $3 IS NULL THEN RETURN NULL; END IF; -- Check numeric arguments IF $3 < 1 THEN RAISE EXCEPTION 'argument ''position'' must be a number greater than 0'; END IF; modifiers := oracle.translate_oracle_modifiers($4, true); v_cnt := (SELECT count(*)::integer FROM regexp_matches(substr($1, $3), $2, modifiers)); RETURN v_cnt; END; $$ LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE; -- REGEXP_SUBSTR( string text, pattern text ) -> text CREATE OR REPLACE FUNCTION oracle.regexp_substr(text, text) RETURNS text AS $$ DECLARE v_substr text; v_pattern text; BEGIN -- Without subexpression specified, assume 0 which mean that the first -- position for the substring matching the whole pattern is returned. -- We need to enclose the pattern between parentheses. v_pattern := '(' || $2 || ')'; -- Oracle default behavior is newline-sensitive, -- PostgreSQL not, so force 'p' modifier to affect -- newline-sensitivity but not ^ and $ search. v_substr := (SELECT (regexp_matches($1, v_pattern, 'sg'))[1] OFFSET 0 LIMIT 1); RETURN v_substr; END; $$ LANGUAGE plpgsql STRICT IMMUTABLE PARALLEL SAFE; -- REGEXP_SUBSTR( string text, pattern text, position int ) -> text CREATE OR REPLACE FUNCTION oracle.regexp_substr(text, text, int) RETURNS text AS $$ DECLARE v_substr text; v_pattern text; BEGIN -- Check numeric arguments IF $3 < 1 THEN RAISE EXCEPTION 'argument ''position'' must be a number greater than 0'; END IF; -- Without subexpression specified, assume 0 which mean that the first -- position for the substring matching the whole pattern is returned. -- We need to enclose the pattern between parentheses. v_pattern := '(' || $2 || ')'; -- Oracle default behavior is newline-sensitive, -- PostgreSQL not, so force 'p' modifier to affect -- newline-sensitivity but not ^ and $ search. v_substr := (SELECT (regexp_matches(substr($1, $3), v_pattern, 'sg'))[1] OFFSET 0 LIMIT 1); RETURN v_substr; END; $$ LANGUAGE plpgsql STRICT IMMUTABLE PARALLEL SAFE; -- REGEXP_SUBSTR( string text, pattern text, position int, occurence int ) -> text CREATE OR REPLACE FUNCTION oracle.regexp_substr(text, text, integer, integer) RETURNS text AS $$ DECLARE v_substr text; v_pattern text; BEGIN -- Check numeric arguments IF $3 < 1 THEN RAISE EXCEPTION 'argument ''position'' must be a number greater than 0'; END IF; IF $4 < 1 THEN RAISE EXCEPTION 'argument ''occurence'' must be a number greater than 0'; END IF; -- Without subexpression specified, assume 0 which mean that the first -- position for the substring matching the whole pattern is returned. -- We need to enclose the pattern between parentheses. v_pattern := '(' || $2 || ')'; -- Oracle default behavior is newline-sensitive, -- PostgreSQL not, so force 'p' modifier to affect -- newline-sensitivity but not ^ and $ search. v_substr := (SELECT (regexp_matches(substr($1, $3), v_pattern, 'sg'))[1] OFFSET $4 - 1 LIMIT 1); RETURN v_substr; END; $$ LANGUAGE plpgsql STRICT IMMUTABLE PARALLEL SAFE; orafce-VERSION_4_14_4/orafce--4.9--4.10.sql000066400000000000000000000002411501757153000174150ustar00rootroot00000000000000DO $$ BEGIN IF NOT EXISTS(SELECT * FROM pg_roles where rolname = 'orafce_set_umask') THEN CREATE ROLE orafce_set_umask INHERIT NOLOGIN; END IF; END; $$; orafce-VERSION_4_14_4/orafce.c000066400000000000000000000102761501757153000160270ustar00rootroot00000000000000#include "postgres.h" #include "storage/lwlock.h" #include "storage/shmem.h" #include "utils/guc.h" #if PG_VERSION_NUM >= 160000 #include "utils/guc_hooks.h" #else #include "commands/variable.h" #endif #include "orafce.h" #include "builtins.h" #include "pipe.h" #if PG_VERSION_NUM >= 150000 #include "miscadmin.h" #endif /* default value */ char *nls_date_format = NULL; char *orafce_timezone = NULL; bool orafce_initialized = false; static const struct config_enum_entry orafce_compatibility_options[] = { {"warning_oracle", ORAFCE_COMPATIBILITY_WARNING_ORACLE, false}, {"warning_orafce", ORAFCE_COMPATIBILITY_WARNING_ORAFCE, false}, {"oracle", ORAFCE_COMPATIBILITY_ORACLE, false}, {"orafce", ORAFCE_COMPATIBILITY_ORAFCE, false}, {NULL, 0, false} }; #if PG_VERSION_NUM >= 150000 static shmem_request_hook_type prev_shmem_request_hook = NULL; #endif #if PG_VERSION_NUM >= 150000 static void orafce_shmem_request(void) { if (prev_shmem_request_hook) prev_shmem_request_hook(); RequestAddinShmemSpace(SHMEMMSGSZ); } #endif static bool check_sys_guid_source(char **newval, void **extra, GucSource source) { char *value = *newval; const char *canonicalstr; char *result; if (pg_strcasecmp(value, "uuid_generate_v1") == 0) canonicalstr = "uuid_generate_v1"; else if (pg_strcasecmp(value, "uuid_generate_v1mc") == 0) canonicalstr = "uuid_generate_v1mc"; else if (pg_strcasecmp(value, "uuid_generate_v4") == 0) canonicalstr = "uuid_generate_v1"; else if (pg_strcasecmp(value, "gen_random_uuid") == 0) canonicalstr = "gen_random_uuid"; else return false; #if PG_VERSION_NUM >= 160000 result = (char *) guc_malloc(LOG, 32); if (!result) return false; strcpy(result, canonicalstr); guc_free(*newval); *newval = result; #else result = (char *) malloc(32); if (!result) return false; strcpy(result, canonicalstr); free(*newval); *newval = result; #endif return true; } void _PG_init(void) { #if PG_VERSION_NUM >= 150000 prev_shmem_request_hook = shmem_request_hook; shmem_request_hook = orafce_shmem_request; #else RequestAddinShmemSpace(SHMEMMSGSZ); #endif /* 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, NULL); DefineCustomBoolVariable("orafce.varchar2_null_safe_concat", "Specify wether empty string should be used instead of NULL in concat clauses with varchar2 and nvarchar2 data type.", NULL, &orafce_varchar2_null_safe_concat, false, PGC_USERSET, 0, NULL, NULL, NULL); DefineCustomStringVariable("orafce.sys_guid_source", "Specify function from uuid-ossp extension used for making result.", NULL, &orafce_sys_guid_source, "uuid_generate_v1", PGC_USERSET, 0, check_sys_guid_source, NULL, NULL); DefineCustomEnumVariable("orafce.using_substring_zero_width_in_substr", gettext_noop("behaviour of substr function when substring_length argument is zero"), NULL, &orafce_substring_length_is_zero, ORAFCE_COMPATIBILITY_WARNING_ORACLE, orafce_compatibility_options, PGC_USERSET, 0, NULL, NULL, NULL); DefineCustomStringVariable("orafce.umask", "Specify umask used by utl_file.fopen.", NULL, &orafce_umask_str, "0077", PGC_USERSET, 0, orafce_umask_check_hook, orafce_umask_assign_hook, NULL); DefineCustomBoolVariable("orafce.oracle_compatibility_date_limit", "Specify if an error is raised when the Oracle to_date() bug is reached.", NULL, &orafce_emit_error_on_date_bug, true, PGC_USERSET, 0, NULL, NULL, NULL); EmitWarningsOnPlaceholders("orafce"); RegisterXactCallback(orafce_xact_cb, NULL); orafce_initialized = true; } orafce-VERSION_4_14_4/orafce.control000066400000000000000000000003151501757153000172560ustar00rootroot00000000000000# orafce extension comment = 'Functions and operators that emulate a subset of functions and packages from the Oracle RDBMS' default_version = '4.15' module_pathname = '$libdir/orafce' relocatable = false orafce-VERSION_4_14_4/orafce.h000066400000000000000000000036061501757153000160330ustar00rootroot00000000000000#ifndef __ORAFCE__ #define __ORAFCE__ #include "postgres.h" #include "access/xact.h" #include "catalog/catversion.h" #include "nodes/pg_list.h" #include #include "utils/datetime.h" #include "utils/datum.h" #include "utils/guc.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; typedef enum orafce_compatibility { ORAFCE_COMPATIBILITY_WARNING_ORACLE, ORAFCE_COMPATIBILITY_WARNING_ORAFCE, ORAFCE_COMPATIBILITY_ORACLE, ORAFCE_COMPATIBILITY_ORAFCE, } orafce_compatibility; 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 *orafce_umask_str; extern bool orafce_initialized; extern bool orafce_varchar2_null_safe_concat; extern int orafce_substring_length_is_zero; extern bool orafce_emit_error_on_date_bug; extern char *orafce_sys_guid_source; extern void orafce_xact_cb(XactEvent event, void *arg); extern void orafce_umask_assign_hook(const char *newvalue, void *extra); extern bool orafce_umask_check_hook(char **newval, void **extra, GucSource source); /* * Version compatibility */ extern Oid equality_oper_funcid(Oid argtype); /* * Date utils */ #define STRING_PTR_FIELD_TYPE const char *const extern STRING_PTR_FIELD_TYPE ora_days[]; extern int ora_seq_search(const char *name, STRING_PTR_FIELD_TYPE array[], size_t max); #ifdef _MSC_VER #define int2size(v) (size_t)(v) #define size2int(v) (int)(v) #else #define int2size(v) v #define size2int(v) v #endif #endif orafce-VERSION_4_14_4/others.c000066400000000000000000000455561501757153000161050ustar00rootroot00000000000000#include "postgres.h" #include #include #if PG_VERSION_NUM < 160000 #include "access/genam.h" #include "access/heapam.h" #include "access/htup_details.h" #include "access/sysattr.h" #if PG_VERSION_NUM >= 120000 #include "access/table.h" #endif #endif #include "catalog/indexing.h" #include "catalog/pg_extension.h" #include "catalog/pg_operator.h" #include "catalog/pg_proc.h" #include "catalog/pg_type.h" #include "commands/extension.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 "storage/lock.h" #include "storage/proc.h" #include "utils/array.h" #include "utils/arrayaccess.h" #include "utils/builtins.h" #include "utils/catcache.h" #include "utils/datum.h" #include "utils/fmgroids.h" #include "utils/lsyscache.h" #include "utils/memutils.h" #include "utils/syscache.h" #include "utils/typcache.h" #include "utils/uuid.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; static text *def_locale = NULL; char *orafce_sys_guid_source; static Oid uuid_generate_func_oid = InvalidOid; static FmgrInfo uuid_generate_func_finfo; /* The oid of function should be valid in oene transaction */ static LocalTransactionId uuid_generate_func_lxid = InvalidLocalTransactionId; static char uuid_generate_func_name[30] = ""; static Datum ora_greatest_least(FunctionCallInfo fcinfo, bool greater); #if PG_VERSION_NUM >= 170000 #define CURRENT_LXID (MyProc->vxid.lxid) #else #define CURRENT_LXID (MyProc->lxid) #endif #if PG_VERSION_NUM < 160000 static Oid get_extension_schema(Oid ext_oid) { Oid result; Relation rel; SysScanDesc scandesc; HeapTuple tuple; ScanKeyData entry[1]; #if PG_VERSION_NUM >= 120000 rel = table_open(ExtensionRelationId, AccessShareLock); ScanKeyInit(&entry[0], Anum_pg_extension_oid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(ext_oid)); #else rel = heap_open(ExtensionRelationId, AccessShareLock); ScanKeyInit(&entry[0], ObjectIdAttributeNumber, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(ext_oid)); #endif scandesc = systable_beginscan(rel, ExtensionOidIndexId, true, NULL, 1, entry); tuple = systable_getnext(scandesc); /* We assume that there can be at most one matching tuple */ if (HeapTupleIsValid(tuple)) result = ((Form_pg_extension) GETSTRUCT(tuple))->extnamespace; else result = InvalidOid; systable_endscan(scandesc); #if PG_VERSION_NUM >= 120000 table_close(rel, AccessShareLock); #else heap_close(rel, AccessShareLock); #endif return result; } #endif static Oid get_uuid_generate_func_oid(bool *reset_fmgr) { Oid result = InvalidOid; if (uuid_generate_func_lxid != CURRENT_LXID || uuid_generate_func_oid == InvalidOid || strcmp(orafce_sys_guid_source, uuid_generate_func_name) != 0) { if (strcmp(orafce_sys_guid_source, "gen_random_uuid") == 0) { /* generated uuid can have not nice features, but uses buildin functionality */ result = fmgr_internal_function("gen_random_uuid"); } else { Oid uuid_ossp_oid = InvalidOid; Oid uuid_ossp_namespace_oid = InvalidOid; CatCList *catlist; int i; uuid_ossp_oid = get_extension_oid("uuid-ossp", true); if (!OidIsValid(uuid_ossp_oid)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("extension \"uuid-ossp\" is not installed"), errhint("the extension \"uuid-ossp\" should be installed before using \"sys_guid\" function"))); uuid_ossp_namespace_oid = get_extension_schema(uuid_ossp_oid); Assert(OidIsValid(uuid_ossp_namespace_oid)); /* Search syscache by name only */ catlist = SearchSysCacheList1(PROCNAMEARGSNSP, CStringGetDatum(orafce_sys_guid_source)); for (i = 0; i < catlist->n_members; i++) { HeapTuple proctup = &catlist->members[i]->tuple; Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup); /* * Consider only procs in specified namespace, * with zero arguments and uuid type as result */ if (procform->pronamespace != uuid_ossp_namespace_oid || procform->pronargs != 0 || procform->prorettype != UUIDOID) continue; #if PG_VERSION_NUM >= 120000 result = procform->oid; #else result = HeapTupleGetOid(proctup); #endif break; } ReleaseSysCacheList(catlist); } /* should be available if extension uuid-ossp is installed */ if (!OidIsValid(result)) elog(ERROR, "function \"%s\" doesn't exist", orafce_sys_guid_source); uuid_generate_func_lxid = CURRENT_LXID; uuid_generate_func_oid = result; strcpy(uuid_generate_func_name, orafce_sys_guid_source); *reset_fmgr = true; } else *reset_fmgr = false; Assert(OidIsValid(uuid_generate_func_oid)); return uuid_generate_func_oid; } 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; text *result; char *tmp = NULL; size_t rest = 0; bool changed_locale = false; /* * 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) { int 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 = true; } } /* * 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(); { size_t size = 0; /* * 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_RE_THROW(); } 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); int16 typlen; bool typbyval; Size length; Datum value; int format; StringInfoData str; if (!OidIsValid(valtype)) 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); 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 } PG_FUNCTION_INFO_V1(ora_greatest); /* * ora_greatest(anyarray) returns anyelement */ Datum ora_greatest(PG_FUNCTION_ARGS) { PG_RETURN_DATUM(ora_greatest_least(fcinfo, true)); } PG_FUNCTION_INFO_V1(ora_least); /* * ora_least(anyarray) returns anyelement */ Datum ora_least(PG_FUNCTION_ARGS) { PG_RETURN_DATUM(ora_greatest_least(fcinfo, false)); } /* * ora_greatest_least(anyarray, bool) returns anyelement * Boolean parameter is true for greatest and false for least. */ static Datum ora_greatest_least(FunctionCallInfo fcinfo, bool greater) { Datum result; Datum value; ArrayType *array; ArrayIterator array_iterator; Oid element_type; Oid collation = PG_GET_COLLATION(); ArrayMetaState *my_extra = NULL; bool isnull; /* caller functions are marked as strict */ Assert(!PG_ARGISNULL(0)); Assert(!PG_ARGISNULL(1)); array = PG_GETARG_ARRAYTYPE_P(1); element_type = ARR_ELEMTYPE(array); Assert(element_type == get_fn_expr_argtype(fcinfo->flinfo, 0)); /* fast return */ if (array_contains_nulls(array)) PG_RETURN_NULL(); my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra; if (my_extra == NULL) { my_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt, sizeof(ArrayMetaState)); my_extra->element_type = ~element_type; fcinfo->flinfo->fn_extra = my_extra; } if (my_extra->element_type != element_type) { Oid sortop_oid; get_typlenbyvalalign(element_type, &my_extra->typlen, &my_extra->typbyval, &my_extra->typalign); if (greater) get_sort_group_operators(element_type, false, false, true, NULL, NULL, &sortop_oid, NULL); else get_sort_group_operators(element_type, true, false, false, &sortop_oid, NULL, NULL, NULL); my_extra->element_type = element_type; fmgr_info_cxt(get_opcode(sortop_oid), &my_extra->proc, fcinfo->flinfo->fn_mcxt); } /* Let's return the first parameter by default */ result = PG_GETARG_DATUM(0); array_iterator = array_create_iterator(array, 0, my_extra); while (array_iterate(array_iterator, &value, &isnull)) { /* not nulls, so run the operator */ if (!DatumGetBool(FunctionCall2Coll(&my_extra->proc, collation, result, value))) result = value; } result = datumCopy(result, my_extra->typbyval, my_extra->typlen); array_free_iterator(array_iterator); /* Avoid leaking memory when handed toasted input */ PG_FREE_IF_COPY(array, 1); PG_RETURN_DATUM(result); } #if PG_VERSION_NUM < 120000 static Datum FunctionCall0Coll(FmgrInfo *flinfo, Oid collation) { FunctionCallInfoData fcinfo_data; FunctionCallInfo fcinfo = &fcinfo_data; Datum result; InitFunctionCallInfoData(*fcinfo, flinfo, 0, collation, NULL, NULL); result = FunctionCallInvoke(fcinfo); /* Check for null result, since caller is clearly not expecting one */ if (fcinfo->isnull) elog(ERROR, "function %u returned NULL", flinfo->fn_oid); return result; } #endif PG_FUNCTION_INFO_V1(orafce_sys_guid); /* * Implementation of sys_guid() function * * Oracle uses guid based on mac address. The calculation is not too * difficult, but there are lot of depenedencies necessary for taking * mac address. Instead to making some static dependecies orafce uses * dynamic dependency on "uuid-ossp" extension, and calls choosed function * from this extension. */ Datum orafce_sys_guid(PG_FUNCTION_ARGS) { bool reset_fmgr; Oid funcoid; pg_uuid_t *uuid; bytea *result; funcoid = get_uuid_generate_func_oid(&reset_fmgr); if (reset_fmgr) fmgr_info_cxt(funcoid, &uuid_generate_func_finfo, TopTransactionContext); uuid = DatumGetUUIDP(FunctionCall0Coll(&uuid_generate_func_finfo, InvalidOid)); result = palloc(VARHDRSZ + UUID_LEN); SET_VARSIZE(result, VARHDRSZ + UUID_LEN); memcpy(VARDATA(result), uuid->data, UUID_LEN); PG_RETURN_BYTEA_P(result); } orafce-VERSION_4_14_4/parallel_schedule000066400000000000000000000001761501757153000200150ustar00rootroot00000000000000test: 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_4_14_4/parse_keyword.c000066400000000000000000000013441501757153000174420ustar00rootroot00000000000000#include "postgres.h" #include "parse_keyword.h" #include "parser/scanner.h" #if PG_VERSION_NUM >= 90600 #include "common/keywords.h" #else #include "parser/keywords.h" #endif #if PG_VERSION_NUM >= 120000 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_4_14_4/parse_keyword.h000066400000000000000000000001111501757153000174360ustar00rootroot00000000000000 extern const char *orafce_scan_keyword(const char *text, int *keycode); orafce-VERSION_4_14_4/pipe.c000066400000000000000000000767171501757153000155410ustar00rootroot00000000000000#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 "lib/stringinfo.h" #include "catalog/pg_type.h" #include "utils/builtins.h" #include "utils/date.h" #include "utils/numeric.h" #if PG_VERSION_NUM >= 140000 #include "utils/wait_event.h" #elif PG_VERSION_NUM >= 130000 #include "pgstat.h" #endif #include "shmmc.h" #include "pipe.h" #include "orafce.h" #include "builtins.h" #include /* * @ Pavel Stehule 2006-2023 */ #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_TIMEOUT 1 /* in sec 1000 days */ #define MAXWAIT 86400000 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 { long identity; bool is_valid; bool registered; char *pipe_name; char *creator; Oid uid; struct _queue_item *items; struct _queue_item *last_item; int16 count; int16 limit; int size; } orafce_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 { int tranche_id; LWLock shmem_lock; orafce_pipe *pipes; alert_event *events; alert_lock *locks; #if PG_VERSION_NUM >= 130000 ConditionVariable pipe_cv; ConditionVariable alert_cv; #endif size_t size; int sid; long identity_seq; vardata data[1]; /* flexible array member */ } sh_memory; #define sh_memory_size (offsetof(sh_memory, data)) static message_buffer *output_buffer = NULL; static message_buffer *input_buffer = NULL; static orafce_pipe* pipes = NULL; static long *identity_seq = NULL; #define NOT_INITIALIZED NULL LWLockId shmem_lockid = NOT_INITIALIZED; int sid; /* session id */ alert_event *events; alert_lock *locks; #if PG_VERSION_NUM >= 130000 static ConditionVariable *pipe_cv = NULL; ConditionVariable *alert_cv = NULL; #endif /* * 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); Assert(buffer->items_count > 0); Assert(buffer->next); message = buffer->next; Assert(message); *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) { bool found; /* reset is always false, really */ Assert(!reset); if (pipes == NULL) { sh_memory *sh_mem; LWLockAcquire(AddinShmemInitLock, LW_EXCLUSIVE); sh_mem = ShmemInitStruct("dbms_pipe", size, &found); if (!found) { int i; sh_mem->tranche_id = LWLockNewTrancheId(); LWLockInitialize(&sh_mem->shmem_lock, sh_mem->tranche_id); LWLockRegisterTranche(sh_mem->tranche_id, "orafce"); shmem_lockid = &sh_mem->shmem_lock; sh_mem->identity_seq = 0; sh_mem->size = size - sh_memory_size; ora_sinit(sh_mem->data, size, true); pipes = sh_mem->pipes = ora_salloc(max_pipes*sizeof(orafce_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; } #if PG_VERSION_NUM >= 130000 ConditionVariableInit(&sh_mem->pipe_cv); ConditionVariableInit(&sh_mem->alert_cv); pipe_cv = &sh_mem->pipe_cv; alert_cv = &sh_mem->alert_cv; #endif identity_seq = &sh_mem->identity_seq; } else { LWLockRegisterTranche(sh_mem->tranche_id, "orafce"); shmem_lockid = &sh_mem->shmem_lock; #if PG_VERSION_NUM >= 130000 pipe_cv = &sh_mem->pipe_cv; alert_cv = &sh_mem->alert_cv; #endif pipes = sh_mem->pipes; ora_sinit(sh_mem->data, sh_mem->size, false); sid = ++(sh_mem->sid); events = sh_mem->events; locks = sh_mem->locks; identity_seq = &sh_mem->identity_seq; } LWLockRelease(AddinShmemInitLock); } Assert(pipes != NULL); LWLockAcquire(shmem_lockid, LW_EXCLUSIVE); return true; } #define NOT_ASSIGNED_IDENTITY -1 /* * can be enhanced access/hash.h */ static orafce_pipe* find_pipe(text* pipe_name, bool* created, bool only_check, long *expected_identity, bool *identity_alarm) { int i; orafce_pipe *result = NULL; *created = false; Assert(!expected_identity || identity_alarm); if (identity_alarm) *identity_alarm = 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))) { if (expected_identity && *expected_identity >= 0 && pipes[i].identity != *expected_identity) { *identity_alarm = true; return result; } /* check owner if non public pipe */ if (pipes[i].creator != NULL && pipes[i].uid != GetUserId()) { ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("insufficient privilege"), errdetail("Insufficient privilege to access pipe"))); } if (expected_identity) *expected_identity = pipes[i].identity; return &pipes[i]; } } if (only_check) return result; if (expected_identity && *expected_identity >= 0) { *identity_alarm = true; 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]; if (expected_identity) *expected_identity = pipes[i].identity = *identity_seq++; } break; } return result; } static bool new_last(orafce_pipe *p, void *ptr, size_t size) { queue_item *aux_q; if (p->count >= p->limit && p->limit != -1) return false; if (p->limit == -1 && p->count > 0 && (p->size + size + sizeof(queue_item) > 8 * 1024)) 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->last_item = p->items; p->count = 1; return true; } if (NULL == (aux_q = ora_salloc(sizeof(queue_item)))) return false; p->last_item->next_item = aux_q; p->last_item = aux_q; aux_q->next_item = NULL; aux_q->ptr = ptr; p->count += 1; return true; } static void* remove_first(orafce_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); if (p->creator) { ora_sfree(p->creator); p->creator = NULL; } p->is_valid = false; } } return ptr; } /* copy message to local memory, if exists */ static message_buffer* get_from_pipe(text *pipe_name, bool *found, long *identity, bool *identity_alarm) { orafce_pipe *p; bool created; 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, identity, identity_alarm))) { if (!created) { message_buffer *shm_msg; 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, long *identity, bool *identity_alarm) { bool created; bool result = false; message_buffer *sh_ptr; if (!ora_lock_shmem(SHMEMMSGSZ, MAX_PIPES, MAX_EVENTS, MAX_LOCKS,false)) return false; for (;;) { orafce_pipe *p; if (NULL != (p = find_pipe(pipe_name, &created, false, identity, identity_alarm))) { 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, ptr->size)) { 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) { orafce_pipe *p; bool created; if (NULL != (p = find_pipe(pipe_name, &created, true, NULL, NULL))) { 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; if (p->creator) { ora_sfree(p->creator); p->creator = NULL; } } } } 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 reset_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))); reset_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; int32 size; Datum result; message_data_type next_type; message_data_type 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; (void) c;\ do \ { #define WATCH_TM_POST(t,et,c) \ if (GetNowFloat() >= et) \ PG_RETURN_INT32(RESULT_TIMEOUT); \ 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; bool found = false; instr_time start_time; int32 result = RESULT_TIMEOUT; long identity = NOT_ASSIGNED_IDENTITY; bool identity_alarm; #if PG_VERSION_NUM < 130000 long cycle = 0; #endif 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 (timeout < 0) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("negative timeout is not allowed"))); if (timeout > MAXWAIT) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("timeout is too large (maximum: %d)", MAXWAIT))); } else timeout = MAXWAIT; if (input_buffer) { pfree(input_buffer); input_buffer = NULL; } INSTR_TIME_SET_CURRENT(start_time); for (;;) { input_buffer = get_from_pipe(pipe_name, &found, &identity, &identity_alarm); if (found) { if (input_buffer) input_buffer->next = message_buffer_get_content(input_buffer); result = RESULT_DATA; break; } if (identity_alarm) break; if (timeout > 0) { instr_time cur_time; long cur_timeout; INSTR_TIME_SET_CURRENT(cur_time); INSTR_TIME_SUBTRACT(cur_time, start_time); cur_timeout = timeout * 1000L - (long) INSTR_TIME_GET_MILLISEC(cur_time); if (cur_timeout <= 0) break; #if PG_VERSION_NUM >= 130000 /* * Timeout should be less than INT_MAX, but we set 1 sec as protection * against deadlocks. */ if (cur_timeout > 1000) cur_timeout = 1000; if (ConditionVariableTimedSleep(pipe_cv, cur_timeout, PG_WAIT_EXTENSION)) { /* exit on timeout */ INSTR_TIME_SET_CURRENT(cur_time); INSTR_TIME_SUBTRACT(cur_time, start_time); cur_timeout = timeout * 1000L - (long) INSTR_TIME_GET_MILLISEC(cur_time); if (cur_timeout <= 0) break; } #else if (cycle++ % 10) CHECK_FOR_INTERRUPTS(); pg_usleep(10000L); /* exit on timeout */ INSTR_TIME_SET_CURRENT(cur_time); INSTR_TIME_SUBTRACT(cur_time, start_time); cur_timeout = timeout * 1000L - (long) INSTR_TIME_GET_MILLISEC(cur_time); if (cur_timeout <= 0) break; #endif } else break; } #if PG_VERSION_NUM >= 130000 ConditionVariableCancelSleep(); if (result == RESULT_DATA) ConditionVariableBroadcast(pipe_cv); #endif PG_RETURN_INT32(result); } Datum dbms_pipe_send_message(PG_FUNCTION_ARGS) { text *pipe_name = NULL; int timeout; int limit = 0; bool valid_limit; instr_time start_time; int32 result = RESULT_TIMEOUT; long identity = NOT_ASSIGNED_IDENTITY; bool identity_alarm; #if PG_VERSION_NUM < 130000 long cycle = 0; #endif 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 (timeout < 0) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("negative timeout is not allowed"))); if (timeout > MAXWAIT) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("timeout is too large (maximum: %d)", MAXWAIT))); } else timeout = MAXWAIT; if (PG_ARGISNULL(2)) valid_limit = false; else { limit = PG_GETARG_INT32(2); valid_limit = true; } INSTR_TIME_SET_CURRENT(start_time); for (;;) { if (add_to_pipe(pipe_name, output_buffer, limit, valid_limit, &identity, &identity_alarm)) { result = RESULT_DATA; break; } if (identity_alarm) break; if (timeout > 0) { instr_time cur_time; long cur_timeout; INSTR_TIME_SET_CURRENT(cur_time); INSTR_TIME_SUBTRACT(cur_time, start_time); cur_timeout = timeout * 1000L - (long) INSTR_TIME_GET_MILLISEC(cur_time); if (cur_timeout <= 0) break; #if PG_VERSION_NUM >= 130000 if (cur_timeout > 1000) cur_timeout = 1000; if (ConditionVariableTimedSleep(pipe_cv, cur_timeout, PG_WAIT_EXTENSION)) { /* exit on timeout */ INSTR_TIME_SET_CURRENT(cur_time); INSTR_TIME_SUBTRACT(cur_time, start_time); cur_timeout = timeout * 1000L - (long) INSTR_TIME_GET_MILLISEC(cur_time); if (cur_timeout <= 0) break; } #else if (cycle++ % 10) CHECK_FOR_INTERRUPTS(); pg_usleep(10000L); /* exit on timeout */ INSTR_TIME_SET_CURRENT(cur_time); INSTR_TIME_SUBTRACT(cur_time, start_time); cur_timeout = timeout * 1000L - (long) INSTR_TIME_GET_MILLISEC(cur_time); if (cur_timeout <= 0) break; #endif } else break; } #if PG_VERSION_NUM >= 130000 ConditionVariableCancelSleep(); if (result == RESULT_DATA) ConditionVariableBroadcast(pipe_cv); #endif reset_buffer(output_buffer, LOCALMSGSZ); PG_RETURN_INT32(result); } Datum dbms_pipe_unique_session_name(PG_FUNCTION_ARGS) { StringInfoData strbuf; 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)) { text *result; 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_TM_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; 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_TM_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; 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)) { orafce_pipe *p; if (NULL != (p = find_pipe(pipe_name, &created, false, NULL, NULL))) { if (!created) { ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("pipe creation error"), errdetail("Pipe is registered."))); } if (is_private) { char *user; p->uid = GetUserId(); user = (char*)DirectFunctionCall1(namein, CStringGetDatum(GetUserNameFromId(p->uid, false))); p->creator = ora_sstrcpy(user); pfree(user); } p->limit = limit_is_valid ? limit : -1; p->registered = true; LWLockRelease(shmem_lockid); PG_RETURN_VOID(); } } WATCH_TM_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_TM_POST(timeout, endtime, cycle); LOCK_ERROR(); #if PG_VERSION_NUM >= 130000 ConditionVariableBroadcast(pipe_cv); #endif 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_TM_POST(timeout, endtime, cycle); LOCK_ERROR(); #if PG_VERSION_NUM >= 130000 ConditionVariableBroadcast(pipe_cv); #endif 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_4_14_4/pipe.h000066400000000000000000000026661501757153000155360ustar00rootroot00000000000000#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 { int sid; int pid; 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 extern alert_event *events; extern alert_lock *locks; extern int sid; extern LWLockId shmem_lockid; #if PG_VERSION_NUM >= 130000 #include "storage/condition_variable.h" extern ConditionVariable *alert_cv; #endif orafce-VERSION_4_14_4/plunit.c000066400000000000000000000276771501757153000161200ustar00rootroot00000000000000/* * 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 ''); * * Purpose: * 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 ''); * * Purpose: * 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 ''); * * Purpose: * 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 ''); * * Purpose: * 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 ''); * * Purpose: * 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 ''); * * Purpose: * 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 ''); * * Purpose: * 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_4_14_4/plvdate.c000066400000000000000000000516641501757153000162350ustar00rootroot00000000000000/* 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-2024 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" #if PG_VERSION_NUM >= 160000 #include "varatt.h" #endif 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} }; static 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} }; static 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 ndays) { int d, dx; int y, m, auxd; holiday_desc hd; d = j2day(day+POSTGRES_EPOCH_JDATE); dx = ndays > 0? 1 : -1; while (ndays != 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; ndays -= dx; } return day; } static int ora_diff_bizdays(DateADT day1, DateADT day2) { int d, ndays; int y, m, auxd; holiday_desc hd; int loops = 0; bool start_is_bizday = false; if (day1 > day2) { DateADT aux_day; 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); ndays = 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; ndays += 1; } /* * decrease result when first day was bizday, but we don't want * calculate first day. */ if ( start_is_bizday && !include_start && ndays > 0) ndays -= 1; return ndays; } /**************************************************************** * PLVdate.add_bizdays * * Syntax: * FUNCTION add_bizdays(IN dt DATE, IN ndays int) RETURNS DATE; * * Purpose: * 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 ndays = PG_GETARG_INT32(1); PG_RETURN_DATEADT(ora_add_bizdays(day,ndays)); } /**************************************************************** * PLVdate.nearest_bizday * * Syntax: * FUNCTION nearest_bizday(IN dt DATE) RETURNS DATE; * * Purpose: * 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; * * Purpose: * 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; * * Purpose: * 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; * * Purpose: * 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; * * Purpose: * 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; * * Purpose: * 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 registration 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; * * Purpose: * 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; * * Purpose: * 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 registration 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 registration 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 registration 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 registration 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; * * Purpose: * 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 unregistration 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 * * Purpose: * 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 * * Purpose: * 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 * * Purpose: * 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 * * Purpose: * 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 * * Purpose: * 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 * * Purpose: * 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 * * Purpose: * 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 * * Purpose: * 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; * * Purpose: * 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; * * Purpose: * Set days as non bussines day, second arg specify year's * periodicity * ****************************************************************/ /**************************************************************** * PLVdate.display * * Syntax: * FUNCTION display() RETURNS void; * * Purpose: * Show current calendar * ****************************************************************/ orafce-VERSION_4_14_4/plvlex.c000066400000000000000000000142551501757153000161030ustar00rootroot00000000000000/* 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-2023 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 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; #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; orafce_lexnode *a = NULL; orafce_lexnode *dot = NULL; foreach(cell, list) { orafce_lexnode *nd = (orafce_lexnode *) lfirst(cell); if (qnames) { bool isdot = (IsType(nd, OTHERS) && (nd->str) && (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) { 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(text_to_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 [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); values[1] = 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); } orafce-VERSION_4_14_4/plvlex.h000066400000000000000000000002241501757153000160770ustar00rootroot00000000000000typedef struct { int typenode; char *str; int keycode; int lloc; char *sep; char *modificator; char *classname; } orafce_lexnode; orafce-VERSION_4_14_4/plvstr.c000066400000000000000000000721731501757153000161260ustar00rootroot00000000000000/* 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-2024 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 "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" #include #include 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); PG_FUNCTION_INFO_V1(oracle_substrb2); PG_FUNCTION_INFO_V1(oracle_substrb3); int orafce_substring_length_is_zero = ORAFCE_COMPATIBILITY_WARNING_ORACLE; 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; 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) { int sz; 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 if (start < 0) { dx = -1; beg = Min(c_len_txt + start, c_len_txt - c_len_pat); end = -1; if (beg <= end) return 0; /* out of range */ } else return 0; 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 if (start < 0) { dx = -1; beg = Min(len_txt + start, len_txt - len_pat); end = -1; if (beg <= end) return 0; /* out of range */ } else return 0; 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, *cur, *aux_cur; int i; #if defined(_MSC_VER) && (defined(_M_X64) || defined(__amd64__)) __int64 l; #else int l; #endif 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++) { char c; 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 (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; if (prefix == 0) PG_RETURN_BOOL(n == 0); do { if (n == prefix) { result = true; break; } n = n / 10; } while (n != 0); 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; if (prefix == 0) PG_RETURN_BOOL(n == 0); do { if (n == prefix) { result = true; break; } n = n / 10; } while (n != 0); 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 * ****************************************************************/ static text * empty_string() { text *result; result = palloc(VARHDRSZ); SET_VARSIZE(result, VARHDRSZ); return result; } 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; if (new_start < 1) PG_RETURN_TEXT_P(empty_string()); new_end = len + end + 1; if (new_end < 1) new_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; char *str_p; len_p = VARSIZE_ANY_EXHDR(pat); len_s = VARSIZE_ANY_EXHDR(str); str_p = VARDATA_ANY(str); while (count < num) { int i; char *aux_str_p, *pat_p; 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; len_p = VARSIZE_ANY_EXHDR(pat); len_s = VARSIZE_ANY_EXHDR(str); str_p = VARDATA_ANY(str) + len_s - 1; while (count < num) { char *pat_p; 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(); if (len == 0) { if (orafce_substring_length_is_zero == ORAFCE_COMPATIBILITY_WARNING_ORACLE || orafce_substring_length_is_zero == ORAFCE_COMPATIBILITY_WARNING_ORAFCE) elog(WARNING, "zero substring_length is used in substr function"); if (orafce_substring_length_is_zero == ORAFCE_COMPATIBILITY_WARNING_ORACLE || orafce_substring_length_is_zero == ORAFCE_COMPATIBILITY_ORACLE) 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)); } /* * len < 0 means "length is not specified". */ static bytea * ora_substrb(Datum str, int start, int len) { if (start == 0) start = 1; /* 0 is interpreted as 1 */ else if (start < 0) { bytea *t = DatumGetByteaPP(str); int n = VARSIZE_ANY_EXHDR(t); start = n + start + 1; if (start <= 0) return DatumGetByteaPP(DirectFunctionCall1(byteain, CStringGetDatum(""))); str = PointerGetDatum(t); /* save detoasted text */ } if (len < 0) return DatumGetByteaP(DirectFunctionCall2(bytea_substr_no_len, str, Int32GetDatum(start))); else return DatumGetByteaP(DirectFunctionCall3(bytea_substr, str, Int32GetDatum(start), Int32GetDatum(len))); } Datum oracle_substrb2(PG_FUNCTION_ARGS) { PG_RETURN_BYTEA_P(ora_substrb(PG_GETARG_DATUM(0), PG_GETARG_INT32(1), -1)); } Datum oracle_substrb3(PG_FUNCTION_ARGS) { PG_RETURN_BYTEA_P(ora_substrb(PG_GETARG_DATUM(0), PG_GETARG_INT32(1), PG_GETARG_INT32(2))); } orafce-VERSION_4_14_4/plvsubst.c000066400000000000000000000133541501757153000164520ustar00rootroot00000000000000/* 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-2024 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 "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 #include 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" static 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, 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) { int *dims; if (ndims != 1) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid parameter"), errdetail("Array of arguments has wrong dimension: %d", ndims))); p = (char *) 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) { if (items++ < nitems) { char *value; if (bitmap && (*bitmap & bitmask) == 0) value = pstrdup("NULL"); else { Datum itemvalue; 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_4_14_4/putline.c000066400000000000000000000161771501757153000162560ustar00rootroot00000000000000#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; } } static void dbms_output_disable_internal() { if (buffer) pfree(buffer); buffer = NULL; buffer_size = 0; buffer_len = 0; buffer_get = 0; } 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) { dbms_output_disable_internal(); 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); else if (!is_server_output && buffer) dbms_output_disable_internal(); 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_4_14_4/random.c000066400000000000000000000201611501757153000160420ustar00rootroot00000000000000/* * 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 #include #include #include #include "orafce.h" #include "builtins.h" #if PG_VERSION_NUM >= 160000 #include "varatt.h" #endif 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++) { double r = (double) rand(); int pos = (int) floor((r / ((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)); if (strlen(option) != 1) ereport(ERROR, (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION), errmsg("this first parameter value is more than 1 characters long"))); 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; /* Otherwise the returning string is in uppercase alpha characters. */ default: charset = upper_only; chrset_size = strlen(upper_only); break; } 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) { float8 aux; aux = low; low = high; high = aux; } /* * in the case high == low, we don't need to calculate result, but then * we change order of calls rand() functions, and this should break * customer's regress tests. To minimize impact on regress tests, we use same formula * for this case too. */ 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_4_14_4/regexp.c000066400000000000000000001007351501757153000160620ustar00rootroot00000000000000#include "postgres.h" #include "catalog/pg_type.h" #include "funcapi.h" #include "miscadmin.h" #include "regex/regex.h" #include "utils/array.h" #include "utils/builtins.h" #include "utils/memutils.h" #if PG_VERSION_NUM >= 150000 #include "utils/varlena.h" #endif #include "orafce.h" #include "builtins.h" /* all the options of interest for regex functions */ typedef struct pg_re_flags { int cflags; /* compile flags for Spencer's regex code */ bool glob; /* do it globally (for each occurrence) */ } pg_re_flags; /* cross-call state for regexp_match and regexp_split functions */ typedef struct regexp_matches_ctx { text *orig_str; /* data string in original TEXT form */ int nmatches; /* number of places where pattern matched */ int npatterns; /* number of capturing subpatterns */ /* We store start char index and end+1 char index for each match */ /* so the number of entries in match_locs is nmatches * npatterns * 2 */ int *match_locs; /* 0-based character indexes */ int next_match; /* 0-based index of next match to process */ /* workspace for build_regexp_match_result() */ Datum *elems; /* has npatterns elements */ bool *nulls; /* has npatterns elements */ pg_wchar *wide_str; /* wide-char version of original string */ char *conv_buf; /* conversion buffer, if needed */ int conv_bufsiz; /* size thereof */ } regexp_matches_ctx; /* * Backport code from PostgreSQL 15 */ PG_FUNCTION_INFO_V1(orafce_regexp_instr); PG_FUNCTION_INFO_V1(orafce_regexp_instr_no_start); PG_FUNCTION_INFO_V1(orafce_regexp_instr_no_n); PG_FUNCTION_INFO_V1(orafce_regexp_instr_no_endoption); PG_FUNCTION_INFO_V1(orafce_regexp_instr_no_flags); PG_FUNCTION_INFO_V1(orafce_regexp_instr_no_subexpr); PG_FUNCTION_INFO_V1(orafce_textregexreplace_noopt); PG_FUNCTION_INFO_V1(orafce_textregexreplace); PG_FUNCTION_INFO_V1(orafce_textregexreplace_extended); PG_FUNCTION_INFO_V1(orafce_textregexreplace_extended_no_n); PG_FUNCTION_INFO_V1(orafce_textregexreplace_extended_no_flags); #if PG_VERSION_NUM < 120000 /* this is the maximum number of cached regular expressions */ #ifndef MAX_CACHED_RES #define MAX_CACHED_RES 32 #endif /* this structure describes one cached regular expression */ typedef struct cached_re_str { char *cre_pat; /* original RE (not null terminated!) */ int cre_pat_len; /* length of original RE, in bytes */ int cre_flags; /* compile flags: extended,icase etc */ Oid cre_collation; /* collation to use */ regex_t cre_re; /* the compiled regular expression */ } cached_re_str; static int num_res = 0; /* # of cached re's */ static cached_re_str re_array[MAX_CACHED_RES]; /* cached re's */ /* * RE_compile_and_cache - compile a RE, caching if possible * * Returns regex_t * * * text_re --- the pattern, expressed as a TEXT object * cflags --- compile options for the pattern * collation --- collation to use for LC_CTYPE-dependent behavior * * Pattern is given in the database encoding. We internally convert to * an array of pg_wchar, which is what Spencer's regex package wants. */ static regex_t * RE_compile_and_cache(text *text_re, int cflags, Oid collation) { int text_re_len = VARSIZE_ANY_EXHDR(text_re); char *text_re_val = VARDATA_ANY(text_re); pg_wchar *pattern; int pattern_len; int i; int regcomp_result; cached_re_str re_temp; char errMsg[100]; /* * Look for a match among previously compiled REs. Since the data * structure is self-organizing with most-used entries at the front, our * search strategy can just be to scan from the front. */ for (i = 0; i < num_res; i++) { if (re_array[i].cre_pat_len == text_re_len && re_array[i].cre_flags == cflags && re_array[i].cre_collation == collation && memcmp(re_array[i].cre_pat, text_re_val, text_re_len) == 0) { /* * Found a match; move it to front if not there already. */ if (i > 0) { re_temp = re_array[i]; memmove(&re_array[1], &re_array[0], i * sizeof(cached_re_str)); re_array[0] = re_temp; } return &re_array[0].cre_re; } } /* * Couldn't find it, so try to compile the new RE. To avoid leaking * resources on failure, we build into the re_temp local. */ /* Convert pattern string to wide characters */ pattern = (pg_wchar *) palloc((text_re_len + 1) * sizeof(pg_wchar)); pattern_len = pg_mb2wchar_with_len(text_re_val, pattern, text_re_len); regcomp_result = pg_regcomp(&re_temp.cre_re, pattern, pattern_len, cflags, collation); pfree(pattern); if (regcomp_result != REG_OKAY) { /* re didn't compile (no need for pg_regfree, if so) */ /* * Here and in other places in this file, do CHECK_FOR_INTERRUPTS * before reporting a regex error. This is so that if the regex * library aborts and returns REG_CANCEL, we don't print an error * message that implies the regex was invalid. */ CHECK_FOR_INTERRUPTS(); pg_regerror(regcomp_result, &re_temp.cre_re, errMsg, sizeof(errMsg)); ereport(ERROR, (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION), errmsg("invalid regular expression: %s", errMsg))); } /* * We use malloc/free for the cre_pat field because the storage has to * persist across transactions, and because we want to get control back on * out-of-memory. The Max() is because some malloc implementations return * NULL for malloc(0). */ re_temp.cre_pat = malloc(Max(text_re_len, 1)); if (re_temp.cre_pat == NULL) { pg_regfree(&re_temp.cre_re); ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"))); } memcpy(re_temp.cre_pat, text_re_val, text_re_len); re_temp.cre_pat_len = text_re_len; re_temp.cre_flags = cflags; re_temp.cre_collation = collation; /* * Okay, we have a valid new item in re_temp; insert it into the storage * array. Discard last entry if needed. */ if (num_res >= MAX_CACHED_RES) { --num_res; Assert(num_res < MAX_CACHED_RES); pg_regfree(&re_array[num_res].cre_re); free(re_array[num_res].cre_pat); } if (num_res > 0) memmove(&re_array[1], &re_array[0], num_res * sizeof(cached_re_str)); re_array[0] = re_temp; num_res++; return &re_array[0].cre_re; } #endif #if PG_VERSION_NUM < 150000 /* * check_replace_text_has_escape * * Returns 0 if text contains no backslashes that need processing. * Returns 1 if text contains backslashes, but not regexp submatch specifiers. * Returns 2 if text contains regexp submatch specifiers (\1 .. \9). */ static int check_replace_text_has_escape(const text *replace_text) { int result = 0; const char *p = VARDATA_ANY(replace_text); const char *p_end = p + VARSIZE_ANY_EXHDR(replace_text); while (p < p_end) { /* Find next escape char, if any. */ p = memchr(p, '\\', p_end - p); if (p == NULL) break; p++; /* Note: a backslash at the end doesn't require extra processing. */ if (p < p_end) { if (*p >= '1' && *p <= '9') return 2; /* Found a submatch specifier, so done */ result = 1; /* Found some other sequence, keep looking */ p++; } } return result; } /* * charlen_to_bytelen() * Compute the number of bytes occupied by n characters starting at *p * * It is caller's responsibility that there actually are n characters; * the string need not be null-terminated. */ static int charlen_to_bytelen(const char *p, int n) { if (pg_database_encoding_max_length() == 1) { /* Optimization for single-byte encodings */ return n; } else { const char *s; for (s = p; n > 0; n--) s += pg_mblen(s); return s - p; } } /* * appendStringInfoText * * Append a text to str. * Like appendStringInfoString(str, text_to_cstring(t)) but faster. */ static void appendStringInfoText(StringInfo str, const text *t) { appendBinaryStringInfo(str, VARDATA_ANY(t), VARSIZE_ANY_EXHDR(t)); } /* * appendStringInfoRegexpSubstr * * Append replace_text to str, substituting regexp back references for * \n escapes. start_ptr is the start of the match in the source string, * at logical character position data_pos. */ static void appendStringInfoRegexpSubstr(StringInfo str, text *replace_text, regmatch_t *pmatch, char *start_ptr, int data_pos) { const char *p = VARDATA_ANY(replace_text); const char *p_end = p + VARSIZE_ANY_EXHDR(replace_text); while (p < p_end) { const char *chunk_start = p; int so; int eo; /* Find next escape char, if any. */ p = memchr(p, '\\', p_end - p); if (p == NULL) p = p_end; /* Copy the text we just scanned over, if any. */ if (p > chunk_start) appendBinaryStringInfo(str, chunk_start, p - chunk_start); /* Done if at end of string, else advance over escape char. */ if (p >= p_end) break; p++; if (p >= p_end) { /* Escape at very end of input. Treat same as unexpected char */ appendStringInfoChar(str, '\\'); break; } if (*p >= '1' && *p <= '9') { /* Use the back reference of regexp. */ int idx = *p - '0'; so = pmatch[idx].rm_so; eo = pmatch[idx].rm_eo; p++; } else if (*p == '&') { /* Use the entire matched string. */ so = pmatch[0].rm_so; eo = pmatch[0].rm_eo; p++; } else if (*p == '\\') { /* \\ means transfer one \ to output. */ appendStringInfoChar(str, '\\'); p++; continue; } else { /* * If escape char is not followed by any expected char, just treat * it as ordinary data to copy. (XXX would it be better to throw * an error?) */ appendStringInfoChar(str, '\\'); continue; } if (so >= 0 && eo >= 0) { /* * Copy the text that is back reference of regexp. Note so and eo * are counted in characters not bytes. */ char *chunk_start; int chunk_len; Assert(so >= data_pos); chunk_start = start_ptr; chunk_start += charlen_to_bytelen(chunk_start, so - data_pos); chunk_len = charlen_to_bytelen(chunk_start, eo - so); appendBinaryStringInfo(str, chunk_start, chunk_len); } } } /* * replace_text_regexp * * replace substring(s) in src_text that match pattern with replace_text. * The replace_text can contain backslash markers to substitute * (parts of) the matched text. * * cflags: regexp compile flags. * collation: collation to use. * search_start: the character (not byte) offset in src_text at which to * begin searching. * n: if 0, replace all matches; if > 0, replace only the N'th match. */ static text * orafce_replace_text_regexp(text *src_text, text *pattern_text, text *replace_text, int cflags, Oid collation, int search_start, int n) { text *ret_text; regex_t *re; int src_text_len = VARSIZE_ANY_EXHDR(src_text); int nmatches = 0; StringInfoData buf; regmatch_t pmatch[10]; /* main match, plus \1 to \9 */ int nmatch = lengthof(pmatch); pg_wchar *data; size_t data_len; size_t data_pos; char *start_ptr; int escape_status; initStringInfo(&buf); /* Convert data string to wide characters. */ data = (pg_wchar *) palloc((src_text_len + 1) * sizeof(pg_wchar)); data_len = pg_mb2wchar_with_len(VARDATA_ANY(src_text), data, src_text_len); /* Check whether replace_text has escapes, especially regexp submatches. */ escape_status = check_replace_text_has_escape(replace_text); #if PG_VERSION_NUM >= 150000 /* REG_NOSUB doesn't work well in pre PostgreSQL 15 */ /* If no regexp submatches, we can use REG_NOSUB. */ if (escape_status < 2) { cflags |= REG_NOSUB; /* Also tell pg_regexec we only want the whole-match location. */ nmatch = 1; } #endif /* Prepare the regexp. */ re = RE_compile_and_cache(pattern_text, cflags, collation); /* start_ptr points to the data_pos'th character of src_text */ start_ptr = (char *) VARDATA_ANY(src_text); data_pos = 0; while (search_start <= (int) data_len) { int regexec_result; CHECK_FOR_INTERRUPTS(); regexec_result = pg_regexec(re, data, data_len, search_start, NULL, /* no details */ nmatch, pmatch, 0); if (regexec_result == REG_NOMATCH) break; if (regexec_result != REG_OKAY) { char errMsg[100]; CHECK_FOR_INTERRUPTS(); pg_regerror(regexec_result, re, errMsg, sizeof(errMsg)); ereport(ERROR, (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION), errmsg("regular expression failed: %s", errMsg))); } /* * Count matches, and decide whether to replace this match. */ nmatches++; if (n > 0 && nmatches != n) { /* * No, so advance search_start, but not start_ptr/data_pos. (Thus, * we treat the matched text as if it weren't matched, and copy it * to the output later.) */ search_start = pmatch[0].rm_eo; if (pmatch[0].rm_so == pmatch[0].rm_eo) search_start++; continue; } /* * Copy the text to the left of the match position. Note we are given * character not byte indexes. */ if (pmatch[0].rm_so - data_pos > 0) { int chunk_len; chunk_len = charlen_to_bytelen(start_ptr, pmatch[0].rm_so - data_pos); appendBinaryStringInfo(&buf, start_ptr, chunk_len); /* * Advance start_ptr over that text, to avoid multiple rescans of * it if the replace_text contains multiple back-references. */ start_ptr += chunk_len; data_pos = pmatch[0].rm_so; } /* * Copy the replace_text, processing escapes if any are present. */ if (escape_status > 0) appendStringInfoRegexpSubstr(&buf, replace_text, pmatch, start_ptr, data_pos); else appendStringInfoText(&buf, replace_text); /* Advance start_ptr and data_pos over the matched text. */ start_ptr += charlen_to_bytelen(start_ptr, pmatch[0].rm_eo - data_pos); data_pos = pmatch[0].rm_eo; /* * If we only want to replace one occurrence, we're done. */ if (n > 0) break; /* * Advance search position. Normally we start the next search at the * end of the previous match; but if the match was of zero length, we * have to advance by one character, or we'd just find the same match * again. */ search_start = data_pos; if (pmatch[0].rm_so == pmatch[0].rm_eo) search_start++; } /* * Copy the text to the right of the last match. */ if (data_pos < data_len) { int chunk_len; chunk_len = ((char *) src_text + VARSIZE_ANY(src_text)) - start_ptr; appendBinaryStringInfo(&buf, start_ptr, chunk_len); } ret_text = cstring_to_text_with_len(buf.data, buf.len); pfree(buf.data); pfree(data); return ret_text; } #else #define orafce_replace_text_regexp replace_text_regexp #endif /* * RE_wchar_execute - execute a RE on pg_wchar data * * Returns true on match, false on no match * * re --- the compiled pattern as returned by RE_compile_and_cache * data --- the data to match against (need not be null-terminated) * data_len --- the length of the data string * start_search -- the offset in the data to start searching * nmatch, pmatch --- optional return area for match details * * Data is given as array of pg_wchar which is what Spencer's regex package * wants. */ static bool RE_wchar_execute(regex_t *re, pg_wchar *data, int data_len, int start_search, int nmatch, regmatch_t *pmatch) { int regexec_result; /* Perform RE match and return result */ regexec_result = pg_regexec(re, data, data_len, start_search, NULL, /* no details */ nmatch, pmatch, 0); if (regexec_result != REG_OKAY && regexec_result != REG_NOMATCH) { char errMsg[100]; /* re failed??? */ CHECK_FOR_INTERRUPTS(); pg_regerror(regexec_result, re, errMsg, sizeof(errMsg)); ereport(ERROR, (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION), errmsg("regular expression failed: %s", errMsg))); } return (regexec_result == REG_OKAY); } /* * setup_regexp_matches --- do the initial matching for regexp_match, * regexp_split, and related functions * * To avoid having to re-find the compiled pattern on each call, we do * all the matching in one swoop. The returned regexp_matches_ctx contains * the locations of all the substrings matching the pattern. * * start_search: the character (not byte) offset in orig_str at which to * begin the search. Returned positions are relative to orig_str anyway. * use_subpatterns: collect data about matches to parenthesized subexpressions. * ignore_degenerate: ignore zero-length matches. * fetching_unmatched: caller wants to fetch unmatched substrings. * * We don't currently assume that fetching_unmatched is exclusive of fetching * the matched text too; if it's set, the conversion buffer is large enough to * fetch any single matched or unmatched string, but not any larger * substring. (In practice, when splitting the matches are usually small * anyway, and it didn't seem worth complicating the code further.) */ static regexp_matches_ctx * setup_regexp_matches(text *orig_str, text *pattern, pg_re_flags *re_flags, int start_search, Oid collation, bool use_subpatterns, bool ignore_degenerate, bool fetching_unmatched) { regexp_matches_ctx *matchctx = palloc0(sizeof(regexp_matches_ctx)); int eml = pg_database_encoding_max_length(); int orig_len; pg_wchar *wide_str; int wide_len; regex_t *cpattern; regmatch_t *pmatch; int pmatch_len; int array_len; int array_idx; int prev_match_end; int prev_valid_match_end; int maxlen = 0; /* largest fetch length in characters */ int cflags; /* save original string --- we'll extract result substrings from it */ matchctx->orig_str = orig_str; /* convert string to pg_wchar form for matching */ orig_len = VARSIZE_ANY_EXHDR(orig_str); wide_str = (pg_wchar *) palloc(sizeof(pg_wchar) * (orig_len + 1)); wide_len = pg_mb2wchar_with_len(VARDATA_ANY(orig_str), wide_str, orig_len); /* set up the compiled pattern */ cflags = re_flags->cflags; #if PG_VERSION_NUM >= 150000 /* REG_NOSUB doesn't work well in pre PostgreSQL 15 */ if (!use_subpatterns) cflags |= REG_NOSUB; #endif cpattern = RE_compile_and_cache(pattern, cflags, collation); /* do we want to remember subpatterns? */ if (use_subpatterns && cpattern->re_nsub > 0) { matchctx->npatterns = cpattern->re_nsub; pmatch_len = cpattern->re_nsub + 1; } else { use_subpatterns = false; matchctx->npatterns = 1; pmatch_len = 1; } /* temporary output space for RE package */ pmatch = palloc(sizeof(regmatch_t) * pmatch_len); /* * the real output space (grown dynamically if needed) * * use values 2^n-1, not 2^n, so that we hit the limit at 2^28-1 rather * than at 2^27 */ array_len = re_flags->glob ? 255 : 31; matchctx->match_locs = (int *) palloc(sizeof(int) * array_len); array_idx = 0; /* search for the pattern, perhaps repeatedly */ prev_match_end = 0; prev_valid_match_end = 0; while (RE_wchar_execute(cpattern, wide_str, wide_len, start_search, pmatch_len, pmatch)) { /* * If requested, ignore degenerate matches, which are zero-length * matches occurring at the start or end of a string or just after a * previous match. */ if (!ignore_degenerate || (pmatch[0].rm_so < wide_len && pmatch[0].rm_eo > prev_match_end)) { /* enlarge output space if needed */ while (array_idx + matchctx->npatterns * 2 + 1 > array_len) { array_len += array_len + 1; /* 2^n-1 => 2^(n+1)-1 */ if (array_len > (int) (MaxAllocSize / sizeof(int))) ereport(ERROR, (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("too many regular expression matches"))); matchctx->match_locs = (int *) repalloc(matchctx->match_locs, sizeof(int) * array_len); } /* save this match's locations */ if (use_subpatterns) { int i; for (i = 1; i <= matchctx->npatterns; i++) { int so = pmatch[i].rm_so; int eo = pmatch[i].rm_eo; matchctx->match_locs[array_idx++] = so; matchctx->match_locs[array_idx++] = eo; if (so >= 0 && eo >= 0 && (eo - so) > maxlen) maxlen = (eo - so); } } else { int so = pmatch[0].rm_so; int eo = pmatch[0].rm_eo; matchctx->match_locs[array_idx++] = so; matchctx->match_locs[array_idx++] = eo; if (so >= 0 && eo >= 0 && (eo - so) > maxlen) maxlen = (eo - so); } matchctx->nmatches++; /* * check length of unmatched portion between end of previous valid * (nondegenerate, or degenerate but not ignored) match and start * of current one */ if (fetching_unmatched && pmatch[0].rm_so >= 0 && (pmatch[0].rm_so - prev_valid_match_end) > maxlen) maxlen = (pmatch[0].rm_so - prev_valid_match_end); prev_valid_match_end = pmatch[0].rm_eo; } prev_match_end = pmatch[0].rm_eo; /* if not glob, stop after one match */ if (!re_flags->glob) break; /* * Advance search position. Normally we start the next search at the * end of the previous match; but if the match was of zero length, we * have to advance by one character, or we'd just find the same match * again. */ start_search = prev_match_end; if (pmatch[0].rm_so == pmatch[0].rm_eo) start_search++; if (start_search > wide_len) break; } /* * check length of unmatched portion between end of last match and end of * input string */ if (fetching_unmatched && (wide_len - prev_valid_match_end) > maxlen) maxlen = (wide_len - prev_valid_match_end); /* * Keep a note of the end position of the string for the benefit of * splitting code. */ matchctx->match_locs[array_idx] = wide_len; if (eml > 1) { int64 maxsiz = eml * (int64) maxlen; int conv_bufsiz; /* * Make the conversion buffer large enough for any substring of * interest. * * Worst case: assume we need the maximum size (maxlen*eml), but take * advantage of the fact that the original string length in bytes is * an upper bound on the byte length of any fetched substring (and we * know that len+1 is safe to allocate because the varlena header is * longer than 1 byte). */ if (maxsiz > orig_len) conv_bufsiz = orig_len + 1; else conv_bufsiz = maxsiz + 1; /* safe since maxsiz < 2^30 */ matchctx->conv_buf = palloc(conv_bufsiz); matchctx->conv_bufsiz = conv_bufsiz; matchctx->wide_str = wide_str; } else { /* No need to keep the wide string if we're in a single-byte charset. */ pfree(wide_str); matchctx->wide_str = NULL; matchctx->conv_buf = NULL; matchctx->conv_bufsiz = 0; } /* Clean up temp storage */ pfree(pmatch); return matchctx; } /* * parse_re_flags - parse the options argument of regexp_match and friends * * flags --- output argument, filled with desired options * opts --- TEXT object, or NULL for defaults * * This accepts all the options allowed by any of the callers; callers that * don't want some have to reject them after the fact. */ static void parse_re_flags(pg_re_flags *flags, text *opts) { /* regex flavor is always folded into the compile flags */ flags->cflags = REG_ADVANCED; flags->glob = false; if (opts) { char *opt_p = VARDATA_ANY(opts); int opt_len = VARSIZE_ANY_EXHDR(opts); int i; for (i = 0; i < opt_len; i++) { switch (opt_p[i]) { case 'g': flags->glob = true; break; case 'b': /* BREs (but why???) */ flags->cflags &= ~(REG_ADVANCED | REG_EXTENDED | REG_QUOTE); break; case 'c': /* case sensitive */ flags->cflags &= ~REG_ICASE; break; case 'e': /* plain EREs */ flags->cflags |= REG_EXTENDED; flags->cflags &= ~(REG_ADVANCED | REG_QUOTE); break; case 'i': /* case insensitive */ flags->cflags |= REG_ICASE; break; case 'm': /* Perloid synonym for n */ case 'n': /* \n affects ^ $ . [^ */ flags->cflags |= REG_NEWLINE; break; case 'p': /* ~Perl, \n affects . [^ */ flags->cflags |= REG_NLSTOP; flags->cflags &= ~REG_NLANCH; break; case 'q': /* literal string */ flags->cflags |= REG_QUOTE; flags->cflags &= ~(REG_ADVANCED | REG_EXTENDED); break; case 's': /* single line, \n ordinary */ flags->cflags &= ~REG_NEWLINE; break; case 't': /* tight syntax */ flags->cflags &= ~REG_EXPANDED; break; case 'w': /* weird, \n affects ^ $ only */ flags->cflags &= ~REG_NLSTOP; flags->cflags |= REG_NLANCH; break; case 'x': /* expanded syntax */ flags->cflags |= REG_EXPANDED; break; default: ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid regular expression option: \"%.*s\"", pg_mblen(opt_p + i), opt_p + i))); break; } } } } /* * regexp_instr() * Return the match's position within the string */ Datum orafce_regexp_instr(PG_FUNCTION_ARGS) { text *str = NULL; text *pattern = NULL; int start = 1; int n = 1; int endoption = 0; text *flags = NULL; int subexpr = 0; int pos; pg_re_flags re_flags; regexp_matches_ctx *matchctx; if (PG_ARGISNULL(0) || PG_ARGISNULL(1)) PG_RETURN_NULL(); str = PG_GETARG_TEXT_PP(0); pattern = PG_GETARG_TEXT_PP(1); /* Collect optional parameters */ if (PG_NARGS() > 2) { if (PG_ARGISNULL(2)) PG_RETURN_NULL(); start = PG_GETARG_INT32(2); if (start <= 0) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("argument 'position' must be a number greater than 0"))); } if (PG_NARGS() > 3) { if (PG_ARGISNULL(3)) PG_RETURN_NULL(); n = PG_GETARG_INT32(3); if (n <= 0) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("argument 'occurence' must be a number greater than 0"))); } if (PG_NARGS() > 4) { if (PG_ARGISNULL(4)) PG_RETURN_NULL(); endoption = PG_GETARG_INT32(4); if (endoption != 0 && endoption != 1) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("argument 'return_opt' must be 0 or 1"))); } if (PG_NARGS() > 5) { if (!PG_ARGISNULL(5)) flags = PG_GETARG_TEXT_PP(5); } if (PG_NARGS() > 6) { if (PG_ARGISNULL(6)) PG_RETURN_NULL(); subexpr = PG_GETARG_INT32(6); if (subexpr < 0) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("argument 'group' must be a positive number"))); } /* Determine options */ parse_re_flags(&re_flags, flags); /* But we find all the matches anyway */ re_flags.glob = true; /* Do the matching */ matchctx = setup_regexp_matches(str, pattern, &re_flags, start - 1, PG_GET_COLLATION(), (subexpr > 0), /* need submatches? */ false, false); /* When n exceeds matches return 0 (includes case of no matches) */ if (n > matchctx->nmatches) PG_RETURN_INT32(0); /* When subexpr exceeds number of subexpressions return 0 */ if (subexpr > matchctx->npatterns) PG_RETURN_INT32(0); /* Select the appropriate match position to return */ pos = (n - 1) * matchctx->npatterns; if (subexpr > 0) pos += subexpr - 1; pos *= 2; if (endoption == 1) pos += 1; if (matchctx->match_locs[pos] >= 0) PG_RETURN_INT32(matchctx->match_locs[pos] + 1); else PG_RETURN_INT32(0); /* position not identifiable */ } /* This is separate to keep the opr_sanity regression test from complaining */ Datum orafce_regexp_instr_no_start(PG_FUNCTION_ARGS) { return orafce_regexp_instr(fcinfo); } /* This is separate to keep the opr_sanity regression test from complaining */ Datum orafce_regexp_instr_no_n(PG_FUNCTION_ARGS) { return orafce_regexp_instr(fcinfo); } /* This is separate to keep the opr_sanity regression test from complaining */ Datum orafce_regexp_instr_no_endoption(PG_FUNCTION_ARGS) { return orafce_regexp_instr(fcinfo); } /* This is separate to keep the opr_sanity regression test from complaining */ Datum orafce_regexp_instr_no_flags(PG_FUNCTION_ARGS) { return orafce_regexp_instr(fcinfo); } /* This is separate to keep the opr_sanity regression test from complaining */ Datum orafce_regexp_instr_no_subexpr(PG_FUNCTION_ARGS) { return orafce_regexp_instr(fcinfo); } /* * textregexreplace_noopt() * Return a string matched by a regular expression, with replacement. * * This version doesn't have an option argument: we default to case * sensitive match, replace the first instance only. */ Datum orafce_textregexreplace_noopt(PG_FUNCTION_ARGS) { text *s; text *p; text *r; if (PG_ARGISNULL(1) && !PG_ARGISNULL(0)) PG_RETURN_TEXT_P(PG_GETARG_TEXT_PP(0)); if (PG_ARGISNULL(0) || PG_ARGISNULL(1) || PG_ARGISNULL(2)) PG_RETURN_NULL(); s = PG_GETARG_TEXT_PP(0); p = PG_GETARG_TEXT_PP(1); r = PG_GETARG_TEXT_PP(2); PG_RETURN_TEXT_P(orafce_replace_text_regexp(s, p, r, REG_ADVANCED, PG_GET_COLLATION(), 0, 0)); } /* * textregexreplace() * Return a string matched by a regular expression, with replacement. */ Datum orafce_textregexreplace(PG_FUNCTION_ARGS) { text *s; text *p; text *r; text *opt = NULL; pg_re_flags flags; /* Always return NULL when start position or occurrence are NULL */ if (PG_NARGS() > 3 && PG_ARGISNULL(3)) PG_RETURN_NULL(); if (PG_NARGS() > 4 && PG_ARGISNULL(4)) PG_RETURN_NULL(); /* * Special case for second parameter in REGEXP_REPLACE, when NULL * returns the original value unless the start position or occurrences * are NULL too. In this case, it returns NULL (see instruction above). */ if (PG_ARGISNULL(1) && !PG_ARGISNULL(0)) PG_RETURN_TEXT_P(PG_GETARG_TEXT_PP(0)); if (PG_ARGISNULL(0) || PG_ARGISNULL(1) || PG_ARGISNULL(2)) PG_RETURN_NULL(); s = PG_GETARG_TEXT_PP(0); p = PG_GETARG_TEXT_PP(1); r = PG_GETARG_TEXT_PP(2); if (!PG_ARGISNULL(3)) opt = PG_GETARG_TEXT_PP(3); /* * regexp_replace() with four arguments will be preferentially resolved as * this form when the fourth argument is of type UNKNOWN. However, the * user might have intended to call textregexreplace_extended_no_n. If we * see flags that look like an integer, emit the same error that * parse_re_flags would, but add a HINT about how to fix it. */ if (opt && VARSIZE_ANY_EXHDR(opt) > 0) { char *opt_p = VARDATA_ANY(opt); if (*opt_p >= '0' && *opt_p <= '9') ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid regular expression option: \"%.*s\"", pg_mblen(opt_p), opt_p), errhint("If you meant to use regexp_replace() with a start parameter, cast the fourth argument to integer explicitly."))); } parse_re_flags(&flags, opt); PG_RETURN_TEXT_P(orafce_replace_text_regexp(s, p, r, flags.cflags, PG_GET_COLLATION(), 0, 0)); } /* * textregexreplace_extended() * Return a string matched by a regular expression, with replacement. * Extends textregexreplace by allowing a start position and the * choice of the occurrence to replace (0 means all occurrences). */ Datum orafce_textregexreplace_extended(PG_FUNCTION_ARGS) { text *s; text *p; text *r; int start = 1; int n = 1; text *flags = NULL; pg_re_flags re_flags; /* Always return NULL when start position or occurrence are NULL */ if (PG_NARGS() > 3 && PG_ARGISNULL(3)) PG_RETURN_NULL(); if (PG_NARGS() > 4 && PG_ARGISNULL(4)) PG_RETURN_NULL(); /* * Special case for second parameter in REGEXP_REPLACE, when NULL * returns the original value unless the start position or occurrences * are NULL too. In this case, it returns NULL (see instruction above). */ if (PG_ARGISNULL(1) && !PG_ARGISNULL(0)) PG_RETURN_TEXT_P(PG_GETARG_TEXT_PP(0)); if (PG_ARGISNULL(0) || PG_ARGISNULL(1) || PG_ARGISNULL(2)) PG_RETURN_NULL(); s = PG_GETARG_TEXT_PP(0); p = PG_GETARG_TEXT_PP(1); r = PG_GETARG_TEXT_PP(2); /* Collect optional parameters */ if (PG_NARGS() > 3) { start = PG_GETARG_INT32(3); if (start <= 0) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("argument 'position' must be a number greater than 0"))); } if (PG_NARGS() > 4) { n = PG_GETARG_INT32(4); if (n < 0) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("argument 'occurrence' must be a positive number"))); } if (PG_NARGS() > 5) { if (!PG_ARGISNULL(5)) flags = PG_GETARG_TEXT_PP(5); } /* Determine options */ parse_re_flags(&re_flags, flags); /* The global modifier is not allowed with Oracle */ if (re_flags.glob) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("modifier 'g' is not supported by this function"))); /* * If N was not specified, force the 'g' modifier. This is the * default in Oracle when no occurence is specified. */ if (PG_NARGS() <= 4) n = 0; /* Do the replacement(s) */ PG_RETURN_TEXT_P(orafce_replace_text_regexp(s, p, r, re_flags.cflags, PG_GET_COLLATION(), start - 1, n)); } /* This is separate to keep the opr_sanity regression test from complaining */ Datum orafce_textregexreplace_extended_no_n(PG_FUNCTION_ARGS) { return orafce_textregexreplace_extended(fcinfo); } /* This is separate to keep the opr_sanity regression test from complaining */ Datum orafce_textregexreplace_extended_no_flags(PG_FUNCTION_ARGS) { return orafce_textregexreplace_extended(fcinfo); } orafce-VERSION_4_14_4/replace_empty_string.c000066400000000000000000000160311501757153000210020ustar00rootroot00000000000000#include "postgres.h" #include "access/htup_details.h" #include "catalog/pg_type.h" #include "commands/trigger.h" #include "executor/spi.h" #include "miscadmin.h" #include "parser/parse_coerce.h" #include "utils/builtins.h" #include "utils/lsyscache.h" #include "utils/rel.h" #include "orafce.h" #include "builtins.h" PG_FUNCTION_INFO_V1(orafce_replace_empty_strings); PG_FUNCTION_INFO_V1(orafce_replace_null_strings); static void trigger_sanity_check(FunctionCallInfo fcinfo, const char *fname) { TriggerData *trigdata = (TriggerData *) fcinfo->context; /* sanity checks from autoinc.c */ if (!CALLED_AS_TRIGGER(fcinfo)) elog(ERROR, "%s: not fired by trigger manager", fname); if (!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event)) elog(ERROR, "%s: must be fired for row", fname); if (!TRIGGER_FIRED_BEFORE(trigdata->tg_event)) elog(ERROR, "%s: must be fired before event", fname); if (trigdata->tg_trigger->tgnargs > 1) elog(ERROR, "%s: only one trigger parameter is allowed", fname); } static HeapTuple get_rettuple(FunctionCallInfo fcinfo) { TriggerData *trigdata = (TriggerData *) fcinfo->context; HeapTuple rettuple = NULL; if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event)) rettuple = trigdata->tg_trigtuple; else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event)) rettuple = trigdata->tg_newtuple; else /* internal error */ elog(ERROR, "remove_empty_string: cannot process DELETE events"); return rettuple; } /* * Trigger argument is used as parameter that can enforce warning about modified * columns. When first argument is "on" or "true", then warnings will be raised. */ static bool should_raise_warnings(FunctionCallInfo fcinfo, bool *raise_error) { TriggerData *trigdata = (TriggerData *) fcinfo->context; Trigger *trigger = trigdata->tg_trigger; *raise_error = false; if (trigger->tgnargs > 0) { char **args = trigger->tgargs; if (strcmp(args[0], "on") == 0 || strcmp(args[0], "true") == 0 || strcmp(args[0], "warning") == 0) return true; if (strcmp(args[0], "error") == 0) { *raise_error = true; return true; } } return false; } /* * Detects emty strings in type text based fields and replaces them by NULL. */ Datum orafce_replace_empty_strings(PG_FUNCTION_ARGS) { TriggerData *trigdata = (TriggerData *) fcinfo->context; HeapTuple rettuple = NULL; TupleDesc tupdesc; int *resetcols = NULL; Datum *values = NULL; bool *nulls = NULL; Oid prev_typid = InvalidOid; bool is_string = false; int nresetcols = 0; int attnum; bool raise_warning = false; bool raise_error; char *relname = NULL; trigger_sanity_check(fcinfo, "replace_empty_strings"); raise_warning = should_raise_warnings(fcinfo, &raise_error); rettuple = get_rettuple(fcinfo); tupdesc = trigdata->tg_relation->rd_att; /* iterate over record's fields */ for (attnum = 1; attnum <= tupdesc->natts; attnum++) { Oid typid; if (TupleDescAttr(tupdesc, attnum - 1)->attisdropped) continue; /* simple cache - lot of time columns with same type is side by side */ typid = SPI_gettypeid(tupdesc, attnum); if (typid != prev_typid) { TYPCATEGORY category; bool ispreferred; Oid base_typid; base_typid = getBaseType(typid); get_type_category_preferred(base_typid, &category, &ispreferred); is_string = (category == TYPCATEGORY_STRING); prev_typid = typid; } if (is_string) { Datum value; bool isnull; value = SPI_getbinval(rettuple, tupdesc, attnum, &isnull); if (!isnull) { text *txt = DatumGetTextP(value); /* is it empty string (has zero length */ if (VARSIZE_ANY_EXHDR(txt) == 0) { if (!resetcols) { /* lazy allocation of dynamic memory */ resetcols = palloc0(tupdesc->natts * sizeof(int)); nulls = palloc0(tupdesc->natts * sizeof(bool)); values = palloc0(tupdesc->natts * sizeof(Datum)); } resetcols[nresetcols] = attnum; values[nresetcols] = (Datum) 0; nulls[nresetcols++] = true; if (raise_warning) { if (!relname) relname = SPI_getrelname(trigdata->tg_relation); elog(raise_error ? ERROR : WARNING, "Field \"%s\" of table \"%s\" is empty string (replaced by NULL).", SPI_fname(tupdesc, attnum), relname); } } } } } if (nresetcols > 0) { /* construct new tuple */ rettuple = heap_modify_tuple_by_cols(rettuple, tupdesc, nresetcols, resetcols, values, nulls); } if (relname) pfree(relname); if (resetcols) pfree(resetcols); if (values) pfree(values); if (nulls) pfree(nulls); return PointerGetDatum(rettuple); } /* * Detects NULL in type text based fields and replaces them by empty string */ Datum orafce_replace_null_strings(PG_FUNCTION_ARGS) { TriggerData *trigdata = (TriggerData *) fcinfo->context; HeapTuple rettuple = NULL; TupleDesc tupdesc; int *resetcols = NULL; Datum *values = NULL; bool *nulls = NULL; Oid prev_typid = InvalidOid; bool is_string = false; int nresetcols = 0; int attnum; bool raise_warning = false; bool raise_error; char *relname = NULL; trigger_sanity_check(fcinfo, "replace_null_strings"); raise_warning = should_raise_warnings(fcinfo, &raise_error); rettuple = get_rettuple(fcinfo); /* return fast when there are not any NULL */ if (!HeapTupleHasNulls(rettuple)) return PointerGetDatum(rettuple); tupdesc = trigdata->tg_relation->rd_att; /* iterate over record's fields */ for (attnum = 1; attnum <= tupdesc->natts; attnum++) { Oid typid; if (TupleDescAttr(tupdesc, attnum - 1)->attisdropped) continue; /* simple cache - lot of time columns with same type is side by side */ typid = SPI_gettypeid(tupdesc, attnum); if (typid != prev_typid) { TYPCATEGORY category; bool ispreferred; Oid base_typid; base_typid = getBaseType(typid); get_type_category_preferred(base_typid, &category, &ispreferred); is_string = (category == TYPCATEGORY_STRING); prev_typid = typid; } if (is_string) { bool isnull; (void) SPI_getbinval(rettuple, tupdesc, attnum, &isnull); if (isnull) { if (!resetcols) { /* lazy allocation of dynamic memory */ resetcols = palloc0(tupdesc->natts * sizeof(int)); nulls = palloc0(tupdesc->natts * sizeof(bool)); values = palloc0(tupdesc->natts * sizeof(Datum)); } resetcols[nresetcols] = attnum; values[nresetcols] = PointerGetDatum(cstring_to_text_with_len("", 0)); nulls[nresetcols++] = false; if (raise_warning) { if (!relname) relname = SPI_getrelname(trigdata->tg_relation); elog(raise_error ? ERROR : WARNING, "Field \"%s\" of table \"%s\" is NULL (replaced by '').", SPI_fname(tupdesc, attnum), relname); } } } } if (nresetcols > 0) { /* construct new tuple */ rettuple = heap_modify_tuple_by_cols(rettuple, tupdesc, nresetcols, resetcols, values, nulls); } if (relname) pfree(relname); if (resetcols) pfree(resetcols); if (values) pfree(values); if (nulls) pfree(nulls); return PointerGetDatum(rettuple); } orafce-VERSION_4_14_4/shmmc.c000066400000000000000000000157631501757153000157050ustar00rootroot00000000000000/* * * Shared memory control - based on alocating chunks aligned on * asize array (fibonachi), and dividing free bigger block. * */ #include "postgres.h" #include "shmmc.h" #include "orafce.h" #include #include #include #if PG_VERSION_NUM >= 160000 #include "varatt.h" #endif #define LIST_ITEMS 512 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}; static int *list_c = NULL; static list_item *list = NULL; static size_t max_size; /* * for debug static int cycle = 0; static int context; */ /* 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(ptr, '#', list[i].size); return; } } ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), errmsg("corrupted pointer"), errdetail("Failed while reallocating memory block in shared memory."), errhint("Please report this bug to the package authors."))); } 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("Please report this bug to the package authors."))); 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_4_14_4/shmmc.h000066400000000000000000000006001501757153000156720ustar00rootroot00000000000000#ifndef __SHMMC__ #define __SHMMC__ extern void ora_sinit(void *ptr, size_t size, bool create); extern void* ora_salloc(size_t size); extern void* ora_srealloc(void *ptr, size_t size); extern void ora_sfree(void* ptr); extern char* ora_sstrcpy(char *str); extern char* ora_scstring(text *str); extern void* salloc(size_t size); extern void* srealloc(void *ptr,size_t size); #endif orafce-VERSION_4_14_4/sql/000077500000000000000000000000001501757153000152155ustar00rootroot00000000000000orafce-VERSION_4_14_4/sql/aggregates.sql000066400000000000000000000055261501757153000200570ustar00rootroot00000000000000SET search_path TO public, oracle; -- 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_4_14_4/sql/dbms_alert_session_A.sql000066400000000000000000000050701501757153000220570ustar00rootroot00000000000000\set ECHO none -- wait for other processes, wait max 100 sec do $$ declare c int; begin if pg_try_advisory_xact_lock(1) then for i in 1..1000 loop perform pg_sleep(0.1); c := (select count(*) from pg_locks where locktype = 'advisory' and objid = 1 and not granted); if c = 2 then return; end if; end loop; else perform pg_advisory_xact_lock(1); end if; end; $$; \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_4_14_4/sql/dbms_alert_session_B.sql000066400000000000000000000040711501757153000220600ustar00rootroot00000000000000\set ECHO none -- wait for other processes, wait max 100 sec do $$ declare c int; begin if pg_try_advisory_xact_lock(1) then for i in 1..1000 loop perform pg_sleep(0.1); c := (select count(*) from pg_locks where locktype = 'advisory' and objid = 1 and not granted); if c = 2 then return; end if; end loop; else perform pg_advisory_xact_lock(1); end if; end; $$; \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_4_14_4/sql/dbms_alert_session_C.sql000066400000000000000000000012751501757153000220640ustar00rootroot00000000000000\set ECHO none -- wait for other processes, wait max 100 sec do $$ declare c int; begin if pg_try_advisory_xact_lock(1) then for i in 1..1000 loop perform pg_sleep(0.1); c := (select count(*) from pg_locks where locktype = 'advisory' and objid = 1 and not granted); if c = 2 then return; end if; end loop; else perform pg_advisory_xact_lock(1); end if; end; $$; \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_4_14_4/sql/dbms_output.sql000066400000000000000000000603211501757153000203050ustar00rootroot00000000000000\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.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.ENABLE(); 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.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.ENABLE(); 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.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.ENABLE(); 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.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.ENABLE(); 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.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.ENABLE(); 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.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.ENABLE(); 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.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.ENABLE(); 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.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.ENABLE(); 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.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.ENABLE(); 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.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.ENABLE(); 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.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.ENABLE(); 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.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.ENABLE(); 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.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.ENABLE(); 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.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.ENABLE(); 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.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.ENABLE(); 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.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.ENABLE(); 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.SERVEROUTPUT ('t'); PERFORM DBMS_OUTPUT.ENABLE(); 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.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.ENABLE(); 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.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.ENABLE(); 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.SERVEROUTPUT ('f'); PERFORM DBMS_OUTPUT.ENABLE(); 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(); -- SERVEROUTPUT [4] SERVEROUTPUT('t') get_line return null 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.SERVEROUTPUT ('t'); PERFORM DBMS_OUTPUT.ENABLE(); 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(); -- test dbms_output.serveroutput(false) clear buffer select dbms_output.serveroutput(true); do $$ BEGIN PERFORM DBMS_OUTPUT.PUT_LINE('1234242'); END$$; select dbms_output.serveroutput(false); do $$ BEGIN PERFORM DBMS_OUTPUT.PUT_LINE('1234242'); END$$; select dbms_output.serveroutput(true); do $$ BEGIN PERFORM DBMS_OUTPUT.PUT_LINE('1234242'); END$$; orafce-VERSION_4_14_4/sql/dbms_pipe.sql000066400000000000000000000031471501757153000177050ustar00rootroot00000000000000CREATE 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_4_14_4/sql/dbms_pipe_session_A.sql000066400000000000000000000165321501757153000217120ustar00rootroot00000000000000\set ECHO none -- wait for other processes, wait max 100 sec do $$ declare c int; begin if pg_try_advisory_xact_lock(1) then for i in 1..1000 loop perform pg_sleep(0.1); c := (select count(*) from pg_locks where locktype = 'advisory' and objid = 1 and not granted); if c = 1 then return; end if; end loop; else perform pg_advisory_xact_lock(1); end if; end; $$; 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_4_14_4/sql/dbms_pipe_session_B.sql000066400000000000000000000144431501757153000217120ustar00rootroot00000000000000\set ECHO none -- wait for other processes, wait max 100 sec do $$ declare c int; begin if pg_try_advisory_xact_lock(1) then for i in 1..1000 loop perform pg_sleep(0.1); c := (select count(*) from pg_locks where locktype = 'advisory' and objid = 1 and not granted); if c = 1 then return; end if; end loop; else perform pg_advisory_xact_lock(1); end if; end; $$; \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_4_14_4/sql/dbms_random.sql000066400000000000000000000020211501757153000202160ustar00rootroot00000000000000-- 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.value(10,10)::numeric(10, 8); SELECT dbms_random.value(15,10)::numeric(10, 8); SELECT dbms_random.seed(5); SELECT dbms_random.string('u', 10); SELECT dbms_random.string('l', 10); SELECT dbms_random.string('a', 10); SELECT dbms_random.string('x', 10); SELECT dbms_random.string('p', 10); SELECT dbms_random.string('uu', 10); -- error SELECT dbms_random.string('w', 10); -- although it is useless, and deprecated on Oracle -- it should be last command SELECT dbms_random.terminate(); orafce-VERSION_4_14_4/sql/dbms_sql.sql000066400000000000000000000154311501757153000175460ustar00rootroot00000000000000do $$ declare c int; strval varchar; intval int; nrows int default 30; begin c := dbms_sql.open_cursor(); call dbms_sql.parse(c, 'select ''ahoj'' || i, i from generate_series(1, :nrows) g(i)'); call dbms_sql.bind_variable(c, 'nrows', nrows); call dbms_sql.define_column(c, 1, strval); call dbms_sql.define_column(c, 2, intval); perform dbms_sql.execute(c); while dbms_sql.fetch_rows(c) > 0 loop call dbms_sql.column_value(c, 1, strval); call dbms_sql.column_value(c, 2, intval); raise notice 'c1: %, c2: %', strval, intval; end loop; call dbms_sql.close_cursor(c); end; $$; do $$ declare c int; strval varchar; intval int; nrows int default 30; begin c := dbms_sql.open_cursor(); call dbms_sql.parse(c, 'select ''ahoj'' || i, i from generate_series(1, :nrows) g(i)'); call dbms_sql.bind_variable(c, 'nrows', nrows); call dbms_sql.define_column(c, 1, strval); call dbms_sql.define_column(c, 2, intval); perform dbms_sql.execute(c); while dbms_sql.fetch_rows(c) > 0 loop strval := dbms_sql.column_value_f(c, 1, strval); intval := dbms_sql.column_value_f(c, 2, intval); raise notice 'c1: %, c2: %', strval, intval; end loop; call dbms_sql.close_cursor(c); end; $$; drop table if exists foo; create table foo(a int, b varchar, c numeric); do $$ declare c int; begin c := dbms_sql.open_cursor(); call dbms_sql.parse(c, 'insert into foo values(:a, :b, :c)'); for i in 1..100 loop call dbms_sql.bind_variable(c, 'a', i); call dbms_sql.bind_variable(c, 'b', 'Ahoj ' || i); call dbms_sql.bind_variable(c, 'c', i + 0.033); perform dbms_sql.execute(c); end loop; end; $$; select * from foo; truncate foo; do $$ declare c int; begin c := dbms_sql.open_cursor(); call dbms_sql.parse(c, 'insert into foo values(:a, :b, :c)'); for i in 1..100 loop perform dbms_sql.bind_variable_f(c, 'a', i); perform dbms_sql.bind_variable_f(c, 'b', 'Ahoj ' || i); perform dbms_sql.bind_variable_f(c, 'c', i + 0.033); perform dbms_sql.execute(c); end loop; end; $$; select * from foo; truncate foo; do $$ declare c int; a int[]; b varchar[]; ca numeric[]; begin c := dbms_sql.open_cursor(); call dbms_sql.parse(c, 'insert into foo values(:a, :b, :c)'); a := ARRAY[1, 2, 3, 4, 5]; b := ARRAY['Ahoj', 'Nazdar', 'Bazar']; ca := ARRAY[3.14, 2.22, 3.8, 4]; call dbms_sql.bind_array(c, 'a', a); call dbms_sql.bind_array(c, 'b', b); call dbms_sql.bind_array(c, 'c', ca); raise notice 'inserted rows %d', dbms_sql.execute(c); end; $$; select * from foo; truncate foo; -- should not to crash, when bound array is null do $$ declare c int; ca numeric[]; begin c := dbms_sql.open_cursor(); call dbms_sql.parse(c, 'insert into foo values(:a, 10, 20)'); call dbms_sql.bind_array(c, 'a', ca); raise notice 'inserted rows %d', dbms_sql.execute(c); end; $$; -- should not to crash, when we try to touch result without execute do $$ declare c int; a int[]; begin c := dbms_sql.open_cursor(); call dbms_sql.parse(c, 'select i from generate_series(1, 2) g(i)'); call dbms_sql.define_array(c, 1, a, 10, 1); call dbms_sql.column_value(c, 1, a); call dbms_sql.close_cursor(c); end; $$; -- should not to crash, when the variable is overwritten DO $$ declare c integer; n integer; c2 numeric; begin c := dbms_sql.open_cursor(); call dbms_sql.parse(c, 'INSERT INTO foo(a) VALUES (:bnd2)'); call dbms_sql.bind_variable(c, 'bnd2', c2); call dbms_sql.bind_variable(c, 'bnd2', c2); n := dbms_sql.execute(c); end $$; -- should not to crash, when we try to read column without data do $$ declare c int; strval varchar; intval int; begin c := dbms_sql.open_cursor(); call dbms_sql.parse(c, 'select ''foo'', 1'); call dbms_sql.define_column(c, 1, strval); call dbms_sql.define_column(c, 2, intval); perform dbms_sql.execute(c); while dbms_sql.fetch_rows(c) > -1 loop call dbms_sql.column_value(c, 1, strval); end loop; call dbms_sql.close_cursor(c); end; $$; select * from foo; truncate foo; do $$ declare c int; a int[]; b varchar[]; ca numeric[]; begin c := dbms_sql.open_cursor(); call dbms_sql.parse(c, 'insert into foo values(:a, :b, :c)'); a := ARRAY[1, 2, 3, 4, 5]; b := ARRAY['Ahoj', 'Nazdar', 'Bazar']; ca := ARRAY[3.14, 2.22, 3.8, 4]; call dbms_sql.bind_array(c, 'a', a, 2, 3); call dbms_sql.bind_array(c, 'b', b, 3, 4); call dbms_sql.bind_array(c, 'c', ca); raise notice 'inserted rows %d', dbms_sql.execute(c); end; $$; select * from foo; truncate foo; do $$ declare c int; a int[]; b varchar[]; ca numeric[]; begin c := dbms_sql.open_cursor(); call dbms_sql.parse(c, 'select i, ''Ahoj'' || i, i + 0.003 from generate_series(1, 35) g(i)'); call dbms_sql.define_array(c, 1, a, 10, 1); call dbms_sql.define_array(c, 2, b, 10, 1); call dbms_sql.define_array(c, 3, ca, 10, 1); perform dbms_sql.execute(c); while dbms_sql.fetch_rows(c) > 0 loop call dbms_sql.column_value(c, 1, a); call dbms_sql.column_value(c, 2, b); call dbms_sql.column_value(c, 3, ca); raise notice 'a = %', a; raise notice 'b = %', b; raise notice 'c = %', ca; end loop; call dbms_sql.close_cursor(c); end; $$; drop table foo; create table tab1(c1 integer, c2 numeric); create or replace procedure single_Row_insert(c1 integer, c2 numeric) as $$ declare c integer; n integer; begin c := dbms_sql.open_cursor(); call dbms_sql.parse(c, 'INSERT INTO tab1 VALUES (:bnd1, :bnd2)'); call dbms_sql.bind_variable(c, 'bnd1', c1); call dbms_sql.bind_variable(c, 'bnd2', c2); n := dbms_sql.execute(c); call dbms_sql.debug_cursor(c); call dbms_sql.close_cursor(c); end $$language plpgsql; do $$ declare a numeric(7,2); begin call single_Row_insert(2,a); end $$; select * from tab1; do $$ declare a numeric(7,2) default 1.23; begin call single_Row_insert(2,a); end $$; select * from tab1; select * from tab1 where c2 is null; do $$ declare a numeric(7,2); begin call single_Row_insert(0,a); -- single_Row_insert(0, null) end $$; select * from tab1; do $$ declare a numeric(7,2) default 1.23; begin call single_Row_insert(0,a); -- single_Row_insert(0, 1.23) end $$; select * from tab1; drop procedure single_Row_insert; drop table tab1; create table test(id text); insert into test(id) values ('1'), (null); -- should not to crash do $$ declare cursor int; id text; row_counter int := 0; begin cursor := dbms_sql.open_cursor(); call dbms_sql.parse(cursor, 'select id from test'); call dbms_sql.define_column(cursor, 1, 'id'); perform dbms_sql.execute(cursor); while dbms_sql.fetch_rows(cursor) > 0 loop row_counter = row_counter + 1; raise notice 'process row #%', row_counter; call dbms_sql.column_value(cursor, 1, id); raise notice 'row id: `%`', id; end loop; call dbms_sql.close_cursor(cursor); end; $$; drop table test; orafce-VERSION_4_14_4/sql/dbms_utility.sql000066400000000000000000000052631501757153000204540ustar00rootroot00000000000000\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(); /* * Test for dbms_utility.get_time(), the result is rounded * to have constant result in the regression test. */ DO $$ DECLARE start_time integer; end_time integer; BEGIN start_time := DBMS_UTILITY.GET_TIME(); PERFORM pg_sleep(2); end_time := DBMS_UTILITY.GET_TIME(); -- clamp long runtime on slow build machines to the 2s the testsuite is expecting IF end_time BETWEEN start_time + 300 AND start_time + 1000 THEN end_time := start_time + 250; END IF; RAISE NOTICE 'Execution time: % seconds', trunc((end_time - start_time)::numeric/100); END $$; orafce-VERSION_4_14_4/sql/files.sql000066400000000000000000000122341501757153000170420ustar00rootroot00000000000000SET 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 --run this under unprivileged user CREATE ROLE test_role_files LOGIN; SET ROLE TO test_role_files; -- should to fail, unpriviliged user cannot to change utl_file_dir INSERT INTO utl_file.utl_file_dir(dir) VALUES('test_tmp_dir'); 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'); SELECT checkFlushFile(utl_file.tmpdir()); SELECT utl_file.fremove(utl_file.tmpdir(), 'regressflush_orafce.txt'); SET ROLE TO DEFAULT; DROP FUNCTION checkFlushFile(text); DELETE FROM utl_file.utl_file_dir; -- try to use named directory INSERT INTO utl_file.utl_file_dir(dir, dirname) VALUES(utl_file.tmpdir(), 'TMPDIR'); SELECT gen_file('TMPDIR'); SELECT read_file('TMPDIR'); SELECT utl_file.fremove('TMPDIR', 'regress_orafce.txt'); DROP FUNCTION gen_file(text); DROP FUNCTION read_file(text); DELETE FROM utl_file.utl_file_dir; -- reconnect \c SET ROLE TO test_role_files; -- use any function from orafce, should not to fail SELECT oracle.add_months('2024-05-20', 1); SET ROLE TO DEFAULT; DROP ROLE test_role_files; orafce-VERSION_4_14_4/sql/init.sql000066400000000000000000000003051501757153000166770ustar00rootroot00000000000000\set ECHO none set client_min_messages TO error; CREATE EXTENSION IF NOT EXISTS orafce; GRANT ALL ON SCHEMA public TO public; SET client_min_messages TO default; SET search_path TO public, oracle; orafce-VERSION_4_14_4/sql/nlssort.sql000066400000000000000000000033741501757153000174510ustar00rootroot00000000000000-- Tests for nlssort -- Skip this test unless it's a Linux/glibc system with the "en_US.utf8" locale installed. SELECT getdatabaseencoding() <> 'UTF8' OR NOT EXISTS (SELECT 1 FROM pg_collation WHERE collname = 'en_US' AND collencoding = pg_char_to_encoding('UTF8')) OR version() !~ 'linux-gnu' AS skip_test \gset \if :skip_test \quit \endif \set ECHO none SET client_min_messages = error; DROP DATABASE IF EXISTS regression_sort; -- For PG >= 15 explicitly set the locale provider libc when creating the -- database with SQL_ASCII encoding. Otherwise during installcheck the new -- database may use the ICU locale provider (from template0) which does not -- support this encoding. SELECT current_setting('server_version_num')::integer >= 150000 AS set_libc_locale_provider \gset \if :set_libc_locale_provider CREATE DATABASE regression_sort WITH TEMPLATE = template0 ENCODING='SQL_ASCII' LC_COLLATE='C' LC_CTYPE='C' LOCALE_PROVIDER='libc'; \else CREATE DATABASE regression_sort WITH TEMPLATE = template0 ENCODING='SQL_ASCII' LC_COLLATE='C' LC_CTYPE='C'; \endif \c regression_sort SET client_min_messages = error; CREATE EXTENSION orafce; SET search_path TO public, oracle; 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_4_14_4/sql/nvarchar2.sql000066400000000000000000000023001501757153000176170ustar00rootroot00000000000000\set VERBOSITY terse SET client_encoding = utf8; SET search_path TO public, oracle; -- -- 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_4_14_4/sql/orafce.sql000066400000000000000000001724201501757153000172030ustar00rootroot00000000000000\set ECHO none SET client_min_messages = warning; SET DATESTYLE TO ISO; SET client_encoding = utf8; \set ECHO all SET search_path TO public, oracle; -- -- test built-in date type oracle compatibility functions -- SELECT add_months (date '2003-08-01', 3); SELECT add_months (date '2003-08-01', -3); SELECT add_months (date '2003-08-21', -3); SELECT add_months (date '2003-01-31', 1); SELECT add_months (date '2008-02-28', 1); SELECT add_months (date '2008-02-29', 1); SELECT add_months (date '2008-01-31', 12); SELECT add_months (date '2008-01-31', -12); SELECT add_months (date '2008-01-31', 95903); SELECT add_months (date '2008-01-31', -80640); SELECT add_months (date '03-21-2008',3); SELECT add_months (date '21-MAR-2008',3); SELECT add_months (date '21-MAR-08',3); SELECT add_months (date '2008-MAR-21',3); SELECT add_months (date 'March 21,2008',3); SELECT add_months(date '03/21/2008',3); SELECT add_months(date '20080321',3); SELECT add_months(date '080321',3); 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); 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(date '1900-02-01'); SELECT last_day(date '2000-02-01'); SELECT last_day(date '2007-02-01'); SELECT last_day(date '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 public, oracle; SELECT next_day (date '2003-08-01', 'TUESDAY'); SELECT next_day (date '2003-08-06', 'WEDNESDAY'); SELECT next_day (date '2003-08-06', 'SUNDAY'); SELECT next_day (date '2008-01-01', 'sun'); SELECT next_day (date '2008-01-01', 'sunAAA'); SELECT next_day (date '2008-01-01', 1); SELECT next_day (date '2008-01-01', 7); 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); 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')); 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')); SELECT sys_extract_utc(timestamptz '2024-08-17 00:41:26.655376+02'); SET timezone to 'europe/prague'; SELECT sys_extract_utc(oracle.date '2024-08-17 00:41:26.655376'); SET timezone 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 public,oracle; 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 0 = instr('ab;cdx', ';', 0); 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'; set orafce.using_substring_zero_width_in_substr TO orafce; select oracle.substr('TechOnTheNet', -8, 0) = ''; set orafce.using_substring_zero_width_in_substr TO oracle; select oracle.substr('TechOnTheNet', -8, 0) is null; set orafce.using_substring_zero_width_in_substr TO warning_oracle; select oracle.substr('TechOnTheNet', -8, 0) is null; set orafce.using_substring_zero_width_in_substr TO default; select oracle.substr('TechOnTheNet', -8, 0) is null; 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::int, 2); select nvl(NULL::double precision, 1); select nvl(1.1::double precision, 1); select nvl(1.1::numeric, 1); 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.rvrs ('l', -2, -5); 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_char('-44444'); select to_char('1234567890123456'); select to_char('123.456'); select to_char('123abc'); select to_char('你儽123@$%abc'); select to_char('1234567890123456789012345678901234567890123456789012345678901234567890'); select to_char(''); select to_char(' '); select to_char(null); 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 to_date('', 'yyyy-mm-dd'); SELECT to_date('112012', 'J'); SELECT to_date('1003/03/15', 'yyyy/mm/dd'); SELECT oracle.to_date('', 'yyyy-mm-dd'); SELECT oracle.to_date('112012', 'J'); SELECT oracle.to_date('1003-03-15', 'yyyy-mm-dd'); SET orafce.oracle_compatibility_date_limit TO off; SELECT oracle.to_date('112012', 'J'); SELECT oracle.to_date('1003/03/15', 'yyyy/mm/dd'); 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.qualified_sql_name('1broken'); select dbms_assert.simple_sql_name('1broken'); 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('ļ½ļ½‚ļ½ƒ'); SELECT octet_length(to_single_byte('ļ½ļ½‚ļ½ƒ')); -- 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 oracle.orafce__obsolete_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 public,oracle; -- 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 public,oracle; -- 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 public,oracle; --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 public,oracle; --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 public,oracle; -- -- 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); -- -- trigger functions -- CREATE TABLE trg_test(a varchar, b int, c varchar, d date, e int); CREATE TRIGGER trg_test_xx BEFORE INSERT OR UPDATE ON trg_test FOR EACH ROW EXECUTE PROCEDURE oracle.replace_empty_strings(true); \pset null *** INSERT INTO trg_test VALUES('',10, 'AHOJ', NULL, NULL); INSERT INTO trg_test VALUES('AHOJ', NULL, '', '2020-01-01', 100); SELECT * FROM trg_test; DELETE FROM trg_test; DROP TRIGGER trg_test_xx ON trg_test; CREATE TRIGGER trg_test_xx BEFORE INSERT OR UPDATE ON trg_test FOR EACH ROW EXECUTE PROCEDURE oracle.replace_null_strings(); INSERT INTO trg_test VALUES(NULL, 10, 'AHOJ', NULL, NULL); INSERT INTO trg_test VALUES('AHOJ', NULL, NULL, '2020-01-01', 100); SELECT * FROM trg_test; DROP TABLE trg_test; SELECT oracle.unistr('\0441\043B\043E\043D'); SELECT oracle.unistr('d\u0061t\U00000061'); -- run-time error SELECT oracle.unistr('wrong: \db99'); SELECT oracle.unistr('wrong: \db99\0061'); SELECT oracle.unistr('wrong: \+00db99\+000061'); SELECT oracle.unistr('wrong: \+2FFFFF'); SELECT oracle.unistr('wrong: \udb99\u0061'); SELECT oracle.unistr('wrong: \U0000db99\U00000061'); SELECT oracle.unistr('wrong: \U002FFFFF'); ---- -- Tests for the greatest/least scalar function ---- -- The PostgreSQL native function returns NULL only if all parameters are nulls SELECT greatest(2, 6, 8); SELECT greatest(2, NULL, 8); SELECT least(2, 6, 8); SELECT least(2, NULL, 8); -- The Oracle function returns NULL on NULL input, even a single parameter SELECT oracle.greatest(2, 6, 8, 4); SELECT oracle.greatest(2, NULL, 8, 4); SELECT oracle.least(2, 6, 8, 1); SELECT oracle.least(2, NULL, 8, 1); -- Test different data type SELECT oracle.greatest('A'::text, 'B'::text, 'C'::text, 'D'::text); SELECT oracle.greatest('A'::bpchar, 'B'::bpchar, 'C'::bpchar, 'D'::bpchar); SELECT oracle.greatest(1::bigint,2::bigint,3::bigint,4::bigint); SELECT oracle.greatest(1::integer,2::integer,3::integer,4::integer); SELECT oracle.greatest(1::smallint,2::smallint,3::smallint,4::smallint); SELECT oracle.greatest(1.2::numeric,2.4::numeric,2.3::numeric,2.2::numeric); SELECT oracle.greatest(1.2::double precision,2.4::double precision,2.3::double precision,2.2::double precision); SELECT oracle.greatest(1.2::real,2.4::real,2.2::real,2.3::real); SELECT oracle.least('A'::text, 'B'::text, 'C'::text, 'D'::text); SELECT oracle.least('A'::bpchar, 'B'::bpchar, 'C'::bpchar, 'D'::bpchar); SELECT oracle.least(1::bigint,2::bigint,3::bigint,4::bigint); SELECT oracle.least(1::integer,2::integer,3::integer,4::integer); SELECT oracle.least(1::smallint,2::smallint,3::smallint,4::smallint); SELECT oracle.least(1.2::numeric,2.4::numeric,2.3::numeric,2.2::numeric); SELECT oracle.least(1.2::double precision,2.4::double precision,2.3::double precision,2.2::double precision); SELECT oracle.least(1.2::real,2.4::real,2.2::real,2.3::real); SELECT i, oracle.greatest(100, 24, 1234, 12, i) FROM generate_series(1,3) g(i); -- test remainder function CREATE TABLE testorafce_remainder(v1 int, v2 int); INSERT INTO testorafce_remainder VALUES(24, 7); INSERT INTO testorafce_remainder VALUES(24, 6); INSERT INTO testorafce_remainder VALUES(24, 5); INSERT INTO testorafce_remainder VALUES(-58, -10); INSERT INTO testorafce_remainder VALUES(58, 10); INSERT INTO testorafce_remainder VALUES(58, -10); INSERT INTO testorafce_remainder VALUES(58, 10); INSERT INTO testorafce_remainder VALUES(-44, -10); INSERT INTO testorafce_remainder VALUES(44, 10); INSERT INTO testorafce_remainder VALUES(44, -10); INSERT INTO testorafce_remainder VALUES(44, 10); SELECT v1, v2, oracle.remainder(v1, v2) FROM testorafce_remainder; SELECT v1, v2, oracle.remainder(v1::smallint, v2::smallint) FROM testorafce_remainder; SELECT v1, v2, oracle.remainder(v1::bigint, v2::bigint) FROM testorafce_remainder; SELECT v1, v2, oracle.remainder(v1::numeric, v2::numeric) FROM testorafce_remainder; DROP TABLE testorafce_remainder; orafce-VERSION_4_14_4/sql/orafce2.sql000066400000000000000000000002721501757153000172600ustar00rootroot00000000000000-- 2) fails and throws error: 'ERROR: could not determine polymorphic type -- because input has type "unknown"' select oracle.decode('2012-01-01', '2012-01-01', 23, '2012-01-02', 24); orafce-VERSION_4_14_4/sql/regexp_func.sql000066400000000000000000000601171501757153000202500ustar00rootroot00000000000000-- Test for the regexp_*() function \set ECHO none SET client_min_messages = warning; SET client_encoding = utf8; \set VERBOSITY terse \set ECHO all SET search_path TO oracle, "$user", public, pg_catalog; ---- -- Tests for REGEXP_LIKE() ---- -- ORACLE> SELECT 1 FROM DUAL WHERE REGEXP_LIKE('a'||CHR(10)||'d', 'a.d'); -> NULL SELECT REGEXP_LIKE('a'||CHR(10)||'d', 'a.d'); -- ORACLE> SELECT 1 FROM DUAL WHERE REGEXP_LIKE('a'||CHR(10)||'d', 'a.d', 'm'); -> NULL SELECT REGEXP_LIKE('a'||CHR(10)||'d', 'a.d', 'm'); -- ORACLE> SELECT 1 FROM DUAL WHERE REGEXP_LIKE('a'||CHR(10)||'d', 'a.d', 'n'); -> 1 SELECT REGEXP_LIKE('a'||CHR(10)||'d', 'a.d', 'n'); -- ORACLE> SELECT 1 FROM DUAL WHERE REGEXP_LIKE('Steven', '^Ste(v|ph)en$'); -> 1 SELECT REGEXP_LIKE('Steven', '^Ste(v|ph)en$'); -- ORACLE> SELECT 1 FROM DUAL WHERE regexp_like('foo' || chr(10) || 'bar' || chr(10) || 'bequq' || chr(10) || 'baz', '^bar'); -> NULL SELECT REGEXP_LIKE('foo' || chr(10) || 'bar' || chr(10) || 'bequq' || chr(10) || 'baz', '^bar'); -- ORACLE> SELECT 1 FROM DUAL WHERE regexp_like('foo' || chr(10) || 'bar' || chr(10) || 'bequq' || chr(10) || 'baz', 'bar'); -> 1 SELECT REGEXP_LIKE('foo' || chr(10) || 'bar' || chr(10) || 'bequq' || chr(10) || 'baz', 'bar'); -- ORACLE> SELECT 1 FROM DUAL WHERE regexp_like('foo' || chr(10) || 'bar' || chr(10) || 'bequq' || chr(10) || 'baz', '^bar', 'm'); -> 1 SELECT REGEXP_LIKE('foo' || chr(10) || 'bar' || chr(10) || 'bequq' || chr(10) || 'baz', '^bar', 'm'); -- ORACLE> SELECT 1 FROM DUAL WHERE regexp_like('foo' || chr(10) || 'bar' || chr(10) || 'bequq' || chr(10) || 'baz', '^bar', 'n'); -> NULL SELECT REGEXP_LIKE('foo' || chr(10) || 'bar' || chr(10) || 'bequq' || chr(10) || 'baz', '^bar', 'n'); -- ORACLE> SELECT 1 FROM DUAL WHERE REGEXP_LIKE('GREEN', '([aeiou])\1'); -> NULL SELECT REGEXP_LIKE('GREEN', '([aeiou])\1'); -- ORACLE> SELECT 1 FROM DUAL WHERE REGEXP_LIKE('GREEN', '([aeiou])\1', 'i'); -> 1 SELECT REGEXP_LIKE('GREEN', '([aeiou])\1', 'i'); -- ORACLE> SELECT 1 FROM DUAL WHERE REGEXP_LIKE('ORANGE' || chr(10) || 'GREEN', '([aeiou])\1', 'i'); -> 1 SELECT REGEXP_LIKE('ORANGE' || chr(10) || 'GREEN', '([aeiou])\1', 'i'); -- ORACLE> SELECT 1 FROM DUAL WHERE REGEXP_LIKE('ORANGE' || chr(10) || 'GREEN', '^..([aeiou])\1', 'i'); -> NULL SELECT REGEXP_LIKE('ORANGE' || chr(10) || 'GREEN', '^..([aeiou])\1', 'i'); -- ORACLE> SELECT 1 FROM DUAL WHERE REGEXP_LIKE('ORANGE' || chr(10) || 'GREEN', '([aeiou])\1', 'in'); -> 1 SELECT REGEXP_LIKE('ORANGE' || chr(10) || 'GREEN', '([aeiou])\1', 'in'); -- ORACLE> SELECT 1 FROM DUAL WHERE REGEXP_LIKE('ORANGE' || chr(10) || 'GREEN', '^..([aeiou])\1', 'in'); -> NULL SELECT REGEXP_LIKE('ORANGE' || chr(10) || 'GREEN', '^..([aeiou])\1', 'in'); -- ORACLE> SELECT 1 FROM DUAL WHERE REGEXP_LIKE('ORANGE' || chr(10) || 'GREEN', '^..([aeiou])\1', 'im'); -> 1 SELECT REGEXP_LIKE('ORANGE' || chr(10) || 'GREEN', '^..([aeiou])\1', 'im'); ---- -- Tests for REGEXP_COUNT() ---- -- ORACLE> SELECT REGEXP_COUNT('a,b' || chr(10) || 'c','[^,]+') FROM DUAL; -> 2 SELECT REGEXP_COUNT('a,b' || chr(10) || 'c','[^,]+'); -- ORACLE> SELECT REGEXP_COUNT('a,b' || chr(10) || 'c','b.c') FROM DUAL; -> 0 SELECT REGEXP_COUNT('a,b' || chr(10) || 'c','b.c'); -- ORACLE> SELECT REGEXP_COUNT('a'||CHR(10)||'d', 'a.d') FROM DUAL; -> 0 SELECT REGEXP_COUNT('a'||CHR(10)||'d', 'a.d'); -- ORACLE> SELECT REGEXP_COUNT('a'||CHR(10)||'d', 'a.d', 1, 'm') FROM DUAL; -> 0 SELECT REGEXP_COUNT('a'||CHR(10)||'d', 'a.d', 1, 'm'); -- ORACLE> SELECT REGEXP_COUNT('a'||CHR(10)||'d', 'a.d', 1, 'n') FROM DUAL; -> 1 SELECT REGEXP_COUNT('a'||CHR(10)||'d', 'a.d', 1, 'n'); -- ORACLE> SELECT REGEXP_COUNT('Steven', '^Ste(v|ph)en$') FROM DUAL; -> 1 SELECT REGEXP_COUNT('Steven', '^Ste(v|ph)en$'); -- ORACLE> SELECT REGEXP_COUNT('foo' || chr(10) || 'bar' || chr(10) || 'bequq' || chr(10) || 'baz', '^bar') FROM DUAL; -> 0 SELECT REGEXP_COUNT('foo' || chr(10) || 'bar' || chr(10) || 'bequq' || chr(10) || 'baz', '^bar'); -- ORACLE> SELECT REGEXP_COUNT('foo' || chr(10) || 'bar' || chr(10) || 'bequq' || chr(10) || 'baz', 'bar') FROM DUAL; -> 1 SELECT REGEXP_COUNT('foo' || chr(10) || 'bar' || chr(10) || 'bequq' || chr(10) || 'baz', 'bar'); -- ORACLE> SELECT REGEXP_COUNT('foo' || chr(10) || 'bar' || chr(10) || 'bequq' || chr(10) || 'baz', '^bar', 0, 'm') FROM DUAL; -> ORA-01428: argument '0' is out of range SELECT REGEXP_COUNT('foo' || chr(10) || 'bar' || chr(10) || 'bequq' || chr(10) || 'baz', '^bar', 0, 'm'); -- ORACLE> SELECT REGEXP_COUNT('foo' || chr(10) || 'bar' || chr(10) || 'bequq' || chr(10) || 'baz', '^bar', 1, 'm') FROM DUAL; -> 1 SELECT REGEXP_COUNT('foo' || chr(10) || 'bar' || chr(10) || 'bequq' || chr(10) || 'baz', '^bar', 1, 'm'); -- ORACLE> SELECT REGEXP_COUNT('foo' || chr(10) || 'bar' || chr(10) || 'bequq' || chr(10) || 'baz', '^bar', 1, 'n') FROM DUAL; -> 0 SELECT REGEXP_COUNT('foo' || chr(10) || 'bar' || chr(10) || 'bequq' || chr(10) || 'baz', '^bar', 1, 'n'); -- ORACLE> SELECT REGEXP_COUNT('GREEN', '([aeiou])\1') FROM DUAL; -> 0 SELECT REGEXP_COUNT('GREEN', '([aeiou])\1'); -- ORACLE> SELECT REGEXP_COUNT('GREEN', '([aeiou])\1', 1, 'i') FROM DUAL; -> 1 SELECT REGEXP_COUNT('GREEN', '([aeiou])\1', 1, 'i'); -- ORACLE> SELECT REGEXP_COUNT('ORANGE' || chr(10) || 'GREEN', '([aeiou])\1', 1, 'i') FROM DUAL; -> 1 SELECT REGEXP_COUNT('ORANGE' || chr(10) || 'GREEN', '([aeiou])\1', 1, 'i'); -- ORACLE> SELECT REGEXP_COUNT('ORANGE' || chr(10) || 'GREEN', '^..([aeiou])\1', 1, 'i') FROM DUAL; -> 0 SELECT REGEXP_COUNT('ORANGE' || chr(10) || 'GREEN', '^..([aeiou])\1', 1, 'i'); -- ORACLE> SELECT REGEXP_COUNT('ORANGE' || chr(10) || 'GREEN', '([aeiou])\1', 1, 'in') FROM DUAL; -> 1 SELECT REGEXP_COUNT('ORANGE' || chr(10) || 'GREEN', '([aeiou])\1', 1, 'in'); -- ORACLE> SELECT REGEXP_COUNT('ORANGE' || chr(10) || 'GREEN', '^..([aeiou])\1', 1, 'in') FROM DUAL; -> 0 SELECT REGEXP_COUNT('ORANGE' || chr(10) || 'GREEN', '^..([aeiou])\1', 1, 'in'); -- ORACLE> SELECT REGEXP_COUNT('ORANGE' || chr(10) || 'GREEN', '^..([aeiou])\1', 1, 'im') FROM DUAL; -> 1 SELECT REGEXP_COUNT('ORANGE' || chr(10) || 'GREEN', '^..([aeiou])\1', 1, 'im'); -- ORACLE> SELECT REGEXP_COUNT('123123123123123', '(12)3', 1, 'i') REGEXP_COUNT FROM DUAL; -> 5 SELECT REGEXP_COUNT('123123123123123', '(12)3', 1, 'i'); -- ORACLE> SELECT REGEXP_COUNT('123123123123', '123', 3, 'i') COUNT FROM DUAL; -> 3 SELECT REGEXP_COUNT('123123123123', '123', 3, 'i'); -- ORACLE> SELECT REGEXP_COUNT('ABC123', '[A-Z]'), REGEXP_COUNT('A1B2C3', '[A-Z]') FROM DUAL; -> 3 | 3 SELECT REGEXP_COUNT('ABC123', '[A-Z]'), oracle.REGEXP_COUNT('A1B2C3', '[A-Z]'); -- ORACLE> SELECT REGEXP_COUNT('ABC123', '[A-Z][0-9]'), REGEXP_COUNT('A1B2C3', '[A-Z][0-9]') FROM DUAL; -> 1 | 3 SELECT REGEXP_COUNT('ABC123', '[A-Z][0-9]'), oracle.REGEXP_COUNT('A1B2C3', '[A-Z][0-9]'); -- ORACLE> SELECT REGEXP_COUNT('ABC123', '^[A-Z][0-9]'), REGEXP_COUNT('A1B2C3', '^[A-Z][0-9]') FROM DUAL; -> 0 | 1 SELECT REGEXP_COUNT('ABC123', '^[A-Z][0-9]'), oracle.REGEXP_COUNT('A1B2C3', '^[A-Z][0-9]'); -- ORACLE> SELECT REGEXP_COUNT('ABC123', '([A-Z][0-9]){2}'), REGEXP_COUNT('A1B2C3', '([A-Z][0-9]){2}') FROM DUAL; -> 0 | 1 SELECT REGEXP_COUNT('ABC123', '([A-Z][0-9]){2}'), oracle.REGEXP_COUNT('A1B2C3', '([A-Z][0-9]){2}'); -- Check negatives values that must throw an error SELECT REGEXP_COUNT('ORANGE' || chr(10) || 'GREEN', '^..([aeiou])\1', -1, 'i'); ---- -- Tests for REGEXP_INSTR() ---- -- ORACLE> SELECT REGEXP_INSTR('1234567890', '(123)(4(56)(78))') FROM DUAL; -> 1 SELECT REGEXP_INSTR('1234567890', '(123)(4(56)(78))'); -- ORACLE> SELECT REGEXP_INSTR('1234567890', '(4(56)(78))') FROM DUAL; -> 4 SELECT REGEXP_INSTR('1234567890', '(4(56)(78))'); -- ORACLE> SELECT regexp_instr('1234567890', '123(4(56)(78))', 3) FROM DUAL; -> 0 SELECT REGEXP_INSTR('1234567890', '(123)(4(56)(78))', 3); -- ORACLE> SELECT REGEXP_INSTR('1234567890', '(4(56)(78))', 3) FROM DUAL; -> 4 SELECT REGEXP_INSTR('1234567890', '(4(56)(78))', 3); -- ORACLE> SELECT REGEXP_INSTR('500 Oracle Parkway, Redwood Shores, CA', '[^ ]+', 1, 6) FROM DUAL; -> 37 SELECT REGEXP_INSTR('500 Oracle Parkway, Redwood Shores, CA', '[^ ]+', 1, 6); -- ORACLE> SELECT REGEXP_INSTR('500 Oracle Parkway, Redwood Shores, CA', '[S|R|P][[:alpha:]]{6}', 3, 2, 0) FROM DUAL; -> 21 SELECT REGEXP_INSTR('500 Oracle Parkway, Redwood Shores, CA', '[S|R|P][[:alpha:]]{6}', 3, 2, 0); -- ORACLE> SELECT REGEXP_INSTR('500 Oracle Parkway, Redwood Shores, CA', '[S|R|P][[:alpha:]]{6}', 3, 2, 1) FROM DUAL; -> 28 SELECT REGEXP_INSTR('500 Oracle Parkway, Redwood Shores, CA', '[S|R|P][[:alpha:]]{6}', 3, 2, 1); -- ORACLE> SELECT REGEXP_INSTR('500 Oracle Parkway, Redwood Shores, CA', '[s|r|p][[:alpha:]]{6}', 3, 2, 1, 'i') FROM DUAL; -> 28 SELECT REGEXP_INSTR('500 Oracle Parkway, Redwood Shores, CA', '[q|r|p][[:alpha:]]{6}', 3, 2, 1, 'i'); -- ORACLE> SELECT REGEXP_INSTR('1234567890', '(123)(4(56)(78))', 1, 1, 0, 'i', 0) FROM DUAL; -> 1 SELECT REGEXP_INSTR('1234567890', '(123)(4(56)(78))', 1, 1, 0, 'i', 0); -- ORACLE> SELECT REGEXP_INSTR('1234567890', '(123)(4(56)(78))', 1, 1, 0, 'i', 1) FROM DUAL; -> 1 SELECT REGEXP_INSTR('1234567890', '(123)(4(56)(78))', 1, 1, 0, 'i', 1); -- ORACLE> SELECT REGEXP_INSTR('1234567890', '(123)(4(56)(78))', 1, 1, 0, 'i', 2) FROM DUAL; -> 4 SELECT REGEXP_INSTR('1234567890', '(123)(4(56)(78))', 1, 1, 0, 'i', 2); -- ORACLE> SELECT REGEXP_INSTR('1234567890', '(123)(4(56)(78))', 1, 1, 0, 'i', 4) FROM DUAL; -> 7 SELECT REGEXP_INSTR('1234567890', '(123)(4(56)(78))', 1, 1, 0, 'i', 4); -- ORACLE> SELECT REGEXP_INSTR('1234567890 1234567890', '(123)(4(56)(78))', 1, 1, 0, 'i', 4) FROM DUAL; -> 7 SELECT REGEXP_INSTR('1234567890 1234567890', '(123)(4(56)(78))', 1, 1, 0, 'i', 4); -- ORACLE> SELECT REGEXP_INSTR('1234567890 1234567890', '(123)(4(56)(78))', 1, 2, 0, 'i', 4) FROM DUAL; -> 18 SELECT REGEXP_INSTR('1234567890 1234567890', '(123)(4(56)(78))', 1, 2, 0, 'i', 4); -- ORACLE> SELECT REGEXP_INSTR('1234567890 1234567890', '(123)(4(56)(78))', 1, 2, 1, 'i', 4) FROM DUAL; -> 20 SELECT REGEXP_INSTR('1234567890 1234567890', '(123)(4(56)(78))', 1, 2, 1, 'i', 4); -- ORACLE> SELECT REGEXP_INSTR('1234567890 1234567890 1234567890', '(123)(4(56)(78))', 1, 3, 0,'i', 4) FROM DUAL; -> 29 SELECT REGEXP_INSTR('1234567890 1234567890 1234567890', '(123)(4(56)(78))', 1, 3, 0, 'i', 4); -- ORACLE> SELECT REGEXP_INSTR('1234567890 1234567890 1234567890', '(123)(4(56)(78))', 1, 3, 1,'i', 4) FROM DUAL; -> 31 SELECT REGEXP_INSTR('1234567890 1234567890 1234567890', '(123)(4(56)(78))', 1, 3, 1, 'i', 4); -- DROP TABLE regexp_temp; -- CREATE TABLE regexp_temp(empName varchar2(20), emailID varchar2(20)); -- INSERT INTO regexp_temp (empName, emailID) VALUES ('John Doe', 'johndoe@example.com'); -- INSERT INTO regexp_temp (empName, emailID) VALUES ('Jane Doe', 'janedoe'); -- COMMIT; CREATE TEMPORARY TABLE regexp_temp(empName varchar(20), emailID varchar(20)); INSERT INTO regexp_temp (empName, emailID) VALUES ('John Doe', 'johndoe@example.com'); INSERT INTO regexp_temp (empName, emailID) VALUES ('Jane Doe', 'janedoe'); -- -- ORACLE> SELECT emailID, REGEXP_INSTR(emailID, '\w+@\w+(\.\w+)+') "IS_A_VALID_EMAIL" FROM regexp_temp; -- EMAILID IS_A_VALID_EMAIL -- -------------------- ---------------- -- johndoe@example.com 1 -- example.com 0 SELECT emailID, REGEXP_INSTR(emailID, '\w+@\w+(\.\w+)+') FROM regexp_temp; -- -- ORACLE> SELECT emailID, REGEXP_INSTR(emailID, '\w+@\w+(\.\w+)+', 1, 1, 0, 'i', 0) "IS_A_VALID_EMAIL" FROM regexp_temp; -- EMAILID IS_A_VALID_EMAIL -- -------------------- ---------------- -- johndoe@example.com 1 -- example.com 0 SELECT emailID, REGEXP_INSTR(emailID, '\w+@\w+(\.\w+)+', 1, 1, 0, 'i', 0) FROM regexp_temp; -- -- ORACLE> SELECT emailID, REGEXP_INSTR(emailID, '\w+@\w+(\.\w+)+', 1, 1, 0, 'i', 1) "IS_A_VALID_EMAIL" FROM regexp_temp; -- EMAILID IS_A_VALID_EMAIL -- -------------------- ---------------- -- johndoe@example.com 16 -- example.com 0 SELECT emailID, REGEXP_INSTR(emailID, '\w+@\w+(\.\w+)+', 1, 1, 0, 'i', 1) FROM regexp_temp; DROP TABLE regexp_temp; -- Check negatives values that must throw an error SELECT REGEXP_INSTR('1234567890 1234567890 1234567890', '(123)(4(56)(78))', -1, 3, 1, 'i', 4); SELECT REGEXP_INSTR('1234567890 1234567890 1234567890', '(123)(4(56)(78))', 1, -3, 1, 'i', 4); SELECT REGEXP_INSTR('1234567890 1234567890 1234567890', '(123)(4(56)(78))', 1, 3, -1, 'i', 4); SELECT REGEXP_INSTR('1234567890 1234567890 1234567890', '(123)(4(56)(78))', 1, 3, 1, 'i', -4); -- ORACLE> SELECT REGEXP_INSTR('123 123456 1234567, 1234567 1234567 12', '[^ ]+', 1, 6) FROM DUAL; -> 37 SELECT REGEXP_INSTR('123 123456 1234567, 1234567 1234567 12', '[^ ]+', 1, 6) ; -- ORACLE> SELECT REGEXP_INSTR('123 123456 1234567, 1234567 1234567 12', '[^ ]+', 1, 6, 1) FROM DUAL; -> 39 SELECT REGEXP_INSTR('123 123456 1234567, 1234567 1234567 12', '[^ ]+', 1, 6, 1) ; -- ORACLE> SELECT REGEXP_INSTR('123 123456 1234567, 1234567 1234567 12', '[^ ]+', 1, 6, 1, 'i') FROM DUAL; -> 39 SELECT REGEXP_INSTR('123 123456 1234567, 1234567 1234567 12', '[^ ]+', 1, 6, 1, 'i') ; ---- -- Tests for REGEXP_SUBSTR() ---- -- ORACLE> SELECT REGEXP_SUBSTR('a,b'||chr(10)||'c','[^,]+',1,2) FROM DUAL; -> b and c SELECT REGEXP_SUBSTR('a,b'||chr(10)||'c','[^,]+',1,2); -- ORACLE> SELECT REGEXP_SUBSTR('a,b'||chr(10)||'c','.',1,4) FROM DUAL; -> c SELECT REGEXP_SUBSTR('a,b'||chr(10)||'c','.',1,4); -- ORACLE> SELECT REGEXP_SUBSTR('number of your street, zipcode town, FR', ',[^,]+') FROM DUAL; -> , zipcode town SELECT REGEXP_SUBSTR('number of your street, zipcode town, FR', ',[^,]+'); -- ORACLE> SELECT REGEXP_SUBSTR('http://www.example.com/products', 'http://([[:alnum:]]+\.?){3,4}/?') FROM DUAL; -> http://www.example.com/ SELECT REGEXP_SUBSTR('http://www.example.com/products', 'http://([[:alnum:]]+\.?){3,4}/?'); -- ORACLE> SELECT REGEXP_SUBSTR('number of your street, zipcode town, FR', ',[^,]+', 24) FROM DUAL; -> , FR SELECT REGEXP_SUBSTR('number of your street, zipcode town, FR', ',[^,]+', 24); -- ORACLE> SELECT REGEXP_SUBSTR('number of your street, zipcode town, FR', ',[^,]+', 1, 1) FROM DUAL; -> , zipcode town SELECT REGEXP_SUBSTR('number of your street, zipcode town, FR', ',[^,]+', 1, 1); -- ORACLE> SELECT REGEXP_SUBSTR('number of your street, zipcode town, FR', ',[^,]+', 1, 2) FROM DUAL; -> , FR SELECT REGEXP_SUBSTR('number of your street, zipcode town, FR', ',[^,]+', 1, 2); -- ORACLE> SELECT REGEXP_SUBSTR('number of your street, zipcode town, FR', ',\s+[Zf][^,]+', 1, 1) FROM DUAL; -> NULL SELECT REGEXP_SUBSTR('number of your street, zipcode town, FR', ',\s+[Zf][^,]+', 1, 1); -- ORACLE> SELECT REGEXP_SUBSTR('number of your street, zipcode town, FR', ',\s+[Zf][^,]+', 1, 1, 'i') FROM DUAL; -> , zipcode town SELECT REGEXP_SUBSTR('number of your street, zipcode town, FR', ',\s+[Zf][^,]+', 1, 1, 'i'); -- ORACLE> SELECT REGEXP_SUBSTR('number of your street, zipcode town, FR', ',\s+[Zf][^,]+', 1, 1, 'i', 0) FROM DUAL; -> , zipcode town SELECT REGEXP_SUBSTR('number of your street, zipcode town, FR', ',\s+[Zf][^,]+', 1, 1, 'i', 0); -- ORACLE> SELECT REGEXP_SUBSTR('number of your street, zipcode town, FR', ',\s+[Zf][^,]+', 1, 1, 'i', 1) FROM DUAL; -> NULL SELECT REGEXP_SUBSTR('number of your street, zipcode town, FR', ',\s+[Zf][^,]+', 1, 1, 'i', 1); -- ORACLE> SELECT REGEXP_SUBSTR('number of your street, zipcode town, FR', ',\s+([Zf][^,]+)', 1, 1, 'i', 1) FROM DUAL; -> zipcode town SELECT REGEXP_SUBSTR('number of your street, zipcode town, FR', ',\s+([Zf][^,]+)', 1, 1, 'i', 1); -- ORACLE> SELECT REGEXP_SUBSTR('1234567890 1234567890', '(123)(4(56)(78))', 1, 1, 'i', 4) FROM DUAL; -> 78 SELECT REGEXP_SUBSTR('1234567890 1234567890', '(123)(4(56)(78))', 1, 1, 'i', 4); -- ORACLE> SELECT REGEXP_SUBSTR('1234567890 1234557890', '(123)(4(5[56])(78))', 1, 2, 'i', 3) FROM DUAL; -> 55 SELECT REGEXP_SUBSTR('1234567890 1234557890', '(123)(4(5[56])(78))', 1, 2, 'i', 3); -- ORACLE> SELECT REGEXP_SUBSTR('1234567890 1234567890', '(123)(4(56)(78))', 1, 1, 'i', 0) FROM DUAL; -> 12345678 SELECT REGEXP_SUBSTR('1234567890 1234567890', '(123)(4(56)(78))', 1, 1, 'i', 0); -- Check negatives values that must throw an error SELECT REGEXP_SUBSTR('1234567890 1234567890', '(123)(4(56)(78))', -1, 1, 'i', 0); SELECT REGEXP_SUBSTR('1234567890 1234567890', '(123)(4(56)(78))', 1, -1, 'i', 0); SELECT REGEXP_SUBSTR('1234567890 1234567890', '(123)(4(56)(78))', 1, 1, 'i', -1); ---- -- Tests for REGEXP_REPLACE() ---- -- ORACLE> SELECT REGEXP_REPLACE('512.123.4567', '([[:digit:]]{3})\.([[:digit:]]{3})\.([[:digit:]]{4})', '(\1) \2-\3') FROM DUAL; -> (512) 123-4567 SELECT REGEXP_REPLACE('512.123.4567', '([[:digit:]]{3})\.([[:digit:]]{3})\.([[:digit:]]{4})', '(\1) \2-\3'); -- ORACLE> SELECT REGEXP_REPLACE('512.123.4567 612.123.4567', '([[:digit:]]{3})\.([[:digit:]]{3})\.([[:digit:]]{4})', '(\1) \2-\3') FROM DUAL; -> (512) 123-4567 (612) 123-4567 SELECT oracle.REGEXP_REPLACE('512.123.4567 612.123.4567', '([[:digit:]]{3})\.([[:digit:]]{3})\.([[:digit:]]{4})', '(\1) \2-\3'); -- ORACLE> SELECT REGEXP_REPLACE('number your street, zipcode town, FR', '( ){2,}', ' ') FROM DUAL; -> number your street, zipcode town, FR SELECT oracle.REGEXP_REPLACE('number your street, zipcode town, FR', '( ){2,}', ' '); -- ORACLE> SELECT REGEXP_REPLACE('number your street,'||CHR(10)||' zipcode town, FR', '( ){2,}', ' ') FROM DUAL; -> number your street, -- zipcode town, FR SELECT oracle.REGEXP_REPLACE('number your street,'||CHR(10)||' zipcode town, FR', '( ){2,}', ' '); -- ORACLE> SELECT REGEXP_REPLACE('number your street, zipcode town, FR', '( ){2,}', ' ', 9) FROM DUAL; -> number your street, zipcode town, FR SELECT oracle.REGEXP_REPLACE('number your street, zipcode town, FR', '( ){2,}', ' ', 9); -- ORACLE> SELECT REGEXP_REPLACE('number your street, zipcode town, FR', '( ){2,}', ' ', 9, 0) FROM DUAL; -> number your street, zipcode town, FR SELECT oracle.REGEXP_REPLACE('number your street, zipcode town, FR', '( ){2,}', ' ', 9, 0); -- ORACLE> SELECT REGEXP_REPLACE('number your street, zipcode town, FR', '( ){2,}', ' ', 9, 2) FROM DUAL; -> number your street, zipcode town, FR SELECT oracle.REGEXP_REPLACE('number your street, zipcode town, FR', '( ){2,}', ' ', 9, 2); -- ORACLE> SELECT REGEXP_REPLACE('number your street, zipcode town, FR', '( ){2,}', ' ', 9, 2, 'm') FROM DUAL; -> number your street, zipcode town, FR SELECT oracle.REGEXP_REPLACE('number your street, zipcode town, FR', '( ){2,}', ' ', 9, 2, 'm'); -- ORACLE> SELECT REGEXP_REPLACE('number your street, zipcode town, FR', '([EURT]){2,}', '[\1]', 9, 2, 'i') FROM DUAL; -> number your s[t], zipcode town, FR SELECT oracle.REGEXP_REPLACE('number your street, zipcode town, FR', '([EURT]){2,}', '[\1]', 9, 2, 'i'); -- ORACLE> SELECT REGEXP_REPLACE('number your street, zipcode town, FR', '[ ]{2,}', ' ', 9, 2) FROM DUAL; -> number your street, zipcode town, FR SELECT oracle.REGEXP_REPLACE('number your street, zipcode town, FR', '( ){2,}', ' ', 9, 2); -- ORACLE> SELECT REGEXP_REPLACE ('A PostgreSQL function', 'A|e|i|o|u', 'X', 1, 2) FROM DUAL; -> A PXstgreSQL function SELECT oracle.REGEXP_REPLACE ('A PostgreSQL function', 'A|e|i|o|u', 'X', 1, 2); -- ORACLE> SELECT REGEXP_REPLACE ('A PostgreSQL function', 'a|e|i|o|u', 'X', 1, 0, 'i') FROM DUAL; -> X PXstgrXSQL fXnctXXn SELECT oracle.REGEXP_REPLACE ('A PostgreSQL function', 'a|e|i|o|u', 'X', 1, 0, 'i'); -- ORACLE> SELECT REGEXP_REPLACE ('A PostgreSQL function', 'a|e|i|o|u', 'X', 1, 1, 'i') FROM DUAL; -> X PostgreSQL function SELECT oracle.REGEXP_REPLACE ('A PostgreSQL function', 'a|e|i|o|u', 'X', 1, 1, 'i'); -- ORACLE> SELECT REGEXP_REPLACE ('A PostgreSQL function', 'a|e|i|o|u', 'X', 1, 2, 'i') FROM DUAL; -> A PXstgreSQL function SELECT oracle.REGEXP_REPLACE ('A PostgreSQL function', 'a|e|i|o|u', 'X', 1, 2, 'i'); -- ORACLE> SELECT REGEXP_REPLACE ('A PostgreSQL function', 'a|e|i|o|u', 'X', 1, 3, 'i') FROM DUAL; -> A PostgrXSQL function SELECT oracle.REGEXP_REPLACE ('A PostgreSQL function', 'a|e|i|o|u', 'X', 1, 3, 'i'); -- ORACLE> SELECT REGEXP_REPLACE ('A PostgreSQL function', 'a|e|i|o|u', 'X', 1, 9, 'i') FROM DUAL; -> A PostgreSQL function SELECT oracle.REGEXP_REPLACE ('A PostgreSQL function', 'a|e|i|o|u', 'X', 1, 9, 'i'); -- ORACLE> SELECT REGEXP_REPLACE ('A PostgreSQL function', 'A|e|i|o|u', 'X', 1, 9) FROM DUAL; -> A PostgreSQL function SELECT oracle.REGEXP_REPLACE ('A PostgreSQL function', 'A|e|i|o|u', 'X', 1, 9); -- ORACLE> SELECT REGEXP_REPLACE ('A PostgreSQL function', 'a|e|i|o|u', 'X', -1, 0, 'i') FROM DUAL; -> ORA-01428 SELECT oracle.REGEXP_REPLACE ('A PostgreSQL function', 'a|e|i|o|u', 'X', -1, 0, 'i'); -- ORACLE> SELECT REGEXP_REPLACE ('A PostgreSQL function', 'a|e|i|o|u', 'X', 1, -1, 'i') FROM DUAL; -> ORA-01428 SELECT oracle.REGEXP_REPLACE ('A PostgreSQL function', 'a|e|i|o|u', 'X', 1, -1, 'i'); -- ORACLE> SELECT REGEXP_REPLACE ('A PostgreSQL function', 'a|e|i|o|u', 'X', 1, 1, 'g') FROM DUAL; -> ORA-01760 SELECT oracle.REGEXP_REPLACE ('A PostgreSQL function', 'a|e|i|o|u', 'X', 1, 1, 'g'); -- -- Test NULL input in the regexp_* functions that must returned NULL except for the modifier -- or regexp flag. There is an exception with regexp_replace(), if the pattern is null (second -- parameter) the original string is returned. We don't test functions witht the STRICT attribute -- SELECT oracle.REGEXP_LIKE(NULL, '\d+', 'i'); SELECT oracle.REGEXP_LIKE('1234', NULL, 'i'); SELECT oracle.REGEXP_LIKE('1234', '\d+', NULL); SELECT oracle.REGEXP_LIKE('1234', '\d+', ''); SELECT oracle.REGEXP_COUNT('1234', '\d', NULL) ; SELECT oracle.REGEXP_COUNT('1234', '\d', 1, NULL) ; SELECT oracle.REGEXP_COUNT('1234', '\d', 1, '') ; SELECT oracle.REGEXP_COUNT('1234', '\d', NULL, NULL) ; SELECT oracle.REGEXP_COUNT(NULL, '4', 1, 'i'); SELECT oracle.REGEXP_INSTR('1234', '4', NULL); SELECT oracle.REGEXP_INSTR('1234', '4', 1, NULL); SELECT oracle.REGEXP_INSTR('1234', '4', 1, 1, NULL); SELECT oracle.REGEXP_INSTR('1234', '4', 1, 1, 1, NULL); SELECT oracle.REGEXP_INSTR('1234', '4', 1, 1, 1, NULL, 0); SELECT oracle.REGEXP_INSTR('1234', '4', 1, 1, 0, NULL); SELECT oracle.REGEXP_INSTR('1234', '4', 1, 1, 0, 'i', NULL); SELECT oracle.REGEXP_INSTR('1234', '4', 1, 1, 0, '', NULL); SELECT oracle.REGEXP_INSTR(NULL, '4', 1, 1, 0, 'i', 2); SELECT oracle.REGEXP_INSTR(NULL, '4', 1, 1, 0, 'i', 2); SELECT oracle.REGEXP_SUBSTR('1234', '1(.*)', null); SELECT oracle.REGEXP_SUBSTR('1234', '234', 1, null); SELECT oracle.REGEXP_SUBSTR('1234', '234', 1, 1, null); SELECT oracle.REGEXP_SUBSTR('1234', '234', 1, 1, ''); SELECT oracle.REGEXP_SUBSTR('1234', '234', 1, 1, 'i', null); -- test for capture group SELECT oracle.REGEXP_SUBSTR('1234', '2(3)(4)', 1, 1, 'i', 1); SELECT oracle.REGEXP_SUBSTR('1234', '2(3)(4)', 1, 1, 'i', 2); SELECT oracle.REGEXP_SUBSTR('1234', '2(3)(4)', 1, 1, 'i', 0); -- ORACLE> SELECT REGEXP_REPLACE(null, '\d', 'a') FROM DUAL; -> NULL SELECT oracle.REGEXP_REPLACE(null, '\d', 'a'); -- ORACLE> SELECT REGEXP_REPLACE('1234', null, 'a') FROM DUAL; -> 1234 SELECT oracle.REGEXP_REPLACE('1234', null, 'a'); -- ORACLE> SELECT REGEXP_REPLACE('1234', null, null) FROM DUAL; -> 1234 SELECT oracle.REGEXP_REPLACE('1234', null, null); -- ORACLE> SELECT REGEXP_REPLACE('1234', '\d', null) FROM DUAL; -> NULL SELECT oracle.REGEXP_REPLACE('1234', '\d', null); -- ORACLE> SELECT REGEXP_REPLACE('1234', '\d', 'a', null) FROM DUAL; -> NULL SELECT oracle.REGEXP_REPLACE('1234', '\d', 'a', null); -- ORACLE> SELECT REGEXP_REPLACE('1234', null, 'a', 2) FROM DUAL; -> 1234 SELECT oracle.REGEXP_REPLACE('1234', null, 'a', 2); -- ORACLE> SELECT REGEXP_REPLACE('1234', null, 'a', null) FROM DUAL; -> NULL SELECT oracle.REGEXP_REPLACE('1234', null, 'a', null); -- ORACLE> SELECT REGEXP_REPLACE('1234', null, 'a', 1) FROM DUAL; -> 1234 SELECT oracle.REGEXP_REPLACE('1234', null, 'a', 1); -- ORACLE> SELECT REGEXP_REPLACE('1234', null, 'a', 1, null) FROM DUAL; -> NULL SELECT oracle.REGEXP_REPLACE('1234', null, 'a', 1, null); -- ORACLE> SELECT REGEXP_REPLACE('1234', '\d', 'a', 1, null) FROM DUAL; -> NULL SELECT oracle.REGEXP_REPLACE('1234', '\d', 'a', 1, null); -- ORACLE> SELECT REGEXP_REPLACE('1234', '\d', 'a', 1, 1, null) FROM DUAL; -> a234 SELECT oracle.REGEXP_REPLACE('1234', '\d', 'a', 1, 1, null); -- ORACLE> SELECT REGEXP_REPLACE('1234', '\d', 'a', 1, NULL, 'i') FROM DUAL; -> NULL SELECT oracle.REGEXP_REPLACE('1234', '\d', 'a', 1, NULL, 'i'); -- ORACLE> SELECT REGEXP_REPLACE('1234', null, 'a', 1, 1, 'i') FROM DUAL; -> 1234 SELECT oracle.REGEXP_REPLACE('1234', null, 'a', 1, 1, 'i'); orafce-VERSION_4_14_4/sql/varchar2.sql000066400000000000000000000041701501757153000174500ustar00rootroot00000000000000\set VERBOSITY terse SET client_encoding = utf8; SET search_path TO public, oracle; -- -- 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_4_14_4/sqlparse.c000066400000000000000000001373531501757153000164300ustar00rootroot00000000000000/* A Bison parser, made by GNU Bison 3.8.2. */ /* Bison implementation for Yacc-like parsers in C Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 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. */ /* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual, especially those whose name start with YY_ or yy_. They are private implementation details that can be changed or removed. */ /* 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. */ /* Identify Bison output, and Bison version. */ #define YYBISON 30802 /* Bison version string. */ #define YYBISON_VERSION "3.8.2" /* 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? */ /* silence -Wmissing-variable-declarations */ extern int orafce_sql_yychar; extern int orafce_sql_yynerrs; #line 133 "sqlparse.c" # ifndef YY_CAST # ifdef __cplusplus # define YY_CAST(Type, Val) static_cast (Val) # define YY_REINTERPRET_CAST(Type, Val) reinterpret_cast (Val) # else # define YY_CAST(Type, Val) ((Type) (Val)) # define YY_REINTERPRET_CAST(Type, Val) ((Type) (Val)) # endif # endif # 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 #include "sqlparse.h" /* Symbol kind. */ enum yysymbol_kind_t { YYSYMBOL_YYEMPTY = -2, YYSYMBOL_YYEOF = 0, /* "end of file" */ YYSYMBOL_YYerror = 1, /* error */ YYSYMBOL_YYUNDEF = 2, /* "invalid token" */ YYSYMBOL_X_IDENT = 3, /* X_IDENT */ YYSYMBOL_X_NCONST = 4, /* X_NCONST */ YYSYMBOL_X_SCONST = 5, /* X_SCONST */ YYSYMBOL_X_OP = 6, /* X_OP */ YYSYMBOL_X_PARAM = 7, /* X_PARAM */ YYSYMBOL_X_COMMENT = 8, /* X_COMMENT */ YYSYMBOL_X_WHITESPACE = 9, /* X_WHITESPACE */ YYSYMBOL_X_KEYWORD = 10, /* X_KEYWORD */ YYSYMBOL_X_OTHERS = 11, /* X_OTHERS */ YYSYMBOL_X_TYPECAST = 12, /* X_TYPECAST */ YYSYMBOL_YYACCEPT = 13, /* $accept */ YYSYMBOL_root = 14, /* root */ YYSYMBOL_elements = 15, /* elements */ YYSYMBOL_anyelement = 16 /* anyelement */ }; typedef enum yysymbol_kind_t yysymbol_kind_t; #ifdef short # undef short #endif /* On compilers that do not define __PTRDIFF_MAX__ etc., make sure and (if available) are included so that the code can choose integer types of a good width. */ #ifndef __PTRDIFF_MAX__ # include /* INFRINGES ON USER NAME SPACE */ # if defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__ # include /* INFRINGES ON USER NAME SPACE */ # define YY_STDINT_H # endif #endif /* Narrow types that promote to a signed type and that can represent a signed or unsigned integer of at least N bits. In tables they can save space and decrease cache pressure. Promoting to a signed type helps avoid bugs in integer arithmetic. */ #ifdef __INT_LEAST8_MAX__ typedef __INT_LEAST8_TYPE__ yytype_int8; #elif defined YY_STDINT_H typedef int_least8_t yytype_int8; #else typedef signed char yytype_int8; #endif #ifdef __INT_LEAST16_MAX__ typedef __INT_LEAST16_TYPE__ yytype_int16; #elif defined YY_STDINT_H typedef int_least16_t yytype_int16; #else typedef short yytype_int16; #endif /* Work around bug in HP-UX 11.23, which defines these macros incorrectly for preprocessor constants. This workaround can likely be removed in 2023, as HPE has promised support for HP-UX 11.23 (aka HP-UX 11i v2) only through the end of 2022; see Table 2 of . */ #ifdef __hpux # undef UINT_LEAST8_MAX # undef UINT_LEAST16_MAX # define UINT_LEAST8_MAX 255 # define UINT_LEAST16_MAX 65535 #endif #if defined __UINT_LEAST8_MAX__ && __UINT_LEAST8_MAX__ <= __INT_MAX__ typedef __UINT_LEAST8_TYPE__ yytype_uint8; #elif (!defined __UINT_LEAST8_MAX__ && defined YY_STDINT_H \ && UINT_LEAST8_MAX <= INT_MAX) typedef uint_least8_t yytype_uint8; #elif !defined __UINT_LEAST8_MAX__ && UCHAR_MAX <= INT_MAX typedef unsigned char yytype_uint8; #else typedef short yytype_uint8; #endif #if defined __UINT_LEAST16_MAX__ && __UINT_LEAST16_MAX__ <= __INT_MAX__ typedef __UINT_LEAST16_TYPE__ yytype_uint16; #elif (!defined __UINT_LEAST16_MAX__ && defined YY_STDINT_H \ && UINT_LEAST16_MAX <= INT_MAX) typedef uint_least16_t yytype_uint16; #elif !defined __UINT_LEAST16_MAX__ && USHRT_MAX <= INT_MAX typedef unsigned short yytype_uint16; #else typedef int yytype_uint16; #endif #ifndef YYPTRDIFF_T # if defined __PTRDIFF_TYPE__ && defined __PTRDIFF_MAX__ # define YYPTRDIFF_T __PTRDIFF_TYPE__ # define YYPTRDIFF_MAXIMUM __PTRDIFF_MAX__ # elif defined PTRDIFF_MAX # ifndef ptrdiff_t # include /* INFRINGES ON USER NAME SPACE */ # endif # define YYPTRDIFF_T ptrdiff_t # define YYPTRDIFF_MAXIMUM PTRDIFF_MAX # else # define YYPTRDIFF_T long # define YYPTRDIFF_MAXIMUM LONG_MAX # endif #endif #ifndef YYSIZE_T # ifdef __SIZE_TYPE__ # define YYSIZE_T __SIZE_TYPE__ # elif defined size_t # define YYSIZE_T size_t # elif defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__ # include /* INFRINGES ON USER NAME SPACE */ # define YYSIZE_T size_t # else # define YYSIZE_T unsigned # endif #endif #define YYSIZE_MAXIMUM \ YY_CAST (YYPTRDIFF_T, \ (YYPTRDIFF_MAXIMUM < YY_CAST (YYSIZE_T, -1) \ ? YYPTRDIFF_MAXIMUM \ : YY_CAST (YYSIZE_T, -1))) #define YYSIZEOF(X) YY_CAST (YYPTRDIFF_T, sizeof (X)) /* Stored state numbers (used for stacks). */ typedef yytype_int8 yy_state_t; /* State numbers in computations. */ typedef int yy_state_fast_t; #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_PURE # if defined __GNUC__ && 2 < __GNUC__ + (96 <= __GNUC_MINOR__) # define YY_ATTRIBUTE_PURE __attribute__ ((__pure__)) # else # define YY_ATTRIBUTE_PURE # endif #endif #ifndef YY_ATTRIBUTE_UNUSED # if defined __GNUC__ && 2 < __GNUC__ + (7 <= __GNUC_MINOR__) # define YY_ATTRIBUTE_UNUSED __attribute__ ((__unused__)) # else # define YY_ATTRIBUTE_UNUSED # endif #endif /* Suppress unused-variable warnings by "using" E. */ #if ! defined lint || defined __GNUC__ # define YY_USE(E) ((void) (E)) #else # define YY_USE(E) /* empty */ #endif /* Suppress an incorrect diagnostic about yylval being uninitialized. */ #if defined __GNUC__ && ! defined __ICC && 406 <= __GNUC__ * 100 + __GNUC_MINOR__ # if __GNUC__ * 100 + __GNUC_MINOR__ < 407 # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") # else # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") \ _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") # endif # 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 #if defined __cplusplus && defined __GNUC__ && ! defined __ICC && 6 <= __GNUC__ # define YY_IGNORE_USELESS_CAST_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuseless-cast\"") # define YY_IGNORE_USELESS_CAST_END \ _Pragma ("GCC diagnostic pop") #endif #ifndef YY_IGNORE_USELESS_CAST_BEGIN # define YY_IGNORE_USELESS_CAST_BEGIN # define YY_IGNORE_USELESS_CAST_END #endif #define YY_ASSERT(E) ((void) (0 && (E))) #if !defined yyoverflow /* 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 */ #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 { yy_state_t 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 (YYSIZEOF (union yyalloc) - 1) /* The size of an array large to enough to hold all stacks, each with N elements. */ # define YYSTACK_BYTES(N) \ ((N) * (YYSIZEOF (yy_state_t) + YYSIZEOF (YYSTYPE) \ + YYSIZEOF (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 \ { \ YYPTRDIFF_T yynewbytes; \ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ Stack = &yyptr->Stack_alloc; \ yynewbytes = yystacksize * YYSIZEOF (*Stack) + YYSTACK_GAP_MAXIMUM; \ yyptr += yynewbytes / YYSIZEOF (*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, YY_CAST (YYSIZE_T, (Count)) * sizeof (*(Src))) # else # define YYCOPY(Dst, Src, Count) \ do \ { \ YYPTRDIFF_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 /* YYMAXUTOK -- Last valid token kind. */ #define YYMAXUTOK 267 /* YYTRANSLATE(TOKEN-NUM) -- Symbol number corresponding to TOKEN-NUM as returned by yylex, with out-of-bounds checking. */ #define YYTRANSLATE(YYX) \ (0 <= (YYX) && (YYX) <= YYMAXUTOK \ ? YY_CAST (yysymbol_kind_t, yytranslate[YYX]) \ : YYSYMBOL_YYUNDEF) /* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM as returned by yylex. */ static const yytype_int8 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_int8 yyrline[] = { 0, 94, 94, 98, 99, 103, 104, 105, 106, 107, 108, 109, 110, 111 }; #endif /** Accessing symbol of state STATE. */ #define YY_ACCESSING_SYMBOL(State) YY_CAST (yysymbol_kind_t, yystos[State]) #if YYDEBUG || 0 /* The user-facing name of the symbol whose (internal) number is YYSYMBOL. No bounds checking. */ static const char *yysymbol_name (yysymbol_kind_t yysymbol) YY_ATTRIBUTE_UNUSED; /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. First, the terminals, then, starting at YYNTOKENS, nonterminals. */ static const char *const yytname[] = { "\"end of file\"", "error", "\"invalid token\"", "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 }; static const char * yysymbol_name (yysymbol_kind_t yysymbol) { return yytname[yysymbol]; } #endif #define YYPACT_NINF (-4) #define yypact_value_is_default(Yyn) \ ((Yyn) == YYPACT_NINF) #define YYTABLE_NINF (-1) #define yytable_value_is_error(Yyn) \ 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_int8 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[] = { 0, 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_int8 yytable[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 13, 14 }; static const yytype_int8 yycheck[] = { 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, 11 }; /* YYSTOS[STATE-NUM] -- The symbol kind of the accessing symbol of state STATE-NUM. */ static const yytype_int8 yystos[] = { 0, 3, 4, 5, 6, 7, 8, 9, 10, 11, 14, 15, 16, 0, 16 }; /* YYR1[RULE-NUM] -- Symbol kind of the left-hand side of rule RULE-NUM. */ static const yytype_int8 yyr1[] = { 0, 13, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16 }; /* YYR2[RULE-NUM] -- Number of symbols on the right-hand side of rule RULE-NUM. */ static const yytype_int8 yyr2[] = { 0, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; enum { YYENOMEM = -2 }; #define yyerrok (yyerrstatus = 0) #define yyclearin (yychar = YYEMPTY) #define YYACCEPT goto yyacceptlab #define YYABORT goto yyabortlab #define YYERROR goto yyerrorlab #define YYNOMEM goto yyexhaustedlab #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) /* Backward compatibility with an undocumented macro. Use YYerror or YYUNDEF. */ #define YYERRCODE YYUNDEF /* 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) /* YYLOCATION_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 YYLOCATION_PRINT # if defined YY_LOCATION_PRINT /* Temporary convenience wrapper in case some people defined the undocumented and private YY_LOCATION_PRINT macros. */ # define YYLOCATION_PRINT(File, Loc) YY_LOCATION_PRINT(File, *(Loc)) # elif 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 YYLOCATION_PRINT yy_location_print_ /* Temporary convenience wrapper in case some people defined the undocumented and private YY_LOCATION_PRINT macros. */ # define YY_LOCATION_PRINT(File, Loc) YYLOCATION_PRINT(File, &(Loc)) # else # define YYLOCATION_PRINT(File, Loc) ((void) 0) /* Temporary convenience wrapper in case some people defined the undocumented and private YY_LOCATION_PRINT macros. */ # define YY_LOCATION_PRINT YYLOCATION_PRINT # endif # endif /* !defined YYLOCATION_PRINT */ # define YY_SYMBOL_PRINT(Title, Kind, Value, Location) \ do { \ if (yydebug) \ { \ YYFPRINTF (stderr, "%s ", Title); \ yy_symbol_print (stderr, \ Kind, Value, Location, result); \ YYFPRINTF (stderr, "\n"); \ } \ } while (0) /*-----------------------------------. | Print this symbol's value on YYO. | `-----------------------------------*/ static void yy_symbol_value_print (FILE *yyo, yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, List **result) { FILE *yyoutput = yyo; YY_USE (yyoutput); YY_USE (yylocationp); YY_USE (result); if (!yyvaluep) return; YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN YY_USE (yykind); YY_IGNORE_MAYBE_UNINITIALIZED_END } /*---------------------------. | Print this symbol on YYO. | `---------------------------*/ static void yy_symbol_print (FILE *yyo, yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, List **result) { YYFPRINTF (yyo, "%s %s (", yykind < YYNTOKENS ? "token" : "nterm", yysymbol_name (yykind)); YYLOCATION_PRINT (yyo, yylocationp); YYFPRINTF (yyo, ": "); yy_symbol_value_print (yyo, yykind, 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 (yy_state_t *yybottom, yy_state_t *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 (yy_state_t *yyssp, YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule, List **result) { int yylno = yyrline[yyrule]; int yynrhs = yyr2[yyrule]; int yyi; YYFPRINTF (stderr, "Reducing stack by rule %d (line %d):\n", yyrule - 1, yylno); /* The symbols being reduced. */ for (yyi = 0; yyi < yynrhs; yyi++) { YYFPRINTF (stderr, " $%d = ", yyi + 1); yy_symbol_print (stderr, YY_ACCESSING_SYMBOL (+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) ((void) 0) # define YY_SYMBOL_PRINT(Title, Kind, 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 /*-----------------------------------------------. | Release the memory associated to this symbol. | `-----------------------------------------------*/ static void yydestruct (const char *yymsg, yysymbol_kind_t yykind, YYSTYPE *yyvaluep, YYLTYPE *yylocationp, List **result) { YY_USE (yyvaluep); YY_USE (yylocationp); YY_USE (result); if (!yymsg) yymsg = "Deleting"; YY_SYMBOL_PRINT (yymsg, yykind, yyvaluep, yylocationp); YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN YY_USE (yykind); YY_IGNORE_MAYBE_UNINITIALIZED_END } /* Lookahead token kind. */ 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) { yy_state_fast_t yystate = 0; /* Number of tokens to shift before error messages enabled. */ int yyerrstatus = 0; /* Refer to the stacks through separate pointers, to allow yyoverflow to reallocate them elsewhere. */ /* Their size. */ YYPTRDIFF_T yystacksize = YYINITDEPTH; /* The state stack: array, bottom, top. */ yy_state_t yyssa[YYINITDEPTH]; yy_state_t *yyss = yyssa; yy_state_t *yyssp = yyss; /* The semantic value stack: array, bottom, top. */ YYSTYPE yyvsa[YYINITDEPTH]; YYSTYPE *yyvs = yyvsa; YYSTYPE *yyvsp = yyvs; /* The location stack: array, bottom, top. */ YYLTYPE yylsa[YYINITDEPTH]; YYLTYPE *yyls = yylsa; YYLTYPE *yylsp = yyls; int yyn; /* The return value of yyparse. */ int yyresult; /* Lookahead symbol kind. */ yysymbol_kind_t yytoken = YYSYMBOL_YYEMPTY; /* The variables used to return semantic value and location from the action routines. */ YYSTYPE yyval; YYLTYPE yyloc; /* The locations where the error started and ended. */ YYLTYPE yyerror_range[3]; #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; YYDPRINTF ((stderr, "Starting parse\n")); 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++; /*--------------------------------------------------------------------. | yysetstate -- set current state (the top of the stack) to yystate. | `--------------------------------------------------------------------*/ yysetstate: YYDPRINTF ((stderr, "Entering state %d\n", yystate)); YY_ASSERT (0 <= yystate && yystate < YYNSTATES); YY_IGNORE_USELESS_CAST_BEGIN *yyssp = YY_CAST (yy_state_t, yystate); YY_IGNORE_USELESS_CAST_END YY_STACK_PRINT (yyss, yyssp); if (yyss + yystacksize - 1 <= yyssp) #if !defined yyoverflow && !defined YYSTACK_RELOCATE YYNOMEM; #else { /* Get the current used size of the three stacks, in elements. */ YYPTRDIFF_T yysize = 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. */ yy_state_t *yyss1 = yyss; YYSTYPE *yyvs1 = yyvs; 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 * YYSIZEOF (*yyssp), &yyvs1, yysize * YYSIZEOF (*yyvsp), &yyls1, yysize * YYSIZEOF (*yylsp), &yystacksize); yyss = yyss1; yyvs = yyvs1; yyls = yyls1; } # else /* defined YYSTACK_RELOCATE */ /* Extend the stack our own way. */ if (YYMAXDEPTH <= yystacksize) YYNOMEM; yystacksize *= 2; if (YYMAXDEPTH < yystacksize) yystacksize = YYMAXDEPTH; { yy_state_t *yyss1 = yyss; union yyalloc *yyptr = YY_CAST (union yyalloc *, YYSTACK_ALLOC (YY_CAST (YYSIZE_T, YYSTACK_BYTES (yystacksize)))); if (! yyptr) YYNOMEM; 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; YY_IGNORE_USELESS_CAST_BEGIN YYDPRINTF ((stderr, "Stack size increased to %ld\n", YY_CAST (long, yystacksize))); YY_IGNORE_USELESS_CAST_END 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 empty, or end-of-input, or a valid lookahead. */ if (yychar == YYEMPTY) { YYDPRINTF ((stderr, "Reading a token\n")); yychar = yylex (); } if (yychar <= YYEOF) { yychar = YYEOF; yytoken = YYSYMBOL_YYEOF; YYDPRINTF ((stderr, "Now at end of input.\n")); } else if (yychar == YYerror) { /* The scanner already issued an error message, process directly to error recovery. But do not keep the error token as lookahead, it is too special and may lead us to an endless loop in error recovery. */ yychar = YYUNDEF; yytoken = YYSYMBOL_YYerror; yyerror_range[1] = yylloc; goto yyerrlab1; } 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); yystate = yyn; YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END *++yylsp = yylloc; /* Discard the shifted token. */ yychar = YYEMPTY; 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: /* root: elements */ #line 94 "sqlparse.y" { *((void**)result) = (yyvsp[0].list); } #line 1250 "sqlparse.c" break; case 3: /* elements: anyelement */ #line 98 "sqlparse.y" { (yyval.list) = list_make1((yyvsp[0].node));} #line 1256 "sqlparse.c" break; case 4: /* elements: elements anyelement */ #line 99 "sqlparse.y" { (yyval.list) = lappend((yyvsp[-1].list), (yyvsp[0].node));} #line 1262 "sqlparse.c" break; case 5: /* anyelement: X_IDENT */ #line 103 "sqlparse.y" { (yyval.node) = (orafce_lexnode*) CREATE_NODE((yyvsp[0].val), IDENT); } #line 1268 "sqlparse.c" break; case 6: /* anyelement: X_NCONST */ #line 104 "sqlparse.y" { (yyval.node) = (orafce_lexnode*) CREATE_NODE((yyvsp[0].val), NCONST); } #line 1274 "sqlparse.c" break; case 7: /* anyelement: X_SCONST */ #line 105 "sqlparse.y" { (yyval.node) = (orafce_lexnode*) CREATE_NODE((yyvsp[0].val), SCONST); } #line 1280 "sqlparse.c" break; case 8: /* anyelement: X_OP */ #line 106 "sqlparse.y" { (yyval.node) = (orafce_lexnode*) CREATE_NODE((yyvsp[0].val), OP); } #line 1286 "sqlparse.c" break; case 9: /* anyelement: X_PARAM */ #line 107 "sqlparse.y" { (yyval.node) = (orafce_lexnode*) CREATE_NODE((yyvsp[0].val), PARAM); } #line 1292 "sqlparse.c" break; case 10: /* anyelement: X_COMMENT */ #line 108 "sqlparse.y" { (yyval.node) = (orafce_lexnode*) CREATE_NODE((yyvsp[0].val), COMMENT); } #line 1298 "sqlparse.c" break; case 11: /* anyelement: X_WHITESPACE */ #line 109 "sqlparse.y" { (yyval.node) = (orafce_lexnode*) CREATE_NODE((yyvsp[0].val), WHITESPACE); } #line 1304 "sqlparse.c" break; case 12: /* anyelement: X_KEYWORD */ #line 110 "sqlparse.y" { (yyval.node) = (orafce_lexnode*) CREATE_NODE((yyvsp[0].val), KEYWORD); } #line 1310 "sqlparse.c" break; case 13: /* anyelement: X_OTHERS */ #line 111 "sqlparse.y" { (yyval.node) = (orafce_lexnode*) CREATE_NODE((yyvsp[0].val), OTHERS); } #line 1316 "sqlparse.c" break; #line 1320 "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 ("-> $$ =", YY_CAST (yysymbol_kind_t, yyr1[yyn]), &yyval, &yyloc); YYPOPSTACK (yylen); yylen = 0; *++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 ? YYSYMBOL_YYEMPTY : YYTRANSLATE (yychar); /* If not already recovering from an error, report this error. */ if (!yyerrstatus) { ++yynerrs; yyerror (result, YY_("syntax error")); } 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; ++yynerrs; /* 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. */ /* Pop stack until we find a state that shifts the error token. */ for (;;) { yyn = yypact[yystate]; if (!yypact_value_is_default (yyn)) { yyn += YYSYMBOL_YYerror; if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYSYMBOL_YYerror) { 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", YY_ACCESSING_SYMBOL (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; ++yylsp; YYLLOC_DEFAULT (*yylsp, yyerror_range, 2); /* Shift the error token. */ YY_SYMBOL_PRINT ("Shifting", YY_ACCESSING_SYMBOL (yyn), yyvsp, yylsp); yystate = yyn; goto yynewstate; /*-------------------------------------. | yyacceptlab -- YYACCEPT comes here. | `-------------------------------------*/ yyacceptlab: yyresult = 0; goto yyreturnlab; /*-----------------------------------. | yyabortlab -- YYABORT comes here. | `-----------------------------------*/ yyabortlab: yyresult = 1; goto yyreturnlab; /*-----------------------------------------------------------. | yyexhaustedlab -- YYNOMEM (memory exhaustion) comes here. | `-----------------------------------------------------------*/ yyexhaustedlab: yyerror (result, YY_("memory exhausted")); yyresult = 2; goto yyreturnlab; /*----------------------------------------------------------. | yyreturnlab -- parsing is finished, clean up and return. | `----------------------------------------------------------*/ yyreturnlab: 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", YY_ACCESSING_SYMBOL (+*yyssp), yyvsp, yylsp, result); YYPOPSTACK (1); } #ifndef yyoverflow if (yyss != yyssa) YYSTACK_FREE (yyss); #endif return yyresult; } #line 113 "sqlparse.y" #undef YYLTYPE #include "sqlscan.c" orafce-VERSION_4_14_4/sqlparse.h000066400000000000000000000070071501757153000164250ustar00rootroot00000000000000/* A Bison parser, made by GNU Bison 3.8.2. */ /* Bison interface for Yacc-like parsers in C Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 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. */ /* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual, especially those whose name start with YY_ or yy_. They are private implementation details that can be changed or removed. */ #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 kinds. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE enum yytokentype { YYEMPTY = -2, YYEOF = 0, /* "end of file" */ YYerror = 256, /* error */ YYUNDEF = 257, /* "invalid token" */ X_IDENT = 258, /* X_IDENT */ X_NCONST = 259, /* X_NCONST */ X_SCONST = 260, /* X_SCONST */ X_OP = 261, /* X_OP */ X_PARAM = 262, /* X_PARAM */ X_COMMENT = 263, /* X_COMMENT */ X_WHITESPACE = 264, /* X_WHITESPACE */ X_KEYWORD = 265, /* X_KEYWORD */ X_OTHERS = 266, /* X_OTHERS */ X_TYPECAST = 267 /* X_TYPECAST */ }; typedef enum yytokentype yytoken_kind_t; #endif /* Value type. */ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED union YYSTYPE { #line 66 "sqlparse.y" int ival; orafce_lexnode *node; List *list; struct { char *str; int keycode; int lloc; char *sep; char *modificator; } val; #line 90 "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_4_14_4/sqlparse.y000066400000000000000000000050431501757153000164440ustar00rootroot00000000000000/* * %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? */ /* silence -Wmissing-variable-declarations */ extern int orafce_sql_yychar; extern int orafce_sql_yynerrs; %} %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_4_14_4/sqlscan.c000066400000000000000000002577741501757153000162540ustar00rootroot00000000000000#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" /* Not needed now that this file is compiled as part of gram.y */ /* #include "parser/parse.h" */ #include "parser/scansup.h" #if PG_VERSION_NUM >= 130000 #include "port/pg_bitutils.h" #endif #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 1013 "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 1141 "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 314 "sqlscan.l" #line 1366 "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 316 "sqlscan.l" { SET_YYLLOC(); yylval.val.str = pstrdup(yytext); yylval.val.modificator = NULL; yylval.val.keycode = -1; yylval.val.sep = NULL; return X_WHITESPACE; } YY_BREAK case 2: YY_RULE_SETUP #line 325 "sqlscan.l" { SET_YYLLOC(); yylval.val.str = pstrdup(yytext); yylval.val.modificator = "sc"; yylval.val.keycode = -1; yylval.val.sep = NULL; return X_COMMENT; } YY_BREAK case 3: YY_RULE_SETUP #line 335 "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 348 "sqlscan.l" { xcdepth++; /* Put back any characters past slash-star; see above */ addlitchar('/'); addlitchar('*'); yyless(2); } YY_BREAK case 5: YY_RULE_SETUP #line 357 "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 379 "sqlscan.l" { addlit(yytext, yyleng); } YY_BREAK case 7: YY_RULE_SETUP #line 383 "sqlscan.l" { addlit(yytext, yyleng); } YY_BREAK case 8: YY_RULE_SETUP #line 387 "sqlscan.l" { addlit(yytext, yyleng); } YY_BREAK case YY_STATE_EOF(xc): #line 391 "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 400 "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 413 "sqlscan.l" case 11: /* rule 11 can match eol */ YY_RULE_SETUP #line 413 "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 423 "sqlscan.l" case 13: /* rule 13 can match eol */ YY_RULE_SETUP #line 423 "sqlscan.l" { addlit(yytext, yyleng); } YY_BREAK case 14: /* rule 14 can match eol */ #line 427 "sqlscan.l" case 15: /* rule 15 can match eol */ YY_RULE_SETUP #line 427 "sqlscan.l" { /* ignore */ } YY_BREAK case YY_STATE_EOF(xb): #line 430 "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 438 "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 451 "sqlscan.l" case 18: /* rule 18 can match eol */ YY_RULE_SETUP #line 451 "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 460 "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 468 "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 488 "sqlscan.l" { SET_YYLLOC(); BEGIN(xq); extended_string = false; startlit(); } YY_BREAK case 21: YY_RULE_SETUP #line 494 "sqlscan.l" { SET_YYLLOC(); BEGIN(xe); extended_string = true; startlit(); } YY_BREAK case 22: /* rule 22 can match eol */ #line 501 "sqlscan.l" case 23: /* rule 23 can match eol */ YY_RULE_SETUP #line 501 "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 510 "sqlscan.l" { addlitchar('\''); } YY_BREAK case 25: /* rule 25 can match eol */ YY_RULE_SETUP #line 513 "sqlscan.l" { addlit(yytext, yyleng); } YY_BREAK case 26: /* rule 26 can match eol */ YY_RULE_SETUP #line 516 "sqlscan.l" { addlit(yytext, yyleng); } YY_BREAK case 27: /* rule 27 can match eol */ YY_RULE_SETUP #line 519 "sqlscan.l" { addlitchar(unescape_single_char(yytext[1])); } YY_BREAK case 28: YY_RULE_SETUP #line 522 "sqlscan.l" { unsigned char c = strtoul(yytext+1, NULL, 8); addlitchar(c); } YY_BREAK case 29: YY_RULE_SETUP #line 527 "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 532 "sqlscan.l" { /* ignore */ } YY_BREAK case 31: YY_RULE_SETUP #line 535 "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 539 "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 547 "sqlscan.l" { SET_YYLLOC(); dolqstart = pstrdup(yytext); BEGIN(xdolq); startlit(); } YY_BREAK case 33: YY_RULE_SETUP #line 553 "sqlscan.l" { /* throw back all but the initial "$" */ yyless(1); /* and treat it as {other} */ yylval.val.str = pstrdup(yytext); yylval.val.modificator = "dolqf"; yylval.val.keycode = -1; yylval.val.sep = NULL; return X_OTHERS; } YY_BREAK case 34: YY_RULE_SETUP #line 563 "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 584 "sqlscan.l" { addlit(yytext, yyleng); } YY_BREAK case 36: YY_RULE_SETUP #line 587 "sqlscan.l" { addlit(yytext, yyleng); } YY_BREAK case 37: YY_RULE_SETUP #line 590 "sqlscan.l" { /* This is only needed for inside the quoted text */ addlitchar(yytext[0]); } YY_BREAK case YY_STATE_EOF(xdolq): #line 594 "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 603 "sqlscan.l" { SET_YYLLOC(); BEGIN(xd); startlit(); } YY_BREAK case 39: YY_RULE_SETUP #line 608 "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 623 "sqlscan.l" { addlitchar('"'); } YY_BREAK case 41: /* rule 41 can match eol */ YY_RULE_SETUP #line 626 "sqlscan.l" { addlit(yytext, yyleng); } YY_BREAK case YY_STATE_EOF(xd): #line 629 "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 636 "sqlscan.l" { SET_YYLLOC(); yylval.val.str = pstrdup(yytext); yylval.val.modificator = "typecast"; yylval.val.keycode = X_TYPECAST; yylval.val.sep = NULL; return X_OTHERS; } YY_BREAK case 43: YY_RULE_SETUP #line 645 "sqlscan.l" { SET_YYLLOC(); yylval.val.str = pstrdup(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 654 "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 = pstrdup(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 743 "sqlscan.l" { SET_YYLLOC(); yylval.val.modificator = NULL; yylval.val.str = pstrdup(yytext); yylval.val.keycode = -1; yylval.val.sep = NULL; return X_PARAM; } YY_BREAK case 46: YY_RULE_SETUP #line 752 "sqlscan.l" { long val; char* endptr; SET_YYLLOC(); errno = 0; val = strtol(yytext, &endptr, 10); if (*endptr != '\0' || errno == ERANGE /* if long > 32 bits, check for overflow of int4 */ || val != (long) ((int32) val) ) { /* 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 = pstrdup(yytext); yylval.val.modificator = "i"; yylval.val.keycode = -1; yylval.val.sep = NULL; return X_NCONST; } YY_BREAK case 47: YY_RULE_SETUP #line 778 "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 786 "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 794 "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 809 "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 821 "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 854 "sqlscan.l" { SET_YYLLOC(); yylval.val.str = pstrdup(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 863 "sqlscan.l" { SET_YYLLOC(); yyterminate(); } YY_BREAK case 53: YY_RULE_SETUP #line 868 "sqlscan.l" YY_FATAL_ERROR( "flex scanner jammed" ); YY_BREAK #line 2185 "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 868 "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 */ #if PG_VERSION_NUM >= 130000 errposition(pos); return pos; #else return errposition(pos); #endif } /* * 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) { #if PG_VERSION_NUM >= 130000 literalalloc = pg_nextpower2_32(literallen + yleng + 1); #else do { literalalloc *= 2; } while ((literallen+yleng) >= literalalloc); #endif 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_4_14_4/sqlscan.l000066400000000000000000000646521501757153000162540ustar00rootroot00000000000000%{ /* ** A scanner for EMP-style numeric ranges */ #include "postgres.h" /* Not needed now that this file is compiled as part of gram.y */ /* #include "parser/parse.h" */ #include "parser/scansup.h" #if PG_VERSION_NUM >= 130000 #include "port/pg_bitutils.h" #endif #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 = pstrdup(yytext); yylval.val.modificator = NULL; yylval.val.keycode = -1; yylval.val.sep = NULL; return X_WHITESPACE; } {comment} { SET_YYLLOC(); yylval.val.str = pstrdup(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 = pstrdup(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.str = pstrdup(yytext); yylval.val.modificator = "typecast"; yylval.val.keycode = X_TYPECAST; yylval.val.sep = NULL; return X_OTHERS; } {self} { SET_YYLLOC(); yylval.val.str = pstrdup(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 = pstrdup(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 = pstrdup(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 /* if long > 32 bits, check for overflow of int4 */ || val != (long) ((int32) val) ) { /* 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 = pstrdup(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 = pstrdup(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 */ #if PG_VERSION_NUM >= 130000 errposition(pos); return pos; #else return errposition(pos); #endif } /* * 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) { #if PG_VERSION_NUM >= 130000 literalalloc = pg_nextpower2_32(literallen + yleng + 1); #else do { literalalloc *= 2; } while ((literallen+yleng) >= literalalloc); #endif 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_4_14_4/utility.c000066400000000000000000000107011501757153000162640ustar00rootroot00000000000000/* 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-2023 This module is under BSD Licence History: 1.0. first public version 22. September 2006 */ #include #include #include #include #include "postgres.h" #include "utils/builtins.h" #include "utils/numeric.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); PG_FUNCTION_INFO_V1(dbms_utility_get_time); static char* dbms_utility_format_call_stack(char mode) { MemoryContext oldcontext = CurrentMemoryContext; ErrorData *edata; ErrorContextCallback *econtext; StringInfo sinfo; #if PG_VERSION_NUM >= 130000 errstart(ERROR, TEXTDOMAIN); #else errstart(ERROR, __FILE__, __LINE__, PG_FUNCNAME_MACRO, TEXTDOMAIN); #endif 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))); } /* * Returns the number of hundredths of seconds that have elapsed * since a point in time in the past. */ Datum dbms_utility_get_time(PG_FUNCTION_ARGS) { struct timeval tv; gettimeofday(&tv,NULL); PG_RETURN_INT32((int32) ((int64) tv.tv_sec * 100 + tv.tv_usec / 10000)); } orafce-VERSION_4_14_4/varchar2.c000066400000000000000000000130531501757153000162740ustar00rootroot00000000000000/*---------------------------------------------------------------------------- * * varchar2.c * VARCHAR2 type for PostgreSQL. * *---------------------------------------------------------------------------- */ #include "postgres.h" #include "access/hash.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) 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, size2int(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) { 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); }