]> granicus.if.org Git - postgresql/commitdiff
Internal functions to support newest ODBC driver {fn ...} conventions.
authorThomas G. Lockhart <lockhart@fourpalms.org>
Tue, 11 Apr 2000 15:53:13 +0000 (15:53 +0000)
committerThomas G. Lockhart <lockhart@fourpalms.org>
Tue, 11 Apr 2000 15:53:13 +0000 (15:53 +0000)
Includes compiled code to support pre-7.0 backends, but for 7.0 only
requires executing odbc.sql.

contrib/odbc/Makefile [new file with mode: 0644]
contrib/odbc/README [new file with mode: 0644]
contrib/odbc/odbc-pre7.source [new file with mode: 0644]
contrib/odbc/odbc.c [new file with mode: 0644]
contrib/odbc/odbc.sql [new file with mode: 0644]

diff --git a/contrib/odbc/Makefile b/contrib/odbc/Makefile
new file mode 100644 (file)
index 0000000..34138c1
--- /dev/null
@@ -0,0 +1,48 @@
+# ODBC extensions
+# Thomas Lockhart 2000-04-03
+
+SRCDIR= ../../src
+
+include $(SRCDIR)/Makefile.global
+
+ifndef PGLIB
+  PGLIB= .
+endif
+
+CFLAGS+= $(CFLAGS_SL) -I$(SRCDIR)/include
+
+TARGETS_7= odbc.sql
+TARGETS_PRE7= odbc$(DLSUFFIX) odbc-pre7.sql
+
+TARGETS= $(TARGETS_7)
+
+CLEANFILES+= $(TARGETS) $(TARGETS_PRE7)
+
+all:: $(TARGETS)
+
+install: all
+ifneq ($(filter odbc$(DLSUFFIX), $(TARGETS)),)
+       -test -d $(PGLIB) || $(INSTALL) -d $(PGLIB)
+       $(INSTALL) odbc$(DLSUFFIX) $(PGLIB)
+endif
+
+pre7:
+       $(MAKE) TARGETS="$(TARGETS) $(TARGETS_PRE7)"
+
+install-pre7:
+       $(MAKE) TARGETS="$(TARGETS) $(TARGETS_PRE7)" install
+
+odbc-pre7.sql: odbc-pre7.source odbc.sql
+       rm -f $@; \
+       cat $^ \
+       | sed -e "s:_OBJWD_:$(PGLIB):g" \
+             -e "s:_DLSUFFIX_:$(DLSUFFIX):g" \
+             -e "s:float(15):float8:g" > $@
+
+%.sql: %.source
+       rm -f $@; \
+       sed -e "s:_OBJWD_:$(PGLIB):g" \
+           -e "s:_DLSUFFIX_:$(DLSUFFIX):g" < $< > $@
+
+clean:
+       rm -f $(TARGETS) *.o
diff --git a/contrib/odbc/README b/contrib/odbc/README
new file mode 100644 (file)
index 0000000..c36f183
--- /dev/null
@@ -0,0 +1,38 @@
+This directory contains support functions for the ODBC driver
+supplied with PostgreSQL-7.0.
+
+To enable additional ODBC functions with PostgreSQL-7.0, simply
+execute the commands in odbc.sql:
+
+psql
+Welcome to psql, the PostgreSQL interactive terminal.
+
+Type:  \copyright for distribution terms
+       \h for help with SQL commands
+       \? for help on internal slash commands
+       \g or terminate with semicolon to execute query
+       \q to quit
+
+postgres=# \i odbc.sql
+CREATE
+...
+
+
+To enable additional ODBC functions with versions of PostgreSQL
+prior to PostgreSQL-7.0 (e.g. PostgreSQL-6.5.3), build the shared
+library and SQL commands as follows:
+
+make pre7
+psql
+Welcome to psql, the PostgreSQL interactive terminal.
+
+Type:  \copyright for distribution terms
+       \h for help with SQL commands
+       \? for help on internal slash commands
+       \g or terminate with semicolon to execute query
+       \q to quit
+
+postgres=# \i odbc-pre7.sql
+CREATE
+...
+
diff --git a/contrib/odbc/odbc-pre7.source b/contrib/odbc/odbc-pre7.source
new file mode 100644 (file)
index 0000000..4fa06c4
--- /dev/null
@@ -0,0 +1,162 @@
+-- ODBC-pre7.sql
+--
+-- Use float8 rather than float(15) since pre-7.0 does not accept
+-- SQL92 type names of this form in the CREATE FUNCTION command.
+--
+
+--
+-- Character string manipulation
+--
+
+--
+-- Compatibility functions for pre-v7.0.
+-- These should be applied to pre-v7.0 databases
+-- when using the v7.0 ODBC driver.
+--
+
+CREATE FUNCTION char_length(text)
+    RETURNS integer
+    AS 'SELECT length(CAST($1 AS text))'
+    LANGUAGE 'SQL';
+
+CREATE FUNCTION pow(float8)
+    RETURNS float8
+    AS 'SELECT dpow($1)'
+    LANGUAGE 'SQL';
+
+--
+-- Extensions for ODBC compliance in v7.0.
+-- In the current driver, ODBC functions must map directly into a
+-- Postgres function. So in some cases we must create a compatible
+-- function.
+--
+
+CREATE FUNCTION ascii(text)
+    RETURNS integer
+    AS '_OBJWD_/odbc_DLSUFFIX_', 'ascii'
+    LANGUAGE 'C';
+
+CREATE FUNCTION ichar(integer)
+    RETURNS char(1)
+    AS '_OBJWD_/odbc_DLSUFFIX_', 'ichar'
+    LANGUAGE 'C';
+
+CREATE FUNCTION insert(text, integer, integer, text)
+    RETURNS text
+    AS '_OBJWD_/odbc_DLSUFFIX_', 'insert'
+    LANGUAGE 'C';
+
+-- replace all occurences of $2 with $3
+CREATE FUNCTION replace(text, text, text)
+    RETURNS text
+    AS '_OBJWD_/odbc_DLSUFFIX_', 'replace'
+    LANGUAGE 'C';
+
+-- return the string repeated n times
+CREATE FUNCTION repeat(text, integer)
+    RETURNS text
+    AS '_OBJWD_/odbc_DLSUFFIX_', 'repeat'
+    LANGUAGE 'C';
+
+--
+-- Mathematical functions for pre-v7.0
+--
+
+CREATE FUNCTION dround(float8)
+    RETURNS float8
+    AS '_OBJWD_/odbc_DLSUFFIX_', 'dround'
+    LANGUAGE 'C';
+
+CREATE FUNCTION round(float8)
+    RETURNS float8
+    AS 'SELECT dround($1)'
+    LANGUAGE 'SQL';
+
+--
+-- Math functions present in backend, but not in catalog for v7.0
+--
+
+CREATE FUNCTION acos(float8)
+    RETURNS float8
+    AS '_OBJWD_/odbc_DLSUFFIX_', 'dacos'
+    LANGUAGE 'C';
+
+CREATE FUNCTION asin(float8)
+    RETURNS float8
+    AS '_OBJWD_/odbc_DLSUFFIX_', 'dasin'
+    LANGUAGE 'C';
+
+CREATE FUNCTION atan(float8)
+    RETURNS float8
+    AS '_OBJWD_/odbc_DLSUFFIX_', 'datan'
+    LANGUAGE 'C';
+
+CREATE FUNCTION atan2(float8,float8)
+    RETURNS float8
+    AS '_OBJWD_/odbc_DLSUFFIX_', 'datan2'
+    LANGUAGE 'C';
+
+CREATE FUNCTION cos(float8)
+    RETURNS float8
+    AS '_OBJWD_/odbc_DLSUFFIX_', 'dcos'
+    LANGUAGE 'C';
+
+CREATE FUNCTION cot(float8)
+    RETURNS float8
+    AS '_OBJWD_/odbc_DLSUFFIX_', 'dcot'
+    LANGUAGE 'C';
+
+CREATE FUNCTION sin(float8)
+    RETURNS float8
+    AS '_OBJWD_/odbc_DLSUFFIX_', 'dsin'
+    LANGUAGE 'C';
+
+CREATE FUNCTION dtan(float8)
+    RETURNS float8
+    AS '_OBJWD_/odbc_DLSUFFIX_', 'dtan'
+    LANGUAGE 'C';
+
+CREATE FUNCTION degrees(float8)
+    RETURNS float8
+    AS '_OBJWD_/odbc_DLSUFFIX_', 'degrees'
+    LANGUAGE 'C';
+
+CREATE FUNCTION pi()
+    RETURNS float8
+    AS '_OBJWD_/odbc_DLSUFFIX_', 'dpi'
+    LANGUAGE 'C';
+
+CREATE FUNCTION radians(float8)
+    RETURNS float8
+    AS '_OBJWD_/odbc_DLSUFFIX_', 'radians'
+    LANGUAGE 'C';
+
+-- random number generator currently requires RAND_MAX be available
+CREATE FUNCTION random()
+    RETURNS float8
+    AS '_OBJWD_/odbc_DLSUFFIX_', 'drandom'
+    LANGUAGE 'C';
+
+CREATE FUNCTION truncate(numeric,integer)
+    RETURNS numeric
+    AS 'SELECT trunc($1, $2)'
+    LANGUAGE 'SQL';
+
+--
+-- Date/time functions for v7.0
+--
+
+CREATE FUNCTION interval_mul(interval,float8)
+    RETURNS interval
+    AS '_OBJWD_/odbc_DLSUFFIX_'
+    LANGUAGE 'C';
+
+CREATE OPERATOR * (
+    LEFTARG = interval,
+    RIGHTARG = float8,
+    PROCEDURE = interval_mul
+);
+
+
+
+
diff --git a/contrib/odbc/odbc.c b/contrib/odbc/odbc.c
new file mode 100644 (file)
index 0000000..8d72c03
--- /dev/null
@@ -0,0 +1,413 @@
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include <float.h>                             /* faked on sunos4 */
+
+#include <math.h>
+
+#include "postgres.h"
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#ifndef MAXINT
+#define MAXINT           INT_MAX
+#endif
+#else
+#ifdef HAVE_VALUES_H
+#include <values.h>
+#endif
+#endif
+#include "fmgr.h"
+#include "utils/timestamp.h"
+#include "utils/builtins.h"
+
+
+int4 ascii(text *string);
+text *ichar(int4 cvalue);
+text *repeat(text *string, int4 count);
+Interval *interval_mul(Interval *span1, float8 *arg2);
+float64 dasin(float64 arg1);
+float64 datan(float64 arg1);
+float64 datan2(float64 arg1, float64 arg2);
+float64 dcos(float64 arg1);
+float64 dcot(float64 arg1);
+float64 dsin(float64 arg1);
+float64 dtan(float64 arg1);
+float64 degrees(float64 arg1);
+float64 dpi(void);
+float64 radians(float64 arg1);
+float64 drandom(void);
+void setseed(int32 seed);
+
+
+int4
+ascii(text *string)
+{
+       if (!PointerIsValid(string))
+               return 0;
+
+       if (VARSIZE(string) <= VARHDRSZ)
+               return 0;
+
+       return ((int) *(VARDATA(string)));
+} /* ascii() */
+
+
+text *
+ichar(int4 cvalue)
+{
+       text   *result;
+
+       result = (text *) palloc(VARHDRSZ + 1);
+       VARSIZE(result) = VARHDRSZ + 1;
+       *VARDATA(result) = (char) cvalue;
+
+       return result;
+} /* ichar() */
+
+
+text *
+repeat(text *string, int4 count)
+{
+       text   *result;
+       int             slen, tlen;
+       int             i;
+       char   *cp;
+
+       if (count < 0)
+               count = 0;
+
+       slen = (VARSIZE(string)-VARHDRSZ);
+       tlen = (VARHDRSZ + (count * slen));
+
+       result = (text *) palloc(tlen);
+
+       VARSIZE(result) = tlen;
+       cp = VARDATA(result);
+       for (i = 0; i < count; i++)
+       {
+               memcpy(cp, VARDATA(string), slen);
+               cp += slen;
+       }
+
+       return result;
+} /* ichar() */
+
+Interval   *
+interval_mul(Interval *span1, float8 *arg2)
+{
+       Interval   *result;
+       double          months;
+
+       if ((!PointerIsValid(span1)) || (!PointerIsValid(arg2)))
+               return NULL;
+
+       if (!PointerIsValid(result = palloc(sizeof(Interval))))
+               elog(ERROR, "Memory allocation failed, can't divide intervals");
+
+       months = (span1->month * *arg2);
+       result->month = rint(months);
+       result->time = JROUND(span1->time * *arg2);
+       result->time += JROUND((months - result->month) * 30);
+
+       return result;
+}      /* interval_mul() */
+
+/*
+ *             dasin                   - returns a pointer to the arcsin of arg1 (radians)
+ */
+float64
+dasin(float64 arg1)
+{
+       float64         result;
+       double          tmp;
+
+       if (!PointerIsValid(arg1))
+               return (float64) NULL;
+
+       result = (float64) palloc(sizeof(float64data));
+
+       tmp = *arg1;
+       errno = 0;
+       *result = (float64data) asin(tmp);
+       if (errno != 0
+#ifdef HAVE_FINITE
+               || !finite(*result)
+#endif
+               )
+               elog(ERROR, "dasin(%f) input is out of range", *arg1);
+
+       CheckFloat8Val(*result);
+       return result;
+} /* dasin() */
+
+
+/*
+ *             datan                   - returns a pointer to the arctan of arg1 (radians)
+ */
+float64
+datan(float64 arg1)
+{
+       float64         result;
+       double          tmp;
+
+       if (!PointerIsValid(arg1))
+               return (float64) NULL;
+
+       result = (float64) palloc(sizeof(float64data));
+
+       tmp = *arg1;
+       errno = 0;
+       *result = (float64data) atan(tmp);
+       if (errno != 0
+#ifdef HAVE_FINITE
+               || !finite(*result)
+#endif
+               )
+               elog(ERROR, "atan(%f) input is out of range", *arg1);
+
+       CheckFloat8Val(*result);
+       return result;
+} /* datan() */
+
+
+/*
+ *             atan2                   - returns a pointer to the arctan2 of arg1 (radians)
+ */
+float64
+datan2(float64 arg1, float64 arg2)
+{
+       float64         result;
+
+       if (!PointerIsValid(arg1) || !PointerIsValid(arg1))
+               return (float64) NULL;
+
+       result = (float64) palloc(sizeof(float64data));
+
+       errno = 0;
+       *result = (float64data) atan2(*arg1, *arg2);
+       if (errno != 0
+#ifdef HAVE_FINITE
+               || !finite(*result)
+#endif
+               )
+               elog(ERROR, "atan2(%f,%f) input is out of range", *arg1, *arg2);
+
+       CheckFloat8Val(*result);
+       return result;
+} /* datan2() */
+
+
+/*
+ *             dcos                    - returns a pointer to the cosine of arg1 (radians)
+ */
+float64
+dcos(float64 arg1)
+{
+       float64         result;
+       double          tmp;
+
+       if (!PointerIsValid(arg1))
+               return (float64) NULL;
+
+       result = (float64) palloc(sizeof(float64data));
+
+       tmp = *arg1;
+       errno = 0;
+       *result = (float64data) cos(tmp);
+       if (errno != 0
+#ifdef HAVE_FINITE
+               || !finite(*result)
+#endif
+               )
+               elog(ERROR, "dcos(%f) input is out of range", *arg1);
+
+       CheckFloat8Val(*result);
+       return result;
+} /* dcos() */
+
+
+/*
+ *             dcot                    - returns a pointer to the cotangent of arg1 (radians)
+ */
+float64
+dcot(float64 arg1)
+{
+       float64         result;
+       double          tmp;
+
+       if (!PointerIsValid(arg1))
+               return (float64) NULL;
+
+       result = (float64) palloc(sizeof(float64data));
+
+       tmp = *arg1;
+       errno = 0;
+       *result = (float64data) tan(tmp);
+       if ((errno != 0) || (*result == 0.0)
+#ifdef HAVE_FINITE
+               || !finite(*result)
+#endif
+               )
+               elog(ERROR, "dcot(%f) input is out of range", *arg1);
+
+       *result = 1.0/(*result);
+       CheckFloat8Val(*result);
+       return result;
+} /* dcot() */
+
+
+/*
+ *             dsin                    - returns a pointer to the sine of arg1 (radians)
+ */
+float64
+dsin(float64 arg1)
+{
+       float64         result;
+       double          tmp;
+
+       if (!PointerIsValid(arg1))
+               return (float64) NULL;
+
+       result = (float64) palloc(sizeof(float64data));
+
+       tmp = *arg1;
+       errno = 0;
+       *result = (float64data) sin(tmp);
+       if (errno != 0
+#ifdef HAVE_FINITE
+               || !finite(*result)
+#endif
+               )
+               elog(ERROR, "dsin(%f) input is out of range", *arg1);
+
+       CheckFloat8Val(*result);
+       return result;
+} /* dsin() */
+
+
+/*
+ *             dtan                    - returns a pointer to the tangent of arg1 (radians)
+ */
+float64
+dtan(float64 arg1)
+{
+       float64         result;
+       double          tmp;
+
+       if (!PointerIsValid(arg1))
+               return (float64) NULL;
+
+       result = (float64) palloc(sizeof(float64data));
+
+       tmp = *arg1;
+       errno = 0;
+       *result = (float64data) tan(tmp);
+       if (errno != 0
+#ifdef HAVE_FINITE
+               || !finite(*result)
+#endif
+               )
+               elog(ERROR, "dtan(%f) input is out of range", *arg1);
+
+       CheckFloat8Val(*result);
+       return result;
+} /* dtan() */
+
+
+#ifndef M_PI
+/* from my RH5.2 gcc math.h file - thomas 2000-04-03 */
+#define M_PI 3.14159265358979323846
+#endif
+
+
+/*
+ *             degrees         - returns a pointer to degrees converted from radians
+ */
+float64
+degrees(float64 arg1)
+{
+       float64         result;
+
+       if (!arg1)
+               return (float64) NULL;
+
+       result = (float64) palloc(sizeof(float64data));
+
+       *result = ((*arg1) * (180.0 / M_PI));
+
+       CheckFloat8Val(*result);
+       return result;
+} /* degrees() */
+
+
+/*
+ *             dpi                             - returns a pointer to degrees converted to radians
+ */
+float64
+dpi(void)
+{
+       float64         result;
+
+       result = (float64) palloc(sizeof(float64data));
+
+       *result = (M_PI);
+
+       return result;
+} /* dpi() */
+
+
+/*
+ *             radians         - returns a pointer to radians converted from degrees
+ */
+float64
+radians(float64 arg1)
+{
+       float64         result;
+
+       if (!arg1)
+               return (float64) NULL;
+
+       result = (float64) palloc(sizeof(float64data));
+
+       *result = ((*arg1) * (M_PI / 180.0));
+
+       CheckFloat8Val(*result);
+       return result;
+} /* radians() */
+
+
+#ifdef RAND_MAX
+
+/*
+ *             drandom         - returns a random number
+ */
+float64
+drandom(void)
+{
+       float64         result;
+
+       result = (float64) palloc(sizeof(float64data));
+
+       /* result 0.0-1.0 */
+       *result = (((double)rand()) / RAND_MAX);
+
+       CheckFloat8Val(*result);
+       return result;
+} /* drandom() */
+
+
+/*
+ *             setseed         - set seed for the random number generator
+ */
+void
+setseed(int32 seed)
+{
+       srand(seed);
+
+       return;
+} /* setseed() */
+
+#endif
+
+
diff --git a/contrib/odbc/odbc.sql b/contrib/odbc/odbc.sql
new file mode 100644 (file)
index 0000000..bec7f48
--- /dev/null
@@ -0,0 +1,145 @@
+-- ODBC.sql
+--
+
+--
+-- Character string manipulation
+--
+
+--
+-- Extensions for ODBC compliance in v7.0.
+-- In the current driver, ODBC functions must map directly into a
+-- Postgres function. So in some cases we must create a compatible
+-- function.
+--
+
+-- truncate on the left
+CREATE FUNCTION ltrunc(text, integer)
+    RETURNS text
+    AS 'SELECT substring($1 FROM 1 FOR $2)'
+    LANGUAGE 'SQL';
+
+-- truncate on the right
+CREATE FUNCTION rtrunc(text, integer)
+    RETURNS text
+    AS 'SELECT substring($1 FROM (char_length($1)-($2)+1) FOR $2)'
+    LANGUAGE 'SQL';
+
+CREATE FUNCTION space(integer)
+    RETURNS text
+    AS 'SELECT lpad('''', $1, '' '')'
+    LANGUAGE 'SQL';
+
+--
+-- Mathematical functions
+--
+
+CREATE FUNCTION truncate(numeric,integer)
+    RETURNS numeric
+    AS 'SELECT trunc($1, $2)'
+    LANGUAGE 'SQL';
+
+--
+-- Date/time functions for v7.0
+--
+
+CREATE FUNCTION curdate()
+    RETURNS date
+    AS 'SELECT CAST(''now'' AS date)'
+    LANGUAGE 'SQL';
+
+CREATE FUNCTION curtime()
+    RETURNS time
+    AS 'SELECT CAST(''now'' AS time)'
+    LANGUAGE 'SQL';
+
+CREATE FUNCTION dayname(timestamp)
+    RETURNS text
+    AS 'SELECT to_char($1,''Day'')'
+    LANGUAGE 'SQL';
+
+CREATE FUNCTION dayofmonth(timestamp)
+    RETURNS integer
+    AS 'SELECT  CAST(date_part(''day'', $1) AS integer)'
+    LANGUAGE 'SQL';
+
+CREATE FUNCTION dayofweek(timestamp)
+    RETURNS integer
+    AS 'SELECT ( CAST(date_part(''dow'', $1) AS integer) + 1)'
+    LANGUAGE 'SQL';
+
+CREATE FUNCTION dayofyear(timestamp)
+    RETURNS integer
+    AS 'SELECT  CAST(date_part(''doy'', $1) AS integer)'
+    LANGUAGE 'SQL';
+
+CREATE FUNCTION hour(timestamp)
+    RETURNS integer
+    AS 'SELECT CAST(date_part(''hour'', $1) AS integer)'
+    LANGUAGE 'SQL';
+
+CREATE FUNCTION minute(timestamp)
+    RETURNS integer
+    AS 'SELECT CAST(date_part(''minute'', $1) AS integer)'
+    LANGUAGE 'SQL';
+
+CREATE FUNCTION odbc_month(timestamp)
+    RETURNS integer
+    AS 'SELECT CAST(date_part(''month'', $1) AS integer)'
+    LANGUAGE 'SQL';
+
+CREATE FUNCTION monthname(timestamp)
+    RETURNS text
+    AS 'SELECT to_char($1, ''Month'')'
+    LANGUAGE 'SQL';
+
+CREATE FUNCTION quarter(timestamp)
+    RETURNS integer
+    AS 'SELECT CAST(date_part(''quarter'', $1) AS integer)'
+    LANGUAGE 'SQL';
+
+CREATE FUNCTION second(timestamp)
+    RETURNS integer
+    AS 'SELECT CAST(date_part(''second'', $1) AS integer)'
+    LANGUAGE 'SQL';
+
+/*
+-- The first argument is an integer constant denoting the units
+-- of the second argument. Until we know the actual values, we
+-- cannot implement these. - thomas 2000-04-11
+CREATE FUNCTION timestampadd(integer,integer,timestamp)
+    RETURNS timestamp
+    AS 'SELECT CAST(($3 + ($2 * $1)) AS timestamp)'
+    LANGUAGE 'SQL';
+
+CREATE FUNCTION timestampdiff(integer,integer,timestamp)
+    RETURNS timestamp
+    AS 'SELECT CAST(($3 + ($2 * $1)) AS timestamp)'
+    LANGUAGE 'SQL';
+*/
+
+CREATE FUNCTION week(timestamp)
+    RETURNS integer
+    AS 'SELECT CAST(date_part(''week'', $1) AS integer)'
+    LANGUAGE 'SQL';
+
+CREATE FUNCTION year(timestamp)
+    RETURNS integer
+    AS 'SELECT CAST(date_part(''year'', $1) AS integer)'
+    LANGUAGE 'SQL';
+
+--
+-- System functions.
+--
+
+/*
+CREATE FUNCTION database()
+    RETURNS text
+    AS 'SELECT ...'
+    LANGUAGE 'SQL';
+*/
+
+CREATE FUNCTION odbc_user()
+    RETURNS text
+    AS 'SELECT CAST(USER AS text)'
+    LANGUAGE 'SQL';
+