Skip to content
Snippets Groups Projects
Commit d20763db authored by Tom Lane's avatar Tom Lane
Browse files

Remove contrib modules that have been agreed to be obsolete.

(There are more that will be removed once they've been copied to
pgfoundry.org.)
parent 4cc7a93d
No related branches found
No related tags found
No related merge requests found
Showing
with 1 addition and 2174 deletions
# $PostgreSQL: pgsql/contrib/Makefile,v 1.54 2005/03/12 15:36:24 neilc Exp $
# $PostgreSQL: pgsql/contrib/Makefile,v 1.55 2005/06/22 22:56:25 tgl Exp $
subdir = contrib
top_builddir = ..
......@@ -21,13 +21,9 @@ WANTED_DIRS = \
isbn_issn \
lo \
ltree \
miscutil \
mysql \
noupdate \
oid2name \
pg_autovacuum \
pg_buffercache \
pg_dumplo \
pg_trgm \
pgbench \
pgcrypto \
......@@ -35,26 +31,19 @@ WANTED_DIRS = \
rtree_gist \
seg \
spi \
string \
tablefunc \
tips \
tsearch \
tsearch2 \
userlock \
vacuumlo
# Missing:
# adddepend \ (does not have a makefile)
# array \ (removed all but the README)
# ipc_check \ (does not have a makefile)
# mSQL-interface \ (requires msql installed)
# mac \ (does not have a makefile)
# oracle \ (does not have a makefile)
# pg_upgrade \ (does not have a makefile)
# reindexdb \ (does not have a makefile)
# start-scripts \ (does not have a makefile)
# tools \ (does not have a makefile)
# xml \ (non-standard makefile)
# xml2 \ (non-standard makefile)
......
......@@ -28,10 +28,6 @@ adddepend -
Add object dependency information to pre-7.3 objects.
by Rod Taylor <rbt@rbt.ca>
array -
Array iterator functions (now obsolete due to backend improvements)
by Massimo Dal Zotto <dz@cs.unitn.it>
btree_gist -
Support for emulating BTREE indexing in GiST
by Oleg Bartunov <oleg@sai.msu.su> and Teodor Sigaev <teodor@sigaev.ru>
......@@ -87,10 +83,6 @@ intarray -
Index support for arrays of int4, using GiST
by Teodor Sigaev <teodor@sigaev.ru> and Oleg Bartunov <oleg@sai.msu.su>
ipc_check -
Simple test script to help in configuring IPC.
FreeBSD only, for now.
isbn_issn -
PostgreSQL type extensions for ISBN (books) and ISSN (serials)
by Garrett A. Wollman <wollman@khavrinen.lcs.mit.edu>
......@@ -111,19 +103,6 @@ mac -
Support functions for MAC address types
by Lawrence E. Rosenman <ler@lerctr.org>
miscutil -
PostgreSQL assert checking and various utility functions
by Massimo Dal Zotto <dz@cs.unitn.it>
mysql -
Utility to convert MySQL schema dumps to SQL92 and PostgreSQL
by Thomas Lockhart <lockhart@alumni.caltech.edu>
Max Rudensky <fonin@ziet.zhitomir.ua>
Valentine Danilchuk <valdan@ziet.zhitomir.ua>
noupdate -
Trigger to prevent updates on single columns
oid2name -
Maps numeric files to table names
by B Palmer <bpalmer@crimelabs.net>
......@@ -140,19 +119,11 @@ pg_buffercache -
Real time queries on the shared buffer cache
by Mark Kirkwood <markir@paradise.net.nz>
pg_dumplo -
Dump large objects
by Karel Zak <zakkr@zf.jcu.cz>
pg_trgm -
Functions for determining the similarity of text based on trigram
matching.
by Oleg Bartunov <oleg@sai.msu.su> and Teodor Sigaev <teodor@sigaev.ru>
pg_upgrade -
Upgrade from previous PostgreSQL version without pg_dump/reload
by Bruce Momjian <pgman@candle.pha.pa.us>
pgbench -
TPC-B like benchmarking tool
by Tatsuo Ishii <t-ishii@sra.co.jp>
......@@ -184,10 +155,6 @@ spi -
start-scripts -
Scripts for starting the server at boot time.
string -
C-like input/output conversion routines for strings
by Massimo Dal Zotto <dz@cs.unitn.it>
tablefunc -
Examples of functions returning tables
by Joe Conway <mail@joeconway.com>
......@@ -196,15 +163,6 @@ tips/apache_logging -
Getting Apache to log to PostgreSQL
by Terry Mackintosh <terry@terrym.com>
tools -
Assorted developer tools
by Massimo Dal Zotto <dz@cs.unitn.it>
tsearch -
Full-text-index support using GiST (obsolete version)
by Teodor Sigaev <teodor@sigaev.ru> and Oleg Bartunov
<oleg@sai.msu.su>.
tsearch2 -
Full-text-index support using GiST
by Teodor Sigaev <teodor@sigaev.ru> and Oleg Bartunov
......@@ -218,10 +176,6 @@ vacuumlo -
Remove orphaned large objects
by Peter T Mount <peter@retep.org.uk>
xml -
Storing XML in PostgreSQL (obsolete version)
by John Gray <jgray@azuli.co.uk>
xml2 -
Storing XML in PostgreSQL
by John Gray <jgray@azuli.co.uk>
Array iterator functions have been removed as of PostgreSQL 7.4, because
equivalent functionality is now available built in to the backend.
For example, previously, using contrib/array, you might have used the
following construct:
create table t(id int4[], txt text[]);
-- select tuples with some id element equal to 123
select * from t where t.id *= 123;
Now you would do this instead:
-- select tuples with some id element equal to 123
select * from t where 123 = any (t.id);
-- or you could also do this
select * from t where 123 = some (t.id);
Similarly, if using contrib/array, you did the following:
-- select tuples with all txt elements matching '^[A-Z]'
select * from t where t.txt[1:3] **~ '^[A-Z]';
Now do this instead:
-- select tuples with all txt elements matching '^[A-Z]'
select * from t where '^[A-Z]' ~ all (t.txt[1:3]);
See this section in the PostgreSQL documentation for more detail:
The SQL Language => Functions and Operators => Row and Array Comparisons
This simple perl script was designed under FreeBSD, and, right now, is
limited to it. It provides a simple way of determining and directing
administrators in what has to be done to get IPC working, and configured.
Usage:
ipc_check.pl
- simply checks for semaphores and shared memory being enabled
- if one or other is not enabled, appropriate "options" are provided
to get it compiled into the kernel
ipc_check.pl -B <# of buffers>
- checks to see if there are sufficient shared memory buffers to
run the postmaster with a -B option as provided
- if insufficient buffers are provided, appropriate 'sysctl' commands,
and instructions, are provided to the administrator to increase
them
#!/usr/bin/perl
# Notes ... -B 1 == 8k
if(@ARGV > 1) {
if($ARGV[0] eq "-B") {
$buffers = $ARGV[1];
}
}
if($buffers > 0) {
$kb_memory_required = $buffers * 8;
}
$shm = `sysctl kern.ipc | grep shmall`;
( $junk, $shm_amt ) = split(/ /, $shm);
chomp($shm_amt);
$sem = `sysctl kern.ipc | grep semmap`;
print "\n\n";
if(length($shm) > 0) {
printf "shared memory enabled: %d kB available\n", $shm_amt * 4;
if($buffers > 0) {
if($kb_memory_required / 4 > $shm_amt) {
print "\n";
print "to provide enough shared memory for a \"-B $buffers\" setting\n";
print "issue the following command\n\n";
printf "\tsysctl -w kern.ipc.shmall=%d\n", $kb_memory_required / 4;
print "\nand add the following to your /etc/sysctl.conf file:\n\n";
printf "\tkern.ipc.shmall=%d\n", $kb_memory_required / 4;
} else {
print "\n";
print "no changes to kernel required for a \"-B $buffers\" setting\n";
}
}
} else {
print "no shared memory support available\n";
print "add the following option to your kernel config:\n\n";
print "\toptions SYSVSHM\n\n";
}
print "\n==========================\n\n";
if(length($sem) > 0) {
print "semaphores enabled\n";
} else {
print "no semaphore support available\n";
print "add the following option to your kernel config:\n\n";
print "\toptions SYSVSEM\n\n";
}
# $PostgreSQL: pgsql/contrib/miscutil/Makefile,v 1.18 2004/08/20 20:13:05 momjian Exp $
MODULES = misc_utils
DATA_built = misc_utils.sql
DOCS = README.misc_utils
ifdef USE_PGXS
PGXS = $(shell pg_config --pgxs)
include $(PGXS)
else
subdir = contrib/miscutil
top_builddir = ../..
include $(top_builddir)/src/Makefile.global
include $(top_srcdir)/contrib/contrib-global.mk
endif
Miscellaneous utility functions for PostgreSQL.
Copyright (C) 1999, Massimo Dal Zotto <dz@cs.unitn.it>
This software is distributed under the GNU General Public License
either version 2, or (at your option) any later version.
backend_pid()
return the pid of our corresponding backend.
unlisten(relname)
unlisten from a relation or from all relations if the argument
is null, empty or '*'.
It is now obsoleted by the new unlisten command but still useful
if you want unlisten a name computed by the query.
Note that a listen/notify relname can be any ascii string, not
just valid relation names.
min(x,y)
max(x,y)
return the min or max of two integers.
--
Massimo Dal Zotto <dz@cs.unitn.it>
/*
* misc_utils.c --
*
* This file defines miscellaneous PostgreSQL utility functions.
*
* Copyright (C) 1999, Massimo Dal Zotto <dz@cs.unitn.it>
*
* This file is distributed under the GNU General Public License
* either version 2, or (at your option) any later version.
*/
#include "postgres.h"
#include <unistd.h>
#include <signal.h>
#include "access/heapam.h"
#include "access/htup.h"
#include "access/relscan.h"
#include "access/skey.h"
#include "access/tupdesc.h"
#include "catalog/pg_listener.h"
#include "commands/async.h"
#include "fmgr.h"
#include "storage/lmgr.h"
#include "utils/fmgroids.h"
#include "utils/rel.h"
#include "utils/tqual.h"
#include "misc_utils.h"
int
backend_pid(void)
{
return getpid();
}
int
unlisten(char *relname)
{
Async_Unlisten(relname, getpid());
return 0;
}
int
int4max(int x, int y)
{
return Max(x, y);
}
int
int4min(int x, int y)
{
return Min(x, y);
}
/*
* Return the number of active listeners on a relation name.
*/
int
active_listeners(text *relname)
{
HeapTuple lTuple;
Relation lRel;
HeapScanDesc sRel;
TupleDesc tdesc;
ScanKeyData key;
Datum d;
bool isnull;
int len,
pid;
int count = 0;
int ourpid = getpid();
char listen_name[NAMEDATALEN];
lRel = heap_open(ListenerRelationId, AccessShareLock);
tdesc = RelationGetDescr(lRel);
if (relname && (VARSIZE(relname) > VARHDRSZ))
{
MemSet(listen_name, 0, NAMEDATALEN);
len = Min(VARSIZE(relname) - VARHDRSZ, NAMEDATALEN - 1);
memcpy(listen_name, VARDATA(relname), len);
ScanKeyInit(&key,
Anum_pg_listener_relname,
BTEqualStrategyNumber, F_NAMEEQ,
PointerGetDatum(listen_name));
sRel = heap_beginscan(lRel, SnapshotNow, 1, &key);
}
else
sRel = heap_beginscan(lRel, SnapshotNow, 0, (ScanKey) NULL);
while ((lTuple = heap_getnext(sRel, ForwardScanDirection)) != NULL)
{
d = heap_getattr(lTuple, Anum_pg_listener_pid, tdesc, &isnull);
pid = DatumGetInt32(d);
if ((pid == ourpid) || (kill(pid, 0) == 0))
count++;
}
heap_endscan(sRel);
heap_close(lRel, AccessShareLock);
return count;
}
#ifndef MISC_UTILS_H
#define MISC_UTILS_H
int backend_pid(void);
int unlisten(char *relname);
int int4max(int x, int y);
int int4min(int x, int y);
int active_listeners(text *relname);
#endif
-- misc_utils.sql --
--
-- SQL code to define misc functions.
--
-- Copyright (c) 1998, Massimo Dal Zotto <dz@cs.unitn.it>
--
-- This file is distributed under the GNU General Public License
-- either version 2, or (at your option) any later version.
-- Return the pid of the backend.
--
-- Adjust this setting to control where the objects get created.
SET search_path = public;
CREATE OR REPLACE FUNCTION backend_pid()
RETURNS int4
AS 'MODULE_PATHNAME'
LANGUAGE 'C';
-- Unlisten from a relation.
--
CREATE OR REPLACE FUNCTION "unlisten"(name)
RETURNS int4
AS 'MODULE_PATHNAME'
LANGUAGE 'C';
-- Unlisten from all relations for this backend.
--
CREATE OR REPLACE FUNCTION "unlisten"()
RETURNS int4
AS 'SELECT "unlisten"(''*'')'
LANGUAGE 'SQL';
-- min(x,y)
--
CREATE OR REPLACE FUNCTION min(int4,int4)
RETURNS int4
AS 'MODULE_PATHNAME', 'int4min'
LANGUAGE 'C' STRICT;
-- max(x,y)
--
CREATE OR REPLACE FUNCTION max(int4,int4)
RETURNS int4
AS 'MODULE_PATHNAME', 'int4max'
LANGUAGE 'C' STRICT;
-- Return the number of active listeners on a relation
--
CREATE OR REPLACE FUNCTION active_listeners(text)
RETURNS int4
AS 'MODULE_PATHNAME'
LANGUAGE 'C';
# mysql conversion Perl scripts
# $PostgreSQL: pgsql/contrib/mysql/Makefile,v 1.1 2004/11/04 06:09:21 neilc Exp $
MODULES =
SCRIPTS = my2pg.pl mysql2pgsql
DOCS = README.mysql
ifdef USE_PGXS
PGXS = $(shell pg_config --pgxs)
include $(PGXS)
else
subdir = contrib/mysql
top_builddir = ../..
include $(top_builddir)/src/Makefile.global
include $(top_srcdir)/contrib/contrib-global.mk
endif
Here are two conversion utilities for MySQL dumps. Use the one you prefer.
The most recent version of my2pg.pl can be obtained from:
http://www.omnistarinc.com/~fonin/downloads.php#my2pg
my2pg.diff has additional changes for CREATE FUNCTION.
Another tool, mysql2pgsql, can be found at:
http://gborg.postgresql.org/project/mysql2psql/projdisplay.php
*** /laptop/my2pg.pl Mon Apr 19 18:51:44 2004
--- my2pg.pl Mon Apr 19 18:59:09 2004
***************
*** 38,43 ****
--- 38,50 ----
# $My2pg: my2pg.pl,v 1.28 2001/12/06 19:32:20 fonin Exp $
# $Id: my2pg.diff,v 1.1 2004/04/19 23:18:12 momjian Exp $
+ # Custom patch
+ # Revision 1.9 2002/08/22 00:01:39 tgl
+ # Add a bunch of pseudo-types to replace the behavior formerly associated
+ # with OPAQUE, as per recent pghackers discussion. I still want to do some
+ # more work on the 'cstring' pseudo-type, but I'm going to commit the bulk
+ # of the changes now before the tree starts shifting under me ...
+
#
# $Log: my2pg.diff,v $
# Revision 1.1 2004/04/19 23:18:12 momjian
# Update to my2pg version 1.28, add docs, update URL for newest version.
#
# Create diff of custom changes Tom made to the utility for CREATE
# FUNCTION.
#
# This will make moving this utility out of CVS easier.
#
# Revision 1.28 2002/11/30 12:03:48 fonin
***************
*** 332,342 ****
print LIBTYPES "\n * Types for table ".uc($table_name);
print LIBTYPES "\n */\n";
! $types.="\nCREATE FUNCTION $typename"."_in (opaque)
RETURNS $typename
AS '$libtypename'
LANGUAGE 'c'
! WITH (ISCACHABLE);\n";
# creating output function
my $func_out="
--- 339,349 ----
print LIBTYPES "\n * Types for table ".uc($table_name);
print LIBTYPES "\n */\n";
! $types.="\nCREATE FUNCTION $typename"."_in (cstring)
RETURNS $typename
AS '$libtypename'
LANGUAGE 'c'
! WITH (ISSTRICT, ISCACHABLE);\n";
# creating output function
my $func_out="
***************
*** 386,396 ****
return (*a>=*b);
}\n";
! $types.="\nCREATE FUNCTION $typename"."_out (opaque)
! RETURNS opaque
AS '$libtypename'
LANGUAGE 'c'
! WITH (ISCACHABLE);\n";
$types.="\nCREATE TYPE $typename (
internallength = 2,
--- 393,403 ----
return (*a>=*b);
}\n";
! $types.="\nCREATE FUNCTION $typename"."_out ($typename)
! RETURNS cstring
AS '$libtypename'
LANGUAGE 'c'
! WITH (ISSTRICT, ISCACHABLE);\n";
$types.="\nCREATE TYPE $typename (
internallength = 2,
***************
*** 532,538 ****
print LIBTYPES "\n * Types for table ".uc($table_name);
print LIBTYPES "\n */\n";
! $types.="\nCREATE FUNCTION $typename"."_in (opaque)
RETURNS $typename
AS '$libtypename'
LANGUAGE 'c';\n";
--- 539,545 ----
print LIBTYPES "\n * Types for table ".uc($table_name);
print LIBTYPES "\n */\n";
! $types.="\nCREATE FUNCTION $typename"."_in (cstring)
RETURNS $typename
AS '$libtypename'
LANGUAGE 'c';\n";
***************
*** 584,591 ****
\n";
! $types.="\nCREATE FUNCTION $typename"."_out (opaque)
! RETURNS opaque
AS '$libtypename'
LANGUAGE 'c';\n";
--- 591,598 ----
\n";
! $types.="\nCREATE FUNCTION $typename"."_out ($typename)
! RETURNS cstring
AS '$libtypename'
LANGUAGE 'c';\n";
<HTML>
<HEAD>
<TITLE>my2pg - MySQL -> PostgreSQL dump conversion utility.</TITLE>
<LINK REV="made" HREF="mailto:bhcompile@daffy.perf.redhat.com">
</HEAD>
<BODY>
<A NAME="__index__"></A>
<!-- INDEX BEGIN -->
<UL>
<LI><A HREF="#name">NAME</A></LI>
<LI><A HREF="#syntax">SYNTAX</A></LI>
<LI><A HREF="#overview">OVERVIEW</A></LI>
<LI><A HREF="#commandline options">COMMAND-LINE OPTIONS</A></LI>
<LI><A HREF="#side effects">SIDE EFFECTS</A></LI>
<LI><A HREF="#bugs">BUGS</A></LI>
<LI><A HREF="#authors">AUTHORS</A></LI>
<LI><A HREF="#credits">CREDITS</A></LI>
<LI><A HREF="#license">LICENSE</A></LI>
</UL>
<!-- INDEX END -->
<HR>
<P>
<H1><A NAME="name">NAME</A></H1>
<P>my2pg - MySQL -&gt; PostgreSQL dump conversion utility.</P>
<P>
<HR>
<H1><A NAME="syntax">SYNTAX</A></H1>
<PRE>
mysqldump db | ./my2pg.pl [-nds] &gt; pgsqldump.sql
vi libtypes.c
make
psql database &lt; pgsqldump.txt
where</PRE>
<DL>
<DT><STRONG><A NAME="item_pgsqldump%2Esql"><EM>pgsqldump.sql</EM></A></STRONG><BR>
<DD>
- file suitable for loading into PostgreSQL.
<P></P>
<DT><STRONG><A NAME="item_libtypes%2Ec"><EM>libtypes.c</EM></A></STRONG><BR>
<DD>
- C source for emulated MySQL types (ENUM, SET) generated by <STRONG>my2pg</STRONG>
<P></P></DL>
<P>
<HR>
<H1><A NAME="overview">OVERVIEW</A></H1>
<P><STRONG>my2pg</STRONG> utility attempts to convert MySQL database dump to Postgres's one.
<STRONG>my2pg</STRONG> performs such conversions:</P>
<UL>
<LI><STRONG><A NAME="item_Type_conversion%2E">Type conversion.</A></STRONG><BR>
It tries to find proper Postgres
type for each column.
Unknown types are silently pushing to output dump;
ENUM and SET types implemented via user types
(C source for such types can be found in
<STRONG>libtypes.c</STRONG> file);
<P></P>
<LI><STRONG><A NAME="item_Encloses_identifiers_into_double_quotes%2E">Encloses identifiers into double quotes.</A></STRONG><BR>
All column and table
names should be enclosed to double-quotes to prevent
conflict with reserved SQL keywords;
<P></P>
<LI><STRONG><A NAME="item_Converting">Converting</A></STRONG><BR>
AUTO_INCREMENT fields to SERIAL. Actually, creating the sequence and
setting default value to nextval('seq'), well, you know :)
<P></P>
<LI><STRONG>Converting</STRONG><BR>
<CODE>KEY(field)</CODE> to CREATE INDEX i_field on table (field);
<P></P>
<LI><STRONG><A NAME="item_The_same">The same</A></STRONG><BR>
for UNIQUE keys;
<P></P>
<LI><STRONG><A NAME="item_Indices">Indices</A></STRONG><BR>
are creating AFTER rows insertion (to speed up the load);
<P></P>
<LI><STRONG><A NAME="item_Translates_%27%23%27">Translates '#'</A></STRONG><BR>
MySQL comments to ANSI SQL '--'
<P></P></UL>
<P>It encloses dump in transaction block to prevent single errors
during data load.</P>
<P>
<HR>
<H1><A NAME="commandline options">COMMAND-LINE OPTIONS</A></H1>
<P>My2pg takes the following command-line options:</P>
<DL>
<DT><STRONG><A NAME="item_%2Dn">-n</A></STRONG><BR>
<DD>
Convert *CHAR DEFAULT '' NOT NULL types to *CHAR NULL.
Postgres can't load empty '' strings in NOT NULL fields.
<P></P>
<DT><STRONG><A NAME="item_%2Dd">-d</A></STRONG><BR>
<DD>
Add double quotes around table and column names
<P></P>
<DT><STRONG><A NAME="item_%2Dh">-h</A></STRONG><BR>
<DD>
Show usage banner.
<P></P>
<DT><STRONG><A NAME="item_%2Ds">-s</A></STRONG><BR>
<DD>
Do not attempt to convert data. Currently my2pg only tries to convert
date and time data.
<P></P></DL>
<P>
<HR>
<H1><A NAME="side effects">SIDE EFFECTS</A></H1>
<UL>
<LI><STRONG><A NAME="item_creates">creates</A></STRONG><BR>
file <STRONG>libtypes.c</STRONG> in current directory
overwriting existed file without any checks;
<P></P>
<LI><STRONG><A NAME="item_the_same">the same</A></STRONG><BR>
for Makefile.
<P></P></UL>
<P>
<HR>
<H1><A NAME="bugs">BUGS</A></H1>
<P>Known bugs are:</P>
<UL>
<LI><STRONG><A NAME="item_Possible_problems_with_the_timestamp_data%2E">Possible problems with the timestamp data.</A></STRONG><BR>
PostgreSQL does not accept incorrect date/time values like <STRONG>2002-00-15</STRONG>,
while MySQL does not care about that. Currently my2pg cannot handle this
issue. You should care yourself to convert such a data.
<P></P>
<LI><STRONG><A NAME="item_Use_%2Ds_option_if_your_numeric_data_are_broken_du">Use -s option if your numeric data are broken during conversion.</A></STRONG><BR>
My2pg attempts to convert MySQL timestamps of the form <STRONG>yyyymmdd</STRONG> to
<STRONG>yyyy-mm-dd</STRONG> and <STRONG>yyyymmddhhmmss</STRONG> to <STRONG>yyyy-mm-dd hh:mm:ss</STRONG>. It performs
some heuristic checks to ensure that the month,day,hour,minutes and seconds have
values from the correct range (0..12, 0..31, 0..23, 0..59, 0..59 respectively).
It is still possible that your numeric values that satisfy these conditions
will get broken.
<P></P>
<LI><STRONG><A NAME="item_Possible_problems_with_enclosing_identifiers_in_do">Possible problems with enclosing identifiers in double quotes.</A></STRONG><BR>
All identifiers such as table and column names should be enclosed in double
quotes. Program can't handle upper-case identifiers,
like DBA. Lower-case identifiers are OK.
<P></P>
<LI><STRONG><A NAME="item_SET_type_emulation_is_not_full%2E_LIKE_operation_o">SET type emulation is not full. LIKE operation on</A></STRONG><BR>
SETs, raw integer input values should be implemented
<P></P>
<LI><STRONG><A NAME="item_Makefile"><STRONG>Makefile</STRONG></A></STRONG><BR>
generated during output is
platform-dependent and surely works only on
Linux/gcc (FreeBSD/gcc probably works as well - not tested)
<P></P>
<LI><STRONG><A NAME="item_Generated_libtypes%2Ec_contain_line">Generated <STRONG>libtypes.c</STRONG> contain line</A></STRONG><BR>
<PRE>
#include &lt;postgres.h&gt;</PRE>
<P>This file may be located not in standard compiler
include path, you need to check it before compiling.</P>
</UL>
<P>
<HR>
<H1><A NAME="authors">AUTHORS</A></H1>
<P><STRONG>(c) 2000-2002 Maxim V. Rudensky (<A HREF="mailto:fonin@omnistaronline.com">fonin@ziet.zhitomir.ua</A>)</STRONG> (developer, maintainer)</P>
<P><STRONG>(c) 2000 Valentine V. Danilchuk (<A HREF="mailto:valdan@ziet.zhitomir.ua">valdan@ziet.zhitomir.ua</A>)</STRONG> (original script)</P>
<P>
<HR>
<H1><A NAME="credits">CREDITS</A></H1>
<P>Great thanks to all those people who provided feedback and make development
of this tool easier.</P>
<P>Jeff Waugh &lt;<A HREF="mailto:jaw@ic.net">jaw@ic.net</A>&gt;</P>
<P>Joakim Lemstrm &lt;<A HREF="mailto:jocke@bytewize.com">jocke@bytewize.com</A>&gt; || &lt;<A HREF="mailto:buddyh19@hotmail.com">buddyh19@hotmail.com</A>&gt;</P>
<P>Yunliang Yu &lt;<A HREF="mailto:yu@math.duke.edu">yu@math.duke.edu</A>&gt;</P>
<P>Brad Hilton &lt;<A HREF="mailto:bhilton@vpop.net">bhilton@vpop.net</A>&gt;</P>
<P>If you are not listed here please write to me.</P>
<P>
<HR>
<H1><A NAME="license">LICENSE</A></H1>
<P><STRONG>BSD</STRONG></P>
</BODY>
</HTML>
#!/usr/bin/perl
#
# My2Pg: MySQL to PostgreSQL dump conversion utility
#
# (c) 2000,2001 Maxim Rudensky <fonin@ziet.zhitomir.ua>
# (c) 2000 Valentine Danilchuk <valdan@ziet.zhitomir.ua>
# All right reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. All advertising materials mentioning features or use of this software
# must display the following acknowledgement:
# This product includes software developed by the Max Rudensky
# and its contributors.
# 4. Neither the name of the author nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# $My2pg: my2pg.pl,v 1.28 2001/12/06 19:32:20 fonin Exp $
# $Id: my2pg.pl,v 1.13 2004/04/19 23:18:12 momjian Exp $
# Custom patch
# Revision 1.9 2002/08/22 00:01:39 tgl
# Add a bunch of pseudo-types to replace the behavior formerly associated
# with OPAQUE, as per recent pghackers discussion. I still want to do some
# more work on the 'cstring' pseudo-type, but I'm going to commit the bulk
# of the changes now before the tree starts shifting under me ...
#
# $Log: my2pg.pl,v $
# Revision 1.13 2004/04/19 23:18:12 momjian
# Update to my2pg version 1.28, add docs, update URL for newest version.
#
# Create diff of custom changes Tom made to the utility for CREATE
# FUNCTION.
#
# This will make moving this utility out of CVS easier.
#
# Revision 1.12 2004/04/19 23:11:49 momjian
# Update to my2pg 1.28, from:
#
# http://www.omnistarinc.com/~fonin/downloads.php#my2pg
#
# Revision 1.28 2002/11/30 12:03:48 fonin
# PostgreSQL does not support indexes on the partial length of column,
# e.g.
# CREATE INDEX i_index ON table (column(16));
# will not work. Fixed.
#
# Added command-line option -s that prevents my2pg from attempting convert
# the data (currently only timestamps).
#
# Better timestamps conversion.
#
# Revision 1.27 2002/07/16 14:54:07 fonin
# Bugfix - didn't quote the fields inside PRIMARY KEY with -d option.
# Fix by Milan P. Stanic <mps@rns-nis.co.yu>.
#
# Revision 1.26 2002/07/14 10:30:27 fonin
# Bugfix - MySQL keywords inside data (INSERT INTO sentence) were replaced
# with Postgres keywords and therefore messed up the data.
#
# Revision 1.25 2002/07/05 09:20:25 fonin
# - fixed data that contains two consecutive timestamps - thanks to
# Ben Darnell <bdarnell@google.com>
# - word 'default' was converted to upper case inside the data - fixed.
# Thanks to Madsen Wikholm <madsen@iki.fi>
#
# Revision 1.24 2002/04/20 14:15:43 fonin
# Patch by Felipe Nievinski <fnievinski@terra.com.br>.
# A table I was re-creating had a composite primary key, and I was using
# the -d switch to maintain the table and column names
# adding double quotes around them.
#
# The SQL code generated was something like this:
#
# CREATE TABLE "rinav" (
# "UnidadeAtendimento" INT8 DEFAULT '0' NOT NULL,
# "NumeroRinav" INT8 DEFAULT '0' NOT NULL,
# -- ...
# PRIMARY KEY ("UnidadeAtendimento"," NumeroRinav")
# );
#
# Please note the space inside the second column name string in the PK
# definition. Because of this PostgreSQL was not able to create the table.
#
# FIXED.
#
# Revision 1.23 2002/02/07 22:13:52 fonin
# Bugfix by Hans-Juergen Schoenig <hs@cybertec.at>: additional space after
# FLOAT8 is required.
#
# Revision 1.22 2001/12/06 19:32:20 fonin
# Patch: On line 594 where you check for UNIQUE, I believe the regex should try
# and match 'UNIQUE KEY'. Otherwise it outputs no unique indexes for the
# postgres dump.
# Thanks to Brad Hilton <bhilton@vpop.net>
#
# Revision 1.21 2001/08/25 18:55:28 fonin
# Incorporated changes from Yunliang Yu <yu@math.duke.edu>:
# - By default table & column names are not quoted; use the new
# "-d" option if you want to,
# - Use conditional substitutions to speed up and preserve
# the data integrity.
# Fixes by Max:
# - timestamps conversion fix. Shouldn't break now matching binary data and
# strings.
#
# Revision 1.21 2001/07/23 03:04:39 yu
# Updates & fixes by Yunliang Yu <yu@math.duke.edu>
# . By default table & column names are not quoted; use the new
# "-d" option if you want to,
# . Use conditional substitutions to speed up and preserve
# the data integrity.
#
# Revision 1.20 2001/07/05 12:45:05 fonin
# Timestamp conversion enhancement from Joakim Lemström <jocke@bytewize.com>
#
# Revision 1.19 2001/05/07 19:36:38 fonin
# Fixed a bug in quoting PRIMARY KEYs, KEYs and UNIQUE indexes with more than 2 columns. Thanks to Jeff Waugh <jaw@ic.net>.
#
# Revision 1.18 2001/03/06 22:25:40 fonin
# Documentation up2dating.
#
# Revision 1.17 2001/03/04 13:01:50 fonin
# Fixes to make work it right with MySQL 3.23 dumps. Tested on mysqldump 8.11.
# Also, AUTO_INCREMENT->SERIAL fields no more have DEFAULT and NOT NULL
# definitions.
#
# Revision 1.16 2001/02/02 08:15:34 fonin
# Sequences should be created BEFORE creating any objects \nthat depends on it.
#
# Revision 1.15 2001/01/30 10:13:36 fonin
# Re-released under BSD-like license.
#
# Revision 1.14 2000/12/18 20:55:13 fonin
# Better -n implementation.
#
# Revision 1.13 2000/12/18 15:26:33 fonin
# Added command-line options. -n forces *CHAR DEFAULT '' NOT NULL to be
# converted to *CHAR NULL.
# AUTO_INCREMENT fields converted not in SERIAL but in
# INT* NOT NULL DEFAULT nextval('seqname').
# Documentation refreshed.
# Dump enclosed in single transaction from now.
#
# Revision 1.12 2000/12/14 20:57:15 fonin
# Doublequotation bug fixed (in CREATE INDEX ON TABLE (field1,field2))
#
# Revision 1.10 2000/11/27 14:18:22 fonin
# Fixed bug - occasionaly was broken CREATE SEQUENCE generation
#
# Revision 1.8 2000/11/24 15:24:16 fonin
# TIMESTAMP fix: MySQL output YYYYMMDDmmhhss to YYYYMMDD mmhhss
#
# Revision 1.7 2000/11/22 23:04:41 fonin
# TIMESTAMP field fix. Better doublequoting. Splitting output dump
# into 2 transactions - create/load/indexing first, sequence setvals then.
# Added POD documentation.
#
#
use Getopt::Std;
my %opts; # command line options
my $chareg=''; # CHAR conversion regexps
my $dq=''; # double quote
# parse command line
getopts('nhds',\%opts);
# output syntax
if($opts{h} ne '') {
usage();
exit;
}
# convert CHAR types from NOT NULL DEFAULT '' to NULL
if($opts{n} ne '') {
$chareg='\s*?(default\s*?\'\')*?\s*?not\s*?null';
}
# want double quotes
if($opts{d} ne '') {
$dq='"';
}
if($opts{s} ne '') {
$safe_data_conv=1;
}
else {
$safe_data_conv=0;
}
$|=1;
print("------------------------------------------------------------------");
print("\n-- My2Pg 1.28 translated dump");
print("\n--");
print("\n------------------------------------------------------------------");
print("\n\nBEGIN;\n\n\n");
my %index; # contains array of CREATE INDEX for each table
my %seq; # contains CREATE SEQUENCE for each table
my %primary; # contains primary (eg SERIAL) fields for each table
my %identifier; # contains generated by this program identifiers
my $j=-1; # current position in $index{table}
my @check; # CHECK constraint for current
# generating full path to libtypes.c
my $libtypesource='libtypes.c';
my $libtypename=`pwd`;
chomp($libtypename);
$libtypename.='/libtypes.so';
# push header to libtypes.c
open(LIBTYPES,">$libtypesource");
print LIBTYPES "/******************************************************";
print LIBTYPES "\n * My2Pg 1.27 \translated dump";
print LIBTYPES "\n * User types definitions";
print LIBTYPES "\n ******************************************************/";
print LIBTYPES "\n\n#include <postgres.h>\n";
print LIBTYPES "\n#define ADD_COMMA if(strcmp(result,\"\")!=0) strcat(result,\",\")\n";
# reading STDIN...
my $tabledef=0; # we are outside a table definition
while (<>) {
if(!$tabledef && /^CREATE TABLE \S+/i){
$tabledef=1;
} elsif($tabledef && /^\) type=\w*;/i){ # /^\w/i
$tabledef=0;
}
# Comments start with -- in SQL
if(/^#/) {# !/insert into.*\(.*#.*\)/i, in mysqldump output
s/#/--/;
}
if($tabledef) {
# Convert numeric types
s/tinyint\(\d+\)/INT2/i;
s/smallint\(\d+\)/INT2/i;
s/mediumint\(\d+\)/INT4/i;
s/bigint\(\d+\)/INT8/i;
s/int\(\d+\)/INT4/i;
s/float(\(\d+,\d*\))/DECIMAL$1/i;
s/double precision/FLOAT8 /i;
s/([\W])double(\(\d+,\d*\))/$1DECIMAL$2/i;
s/([\W])double[\W]/$1FLOAT8 /i;
s/([\W])real[\W]/$1FLOAT8 /i;
s/([\W])real(\(\d+,\d*\))/$1DECIMAL$2/i;
# Convert string types
s/\w*blob$chareg/text/i;
s/mediumtext$chareg/text/i;
s/tinytext$chareg/text/i;
s/\stext\s+not\s+null/ TEXT DEFAULT '' NOT NULL/i;
s/(.*?char\(.*?\))$chareg/$1/i;
# Old and New are reserved words in Postgres
s/^(\s+)Old /${1}MyOld /;
s/^(\s+)New /${1}MyNew /;
# Convert DATE types
s/datetime/TIMESTAMP/;
s/timestamp\(\d+\)/TIMESTAMP/i;
s/ date / DATE /i;
if((/date/ig || /time/ig) && /[,(]\d{4}(\d{2})(\d{2})[,)]/ &&
$1>=0 && $1<=12 && $2>=0 && $2<=31) {
s/,(\d{4})(\d{2})(\d{2}),/,'$1-$2-$3 00:00:00',/g;
}
# small hack - convert "default" to uppercase, because below we
# enclose all lowercase words in double quotes
if(!/^INSERT/) {
s/default/DEFAULT/;
}
# Change all AUTO_INCREMENT fields to SERIAL ones with a pre-defined sequence
if(/([\w\d]+)\sint.*auto_increment/i) {
$tmpseq=new_name("$table_name"."_"."$+"."_SEQ",28);
$seq{$table_name}=$tmpseq;
$primary{$table_name}=$+;
s/(int.*?) .*AUTO_INCREMENT/$1 DEFAULT nextval\('$tmpseq'\)/i;
}
# convert UNSIGNED to CHECK constraints
if(/^\s+?([\w\d_]+).*?unsigned/i) {
$check.=",\n CHECK ($dq$1$dq>=0)";
}
s/unsigned//i;
# Limited ENUM support - little heuristic
s/enum\('N','Y'\)/BOOL/i;
s/enum\('Y','N'\)/BOOL/i;
# ENUM support
if(/^\s+?([\w\d_]+).*?enum\((.*?)\)/i) {
my $enumlist=$2;
my @item;
$item[0]='';
while($enumlist=~s/'([\d\w_]+)'//i) {
$item[++$#item]=$1;
}
# forming identifier name
$typename=new_name('enum_'.$table_name.'_'.$item[1],28);
# creating input type function
my $func_in="
int2* $typename"."_in (char *str) {
int2* result;
if(str==NULL)
return NULL;
result=(int2*)palloc(sizeof(int2));
*result=-1;";
for(my $i=0;$i<=$#item;$i++) {
$func_in.="
if(strcmp(str,\"$item[$i]\")==0) {
*result=$i;
}";
}
$func_in.="
if(*result == -1) {
elog(ERROR,\"$typename"."_in: incorrect input value\");
return NULL;
}
return (result);
}\n";
$types.="\n---";
$types.="\n--- Types for table ".uc($table_name);
$types.="\n---\n";
print LIBTYPES "\n/*";
print LIBTYPES "\n * Types for table ".uc($table_name);
print LIBTYPES "\n */\n";
$types.="\nCREATE FUNCTION $typename"."_in (cstring)
RETURNS $typename
AS '$libtypename'
LANGUAGE 'c'
WITH (ISSTRICT, ISCACHABLE);\n";
# creating output function
my $func_out="
char* $typename"."_out (int2 *outvalue) {
char* result;
if(outvalue==NULL)
return NULL;
result=(char*)palloc(10);
switch (*outvalue) {";
for(my $i=0;$i<=$#item;$i++) {
$func_out.="
case $i:
strcpy(result,\"$item[$i]\");
break;";
}
$func_out.="
default :
elog(ERROR,\"$typename"."_out: incorrect stored value\");
return NULL;
break;
}
return result;
}\n";
$func_out.="\nbool $typename"."_eq(int2* a, int2* b) {
return (*a==*b);
}
bool $typename"."_ne(int2* a, int2* b) {
return (*a!=*b);
}
bool $typename"."_lt(int2* a, int2* b) {
return (*a<*b);
}
bool $typename"."_le(int2* a, int2* b) {
return (*a<=*b);
}
bool $typename"."_gt(int2* a, int2* b) {
return (*a>*b);
}
bool $typename"."_ge(int2* a, int2* b) {
return (*a>=*b);
}\n";
$types.="\nCREATE FUNCTION $typename"."_out ($typename)
RETURNS cstring
AS '$libtypename'
LANGUAGE 'c'
WITH (ISSTRICT, ISCACHABLE);\n";
$types.="\nCREATE TYPE $typename (
internallength = 2,
input = $typename\_in,
output = $typename\_out
);\n";
$types.="\nCREATE FUNCTION $typename"."_eq ($typename,$typename)
RETURNS bool
AS '$libtypename'
LANGUAGE 'c';
CREATE FUNCTION $typename"."_lt ($typename,$typename)
RETURNS bool
AS '$libtypename'
LANGUAGE 'c';
CREATE FUNCTION $typename"."_le ($typename,$typename)
RETURNS bool
AS '$libtypename'
LANGUAGE 'c';
CREATE FUNCTION $typename"."_gt ($typename,$typename)
RETURNS bool
AS '$libtypename'
LANGUAGE 'c';
CREATE FUNCTION $typename"."_ge ($typename,$typename)
RETURNS bool
AS '$libtypename'
LANGUAGE 'c';
CREATE FUNCTION $typename"."_ne ($typename,$typename)
RETURNS bool
AS '$libtypename'
LANGUAGE 'c';
CREATE OPERATOR < (
leftarg = $typename,
rightarg = $typename,
-- negator = >=,
procedure = $typename"."_lt
);
CREATE OPERATOR <= (
leftarg = $typename,
rightarg = $typename,
-- negator = >,
procedure = $typename"."_le
);
CREATE OPERATOR = (
leftarg = $typename,
rightarg = $typename,
commutator = =,
-- negator = <>,
procedure = $typename"."_eq
);
CREATE OPERATOR >= (
leftarg = $typename,
rightarg = $typename,
negator = <,
procedure = $typename"."_ge
);
CREATE OPERATOR > (
leftarg = $typename,
rightarg = $typename,
negator = <=,
procedure = $typename"."_gt
);
CREATE OPERATOR <> (
leftarg = $typename,
rightarg = $typename,
negator = =,
procedure = $typename"."_ne
);\n";
print LIBTYPES $func_in;
print LIBTYPES $func_out;
s/enum\(.*?\)/$typename/i;
}
# SET support
if(/^\s+?([\w\d_]+).*?set\((.*?)\)/i) {
my $setlist=$2;
my @item;
$item[0]='';
my $maxlen=0; # maximal string length
while($setlist=~s/'([\d\w_]+)'//i) {
$item[++$#item]=$1;
$maxlen+=length($item[$#item])+1;
}
$maxlen+=1;
my $typesize=int($#item/8);
if($typesize<2) {
$typesize=2;
}
$internalsize=$typesize;
$typesize='int'.$typesize;
$typename=new_name('set_'.$table_name.'_'.$item[1],28);
# creating input type function
my $func_in="
$typesize* $typename"."_in (char *str) {
$typesize* result;
char* token;
if(str==NULL)
return NULL;
result=($typesize*)palloc(sizeof($typesize));
*result=0;
if(strcmp(str,\"\")==0)
return result;
for(token=strtok(str,\",\");token!=NULL;token=strtok(NULL,\",\")) {";
for(my $i=0,my $j=1;$i<=$#item;$i++,$j*=2) {
$func_in.="
if(strcmp(token,\"$item[$i]\")==0) {
*result|=$j;
continue;
}";
}
$func_in.="
}
if(*result == 0) {
elog(ERROR,\"$typename"."_in: incorrect input value\");
return NULL;
}
return (result);
}\n";
$types.="\n---";
$types.="\n--- Types for table ".uc($table_name);
$types.="\n---\n";
print LIBTYPES "\n/*";
print LIBTYPES "\n * Types for table ".uc($table_name);
print LIBTYPES "\n */\n";
$types.="\nCREATE FUNCTION $typename"."_in (cstring)
RETURNS $typename
AS '$libtypename'
LANGUAGE 'c';\n";
# creating output function
my $func_out="
char* $typename"."_out ($typesize *outvalue) {
char* result;
int i;
if(outvalue==NULL)
return NULL;
result=(char*)palloc($maxlen);
strcpy(result,\"\");
for(i=1;i<=2 << (sizeof(int2)*8);i*=2) {
switch (*outvalue & i) {";
for(my $i=0,$j=1;$i<=$#item;$i++,$j*=2) {
$func_out.="
case $j:";
if($item[$i] ne '') {
$func_out.="ADD_COMMA;";
}
$func_out.="strcat(result,\"$item[$i]\");
break;";
}
$func_out.="
default :
break;
}
}
return result;
}\n";
$func_out.="\nbool $typename"."_eq($typesize* a, $typesize* b) {
return (*a==*b);
}
$typesize find_in_set($typesize *a, $typesize *b) {
int i;
for(i=1;i<=sizeof($typesize)*8;i*=2) {
if(*a & *b) {
return 1;
}
}
return 0;
}
\n";
$types.="\nCREATE FUNCTION $typename"."_out ($typename)
RETURNS cstring
AS '$libtypename'
LANGUAGE 'c';\n";
$types.="\nCREATE TYPE $typename (
internallength = $internalsize,
input = $typename\_in,
output = $typename\_out
);\n";
$types.="\nCREATE FUNCTION $typename"."_eq ($typename,$typename)
RETURNS bool
AS '$libtypename'
LANGUAGE 'c';
CREATE FUNCTION find_in_set ($typename,$typename)
RETURNS bool
AS '$libtypename'
LANGUAGE 'c';
CREATE OPERATOR = (
leftarg = $typename,
rightarg = $typename,
commutator = =,
procedure = $typename"."_eq
);
CREATE OPERATOR <> (
leftarg = $typename,
rightarg = $typename,
commutator = <>,
negator = =,
procedure = $typename"."_eq
);
\n";
print LIBTYPES $func_in;
print LIBTYPES $func_out;
s/set\(.*?\)/$typename/i;
}
# Change multy-field keys to multi-field indices
# MySQL Dump usually ends the CREATE TABLE statement like this:
# CREATE TABLE bids (
# ...
# PRIMARY KEY (bids_id),
# KEY offer_id (offer_id,user_id,the_time),
# KEY bid_value (bid_value)
# );
# We want to replace this with smth like
# CREATE TABLE bids (
# ...
# PRIMARY KEY (bids_id),
# );
# CREATE INDEX offer_id ON bids (offer_id,user_id,the_time);
# CREATE INDEX bid_value ON bids (bid_value);
if (s/CREATE TABLE (.*) /CREATE TABLE $dq$1$dq /i) {
if($oldtable ne $table_name) {
$oldtable=$table_name;
$j=-1;
$check='';
if($seq{$table_name} ne '') {
print "\n\n--";
print "\n-- Sequences for table ".uc($table_name);
print "\n--\n";
print "\nCREATE SEQUENCE ".$seq{$table_name}.";\n\n";
}
print $types;
$types='';
$dump=~s/,\n\).*;/\n\);/gmi;
# removing table options after closing bracket:
# ) TYPE=ISAM PACK_KEYS=1;
$dump=~s/\n\).*/\n\);/gmi;
print $dump;
$dump='';
}
$table_name=$1;
}
# output CHECK constraints instead UNSIGNED modifiers
if(/PRIMARY KEY\s+\((.*)\)/i) {
my $tmpfld=$1;
$tmpfld=~s/,/","/g if $dq;
$tmpfld=~s/ //g;
s/PRIMARY KEY\s+(\(.*\))/PRIMARY KEY \($dq$tmpfld$dq\)/i;
s/(PRIMARY KEY \(.*\)).*/$1$check\n/i;
}
if(/^\s*KEY ([\w\d_]+)\s*\((.*)\).*/i) {
my $tmpfld=$2; my $ky=$1;
$tmpfld=~s/\s*,\s*/","/g if $dq;
$tmpfld=~s/(\(\d+\))//g;
$index{$table_name}[++$j]="CREATE INDEX ${ky}_$table_name\_index ON $dq$table_name$dq ($dq$tmpfld$dq);";
}
if(/^\s*UNIQUE.*?([\w\d_]+)\s*\((.*)\).*/i) {
my $tmpfld=$2; my $ky=$1;
$tmpfld=~s/,/","/g if $dq;
$tmpfld=~s/(\(\d+\))//g;
$index{$table_name}[++$j]="CREATE UNIQUE INDEX ${ky}_$table_name\_index ON $dq$table_name$dq ($dq$tmpfld$dq);";
}
s/^\s*UNIQUE (.+).*(\(.*\)).*\n//i;
s/^\s*KEY (.+).*(\(.*\)).*\n//i;
if($dq && !/^\s*(PRIMARY KEY|UNIQUE |KEY |CREATE TABLE|INSERT INTO|\);)/i) {
s/\s([A-Za-z_\d]+)\s/ $dq$+$dq /;
}
} # end of if($tabledef)
s/INSERT INTO\s+?(.*?)\s+?/INSERT INTO $dq$1$dq /i;
# if not defined -s command-line option (safe data conversion),
# attempting to convert timestamp data
if(!$safe_data_conv) {
# Fix timestamps
s/'0000-00-00/'0001-01-01/g;
# may corrupt data !!!
s/([,(])00000000000000(?=[,)])/$1'00010101 000000'/g;
if(/[,(]\d{4}(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})[,)]/ &&
$1>=0 && $1<=12 && $2>=0 && $2<=31 && $3>=0 && $3<=23 &&
$4>=0 && $4<=59 && $5>=0 && $5<=59) {
s/([,(])(\d{8})(\d{6})(?=[,)])/$1'$2 $3'/g;
}
if(/[,(]\d{4}(\d{2})(\d{2})[,)]/ &&
$2>=0 && $2<=12 && $3>=0 && $3<=31) {
s/([,(])(\d{4})(\d{2})(\d{2})(?=[,)])/$1'$2-$3-$4 00:00:00'/g;
}
}
$dump.=$_;
}
if($seq{$table_name} ne '') {
print "\n\n--";
print "\n-- Sequences for table ".uc($table_name);
print "\n--\n";
print "\nCREATE SEQUENCE ".$seq{$table_name}.";\n\n";
}
print $types;
$dump=~s/,\n\).*;/\n\);/gmi;
$dump=~s/\n\).*/\n\);/gmi;
print $dump;
# Output indices for tables
while(my($table,$ind)=each(%index)) {
print "\n\n--";
print "\n-- Indexes for table ".uc($table);
print "\n--\n";
for(my $i=0;$i<=$#{$ind};$i++) {
print "\n$ind->[$i]";
}
}
while(my($table,$s)=each(%seq)) {
print "\n\n--";
print "\n-- Sequences for table ".uc($table);
print "\n--\n";
# setting SERIAL sequence values right
if($primary{$table} ne '') {
print "\nSELECT SETVAL('".$seq{$table}."',(select case when max($dq".$primary{$table}."$dq)>0 then max($dq".$primary{$table}."$dq)+1 else 1 end from $dq$table$dq));";
}
}
print("\n\nCOMMIT;\n");
close(LIBTYPES);
open(MAKE,">Makefile");
print MAKE "#
# My2Pg \$Revision: 1.13 $ \translated dump
# Makefile
#
all: libtypes.so
libtypes.o: libtypes.c
gcc -c -fPIC -g -O libtypes.c
libtypes.so: libtypes.o
ld -Bshareable -o libtypes.so libtypes.o";
close(MAKE);
#
# Function generates unique identifier
# Args : template name, max length
# Globals: %identifier
#
sub new_name() {
my $name=lc(shift @_);
my $len=shift @_;
# truncate long names
if(length($name)>$len) {
$name=~s/(.{$len}).*/$1/i;
}
# find reserved identifiers
if($identifier{$name}!=1) {
$identifier{$name}=1;
return $name;
}
else {
for(my $i=1,my $tmpname=$name.$i;$identifier{$tmpname}!=1;) {
$tmpname=$name.$i
}
$identifier{$tmpname}=1;
return $tmpname;
}
die "Error during unique identifier generation :-(";
}
sub usage() {
print <<EOF
my2pg - MySQL to PostgreSQL database dump converter
Copyright (c) 2000-2002 Max Rudensky <fonin\@ziet.zhitomir.ua>
Copyright (c) 2000 Valentine Danilchuk <valdan\@ziet.zhitomir.ua>
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
code source for license details.
SYNTAX:
my2pg [-hnds]
OPTIONS:
h - this help
n - convert *CHAR NOT NULL DEFAULT '' types to *CHAR NULL
d - double quotes around table and column names
s - do not attempt to convert data (timestamps at the moment)
EOF
;
}
=head1 NAME
my2pg - MySQL -> PostgreSQL dump conversion utility.
=head1 SYNTAX
mysqldump db | ./my2pg.pl [-nds] > pgsqldump.sql
vi libtypes.c
make
psql database < pgsqldump.txt
where
=over 4
=item F<pgsqldump.sql>
- file suitable for loading into PostgreSQL.
=item F<libtypes.c>
- C source for emulated MySQL types (ENUM, SET) generated by B<my2pg>
=back
=head1 OVERVIEW
B<my2pg> utility attempts to convert MySQL database dump to Postgres's one.
B<my2pg> performs such conversions:
=over 4
=item * Type conversion.
It tries to find proper Postgres
type for each column.
Unknown types are silently pushing to output dump;
ENUM and SET types implemented via user types
(C source for such types can be found in
B<libtypes.c> file);
=item * Encloses identifiers into double quotes.
All column and table
names should be enclosed to double-quotes to prevent
conflict with reserved SQL keywords;
=item * Converting
AUTO_INCREMENT fields to SERIAL. Actually, creating the sequence and
setting default value to nextval('seq'), well, you know :)
=item * Converting
KEY(field) to CREATE INDEX i_field on table (field);
=item * The same
for UNIQUE keys;
=item * Indices
are creating AFTER rows insertion (to speed up the load);
=item * Translates '#'
MySQL comments to ANSI SQL '--'
=back
It encloses dump in transaction block to prevent single errors
during data load.
=head1 COMMAND-LINE OPTIONS
My2pg takes the following command-line options:
=over 2
=item -n
Convert *CHAR DEFAULT '' NOT NULL types to *CHAR NULL.
Postgres can't load empty '' strings in NOT NULL fields.
=item -d
Add double quotes around table and column names
=item -h
Show usage banner.
=item -s
Do not attempt to convert data. Currently my2pg only tries to convert
date and time data.
=back
=head1 SIDE EFFECTS
=over 4
=item * creates
file B<libtypes.c> in current directory
overwriting existed file without any checks;
=item * the same
for Makefile.
=back
=head1 BUGS
Known bugs are:
=over 4
=item * Possible problems with the timestamp data.
PostgreSQL does not accept incorrect date/time values like B<2002-00-15>,
while MySQL does not care about that. Currently my2pg cannot handle this
issue. You should care yourself to convert such a data.
=item * Use -s option if your numeric data are broken during conversion.
My2pg attempts to convert MySQL timestamps of the form B<yyyymmdd> to
B<yyyy-mm-dd> and B<yyyymmddhhmmss> to B<yyyy-mm-dd hh:mm:ss>. It performs
some heuristic checks to ensure that the month,day,hour,minutes and seconds have
values from the correct range (0..12, 0..31, 0..23, 0..59, 0..59 respectively).
It is still possible that your numeric values that satisfy these conditions
will get broken.
=item * Possible problems with enclosing identifiers in double quotes.
All identifiers such as table and column names should be enclosed in double
quotes. Program can't handle upper-case identifiers,
like DBA. Lower-case identifiers are OK.
=item * SET type emulation is not full. LIKE operation on
SETs, raw integer input values should be implemented
=item * B<Makefile>
generated during output is
platform-dependent and surely works only on
Linux/gcc (FreeBSD/gcc probably works as well - not tested)
=item * Generated B<libtypes.c> contain line
#include <postgres.h>
This file may be located not in standard compiler
include path, you need to check it before compiling.
=back
=head1 AUTHORS
B<(c) 2000-2002 Maxim V. Rudensky (fonin@ziet.zhitomir.ua)> (developer, maintainer)
B<(c) 2000 Valentine V. Danilchuk (valdan@ziet.zhitomir.ua)> (original script)
=head1 CREDITS
Great thanks to all those people who provided feedback and make development
of this tool easier.
Jeff Waugh <jaw@ic.net>
Joakim Lemström <jocke@bytewize.com> || <buddyh19@hotmail.com>
Yunliang Yu <yu@math.duke.edu>
Brad Hilton <bhilton@vpop.net>
If you are not listed here please write to me.
=head1 LICENSE
B<BSD>
=cut
#!/usr/bin/perl
# mysql2pgsql
# Take a MySQL schema dump and turn it into SQL92 and PostgreSQL form.
# Thomas Lockhart, (c) 2000, PostgreSQL Inc.
# Thanks to Tim Perdue at SourceForge.Net for testing and feedback.
#
eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}'
& eval 'exec perl -S $0 $argv:q'
if 0;
use IO::File;
use Getopt::Long;
my $progname = "mysql2pgsql";
my $version = "0.3";
GetOptions("debug!", "verbose!", "version", "path=s", "help", "data!");
my $debug = $opt_debug || 0;
my $verbose = $opt_verbose || 0;
my $pathfrom = $opt_path || "";
my $nodata = (! $opt_data);
$pathfrom = "$pathfrom/" if ($pathfrom =~ /.*[^\/]$/);
print "$0: $progname version $version\n"
if ($opt_version || $opt_help);
print "\t(c) 2000 Thomas Lockhart PostgreSQL Inc.\n"
if ($opt_version && $opt_verbose || $opt_help);
if ($opt_help) {
print "$0 --verbose --version --help --path=dir --nodata infile ...\n";
exit;
}
while (@ARGV) {
my $ostem;
my $oname;
my $pname;
my @xargs;
$iname = shift @ARGV;
$ostem = $iname;
$ostem = $1 if ($ostem =~ /.+\/([^\/]+)$/);
$ostem = $1 if ($ostem =~ /(.+)[.][^.]*$/);
$oname = "$ostem.sql92";
$pname = "$ostem.init";
@xargs = ($iname, $oname);
push @xargs, $pname unless ($nodata);
print "@xargs\n" if ($debug);
TransformDumpFile($iname, $oname, $pname);
}
exit;
sub TransformDumpFile {
local ($iname, $oname, $pname) = @_;
local @dlines;
local @slines;
local @plines;
local @tables; # list of tables created
local %pkeys;
local %pseqs;
local %sequences;
open(IN, "<$iname") || die "Unable to open file $iname";
while (<IN>) {
chomp;
push @dlines, $_;
}
print("Calling CreateSchema with $#dlines lines\n") if ($debug);
@slines = CreateSchema(@dlines);
open(OUT, ">$oname") || die "Unable to open output file $oname";
foreach (@slines) {
print "> $_" if ($debug);
print OUT "$_";
}
close(OUT);
return if (! defined($pname));
@plines = PopulateSchema(@tables);
open(OUT, ">$pname") || die "Unable to open output file $pname";
foreach (@plines) {
print "> $_" if ($debug);
print OUT "$_";
}
close(OUT);
}
sub PopulateSchema {
local @tables = @_;
local @out;
local $pkey;
local $pseq;
foreach (@tables) {
$table = $_;
$tpath = "$pathfrom$table";
print "Table is $table\n" if ($debug);
push @out, "\n";
push @out, "copy $table from '$tpath.txt';\n";
if (defined($pkeys{$table})) {
foreach ($pkeys{$table}) {
$pkey = $_;
$pseq = $pseqs{$table};
print "Key for $table is $pkey on $pseq\n" if ($debug);
# //push @out, "\$value = select max($pkey) from $table;\n";
push @out, "select setval ('$pseq', (select max($pkey) from $table));\n";
}
}
}
return @out;
}
sub CreateSchema {
local @lines = @_;
local @out;
# undef $last;
local %knames;
push @out, "--\n";
push @out, "-- Generated from mysql2pgsql\n";
push @out, "-- (c) 2000, Thomas Lockhart, PostgreSQL Inc.\n";
push @out, "--\n";
push @out, "\n";
while (@lines) {
$_ = shift @lines;
print "< $_\n" if ($debug);
# Replace hash comments with SQL9x standard syntax
$_ = "-- $1" if (/^[\#](.*)/);
# Found a CREATE TABLE statement?
if (/(create\s+table)\s+(\w+)\s+([(])\s*$/i) {
$table = $2;
$table = "\"$1\"" if ($table =~ /^(user)$/);
push @tables, $table;
push @tabledef, "create table $table (";
# push @out, "$_\n";
while (@lines) {
$_ = shift @lines;
print "< $_\n" if ($debug);
# Replace int(11) with SQL9x standard syntax
while (/int\(\d*\)/gi) {
$_ = "$`integer$'";
}
# Replace float(10,2) with SQL9x standard syntax
while (/(float)\((\d+),\s*(\d+)\)/gi) {
$_ = "$`$1($2)$'";
}
# Replace smallinteger with SQL9x syntax
while (/smallinteger/gi) {
$_ = "$`integer$'";
}
# Replace mediumtext with PostgreSQL syntax
while (/(longtext|mediumtext|blob|largeblob)/gi) {
$_ = "$`text$'";
}
# Replace integer ... auto_increment with PostgreSQL syntax
while (/(\s*)(\w+)\s+integer\s+(.*)\s+auto_increment/gi) {
$serid = $table . "_pk_seq";
push @out, "-- serial identifier $serid will likely be truncated\n"
if (length($serid) >= 32);
if (length($serid) >= 32) {
$excess=(length($serid)-31);
$serid = substr($table,0,-($excess)) . "_pk_seq";
push @out, "-- serial identifier $serid was truncated\n";
}
push @out, "CREATE SEQUENCE $serid;\n\n";
$pkeys{$table} = $2;
$pseqs{$table} = $serid;
push @out, "-- key is $pkeys{$table}, sequence is $pseqs{$table}\n" if ($debug);
$_ = "$`$1$2 integer default nextval('$serid') $3$'";
}
# Replace date with double-quoted name
# while (/^(\s*)(date|time)(\s+)/gi) {
# $_ = "$1\"$2\"$3$'";
# }
# Found "KEY"? Then remove it from the CREATE TABLE statement
# and instead write a CREATE INDEX statement.
if (/^\s*key\s+(\w+)\s*[(](\w[()\w\d,\s]*)[)][,]?/i) {
$iname = $1;
$column = $2;
$iname = $1 if ($iname =~ /^idx_(\w[\_\w\d]+)/);
# Sheesh, there can be upper bounds on index string sizes?
# Get rid of the length specifier (e.g. filename(45) -> filename)
while ($column =~ /(\w[\w\d])[(]\d+[)]/g) {
$column = "$`$1$'";
}
# $column = $1 if ($column =~ /(\w+)[(]\d+[)]/);
# push @out, "Index on $table($column) is $iname\n";
if (defined($knames{$iname})) {
push @out, "-- $iname already exists";
# sprintf($iname, "idx_%_%s", $table, $iname);
# $iname = "idx_" . $table . "_" . $column;
# Do not bother with more to the name; it will be too big anyway
$iname = $table . "_" . $column;
push @out, "; use $iname instead\n";
}
$knames{$iname} = $iname;
$keydef{$column} = $iname;
# push @out, "! $_\n";
# $last = $tabledef[$#tabledef];
# push @out, "? $#tabledef $last\n";
# push @out, "match $1\n" if ($last =~ /(.*),\s*$/);
# Remove the trailing comma from the previous line, if necessary
$tabledef[$#tabledef] = $1
if (($#tabledef > 0) && ($tabledef[$#tabledef] =~ /(.*),\s*$/));
# push @out, "? $tabledef[$#tabledef]\n";
# If this is the end of the statement, save it and exit loop
} elsif (/^\s*[)]\;/) {
push @tabledef, $_;
# push @out, "< $_\n";
last;
# Otherwise, just save the line
} else {
# push @out, "$last\n" if (defined($last));
# $last = $_;
push @tabledef, $_;
# push @out, "$_\n";
}
}
foreach $t (@tabledef) {
push @out, "$t\n";
}
undef @tabledef;
foreach $k (keys %keydef) {
push @out, "create index $keydef{$k} on $table ($k);\n";
}
undef %keydef;
} else {
push @out, "$_\n";
}
}
# push @out, "$last\n" if (defined($last));
foreach (keys %pkeys) {
my $val = $pkeys{$_};
print "key is $val\n" if ($debug);
}
return @out;
}
sub StripComma {
local $line = shift @_;
$line = "$1" if ($line =~ /(.*)[,]\s*$/);
return $line;
}
# $PostgreSQL: pgsql/contrib/noupdate/Makefile,v 1.11 2004/08/20 20:13:05 momjian Exp $
MODULES = noup
DATA_built = noup.sql
DOCS = README.noup
ifdef USE_PGXS
PGXS = $(shell pg_config --pgxs)
include $(PGXS)
else
subdir = contrib/noupdate
top_builddir = ../..
include $(top_builddir)/src/Makefile.global
include $(top_srcdir)/contrib/contrib-global.mk
endif
noupdate
~~~~~~~~
- trigger to prevent updates on single columns.
Example:
~~~~~~~
CREATE TABLE TEST ( COL1 INT, COL2 INT, COL3 INT );
CREATE TRIGGER BT BEFORE UPDATE ON TEST FOR EACH ROW
EXECUTE PROCEDURE
noup ('COL1');
-- Now Try
INSERT INTO TEST VALUES (10,20,30);
UPDATE TEST SET COL1 = 5;
/*
* noup.c -- functions to remove update permission from a column
*/
#include "executor/spi.h" /* this is what you need to work with SPI */
#include "commands/trigger.h" /* -"- and triggers */
#include <ctype.h> /* tolower () */
extern Datum noup(PG_FUNCTION_ARGS);
/*
* noup () -- revoke permission on column
*
* Though it's called without args You have to specify referenced
* table/column while creating trigger:
* EXECUTE PROCEDURE noup ('col').
*/
PG_FUNCTION_INFO_V1(noup);
Datum
noup(PG_FUNCTION_ARGS)
{
TriggerData *trigdata = (TriggerData *) fcinfo->context;
Trigger *trigger; /* to get trigger name */
int nargs; /* # of args specified in CREATE TRIGGER */
char **args; /* arguments: column names and table name */
int nkeys; /* # of key columns (= nargs / 2) */
Datum *kvals; /* key values */
Relation rel; /* triggered relation */
HeapTuple tuple = NULL; /* tuple to return */
TupleDesc tupdesc; /* tuple description */
bool isnull; /* to know is some column NULL or not */
int ret;
int i;
/*
* Some checks first...
*/
/* Called by trigger manager ? */
if (!CALLED_AS_TRIGGER(fcinfo))
/* internal error */
elog(ERROR, "noup: not fired by trigger manager");
/* Should be called for ROW trigger */
if (TRIGGER_FIRED_FOR_STATEMENT(trigdata->tg_event))
/* internal error */
elog(ERROR, "noup: can't process STATEMENT events");
/* Should not be called for INSERT */
if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
/* internal error */
elog(ERROR, "noup: can't process INSERT events");
/* Should not be called for DELETE */
else if (TRIGGER_FIRED_BY_DELETE(trigdata->tg_event))
/* internal error */
elog(ERROR, "noup: can't process DELETE events");
/* check new Tuple */
tuple = trigdata->tg_newtuple;
trigger = trigdata->tg_trigger;
nargs = trigger->tgnargs;
args = trigger->tgargs;
nkeys = nargs;
rel = trigdata->tg_relation;
tupdesc = rel->rd_att;
/* Connect to SPI manager */
if ((ret = SPI_connect()) < 0)
/* internal error */
elog(ERROR, "noup: SPI_connect returned %d", ret);
/*
* We use SPI plan preparation feature, so allocate space to place key
* values.
*/
kvals = (Datum *) palloc(nkeys * sizeof(Datum));
/* For each column in key ... */
for (i = 0; i < nkeys; i++)
{
/* get index of column in tuple */
int fnumber = SPI_fnumber(tupdesc, args[i]);
/* Bad guys may give us un-existing column in CREATE TRIGGER */
if (fnumber < 0)
/* internal error */
elog(ERROR, "noup: there is no attribute %s in relation %s",
args[i], SPI_getrelname(rel));
/* Well, get binary (in internal format) value of column */
kvals[i] = SPI_getbinval(tuple, tupdesc, fnumber, &isnull);
/*
* If it's NOT NULL then cancel update
*/
if (!isnull)
{
elog(WARNING, "%s: update not allowed", args[i]);
SPI_finish();
return PointerGetDatum(NULL);
}
}
SPI_finish();
return PointerGetDatum(tuple);
}
-- Adjust this setting to control where the objects get created.
SET search_path = public;
CREATE OR REPLACE FUNCTION noup ()
RETURNS trigger
AS 'MODULE_PATHNAME'
LANGUAGE 'C';
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment