Skip to content

Commit

Permalink
Merge pull request #6 from aanhh/RELEASE_v2.8.0
Browse files Browse the repository at this point in the history
RELEASE v2.8.0
  • Loading branch information
t-hiroshige authored Jan 20, 2023
2 parents ec4f20d + 82c7695 commit 95dca57
Show file tree
Hide file tree
Showing 107 changed files with 114,304 additions and 14,398 deletions.
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MySQL Foreign Data Wrapper for PostgreSQL

Copyright (c) 2011-2021, EnterpriseDB Corporation.
Copyright (c) 2011-2022, EnterpriseDB Corporation.

Permission to use, copy, modify, and distribute this software and its
documentation for any purpose, without fee, and without a written agreement is
Expand Down
6 changes: 3 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
# mysql_fdw/Makefile
#
# Portions Copyright (c) 2012-2014, PostgreSQL Global Development Group
# Portions Copyright (c) 2004-2021, EnterpriseDB Corporation.
# Portions Copyright (c) 2004-2022, EnterpriseDB Corporation.
#

MODULE_big = mysql_fdw
OBJS = connection.o option.o deparse.o mysql_query.o mysql_fdw.o

EXTENSION = mysql_fdw
DATA = mysql_fdw--1.0.sql mysql_fdw--1.0--1.1.sql mysql_fdw--1.1.sql mysql_fdw--1.2.sql
DATA = mysql_fdw--1.0.sql mysql_fdw--1.0--1.1.sql mysql_fdw--1.1.sql mysql_fdw--1.2.sql mysql_fdw--1.3.sql

REGRESS = mysql_fdw server_options connection_validation dml select pushdown selectfunc mysql_fdw_post join_pushdown extra/aggregates
REGRESS = mysql_fdw server_options connection_validation dml select pushdown selectfunc mysql_fdw_post join_pushdown aggregate_pushdown extra/aggregates

MYSQL_CONFIG = mysql_config
PG_CPPFLAGS := $(shell $(MYSQL_CONFIG) --include)
Expand Down
43 changes: 36 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ abs, acos, asin, atan, atan2, ceil, ceiling, cos, cot, degrees, div, exp, floor,
ln, log, log10, mod, pow, power, radians, round, sign, sin, sqrt, tan.
ascii, bit_length, char_length, character_length, concat, concat_ws, left,
length, lower, lpad, ltrim, octet_length, repeat, replace, reverse, right,
rpad, rtrim, position, regexp_replace, substr, substring, trim, upper.
rpad, rtrim, position, substr, substring, trim, upper.
date.
json_build_array, json_build_object.
```
Expand All @@ -136,8 +136,8 @@ conv, crc32, div, log2, rand, truncate.
String:
```
bin, char, elt, export_set, field, find_in_set, format, from_base64, hex, insert,
instr, lcase,locate, make_set, mid, oct, ord, quote, regexp_instr, regexp_like,
regexp_replace, regexp_substr,space, strcmp, substring_index, to_base64, ucase,
instr, lcase,locate, make_set, mid, oct, ord, quote, regexp_like, regexp_instr,
regexp_substr, regexp_replace, space, strcmp, substring_index, to_base64, ucase,
unhex, weight_string.
```
Json:
Expand All @@ -158,7 +158,7 @@ List of unique functions of Mysql with different name and syntax:
- MATCH ... AGAINST ...: `match_against`
Example: SELECT content FROM contents WHERE match_against(content, 'search_keyword','in boolean mode') != 0;
- Prefix name with `mysql_`:
User needs to append prefix with `mysql_` for function name: pi, char, now, current_date, current_time, current_timestamp, extract, localtime, localtimestamp, time, timestamp.
User needs to append prefix with `mysql_` for function name: pi, char, now, format, regexp_like, regexp_instr, regexp_substr, regexp_replace, current_date, current_time, current_timestamp, extract, localtime, localtimestamp, time, timestamp, json_table, json_value.
Example: pi() -> mysql_pi()
- WEIGHT_STRING(str [AS {CHAR|BINARY} (N)]):
Example: SELECT str1 FROM s3 WHERE weight_string(str1, 'CHAR', 3) > 0 AND weight_string(str1, 'BINARY', 5) > 1;
Expand Down Expand Up @@ -201,15 +201,15 @@ SEMI, and ANTI join. This is a performance feature.
- Support discard cached connections to remote servers by using function mysql_fdw_disconnect(), mysql_fdw_disconnect_all().
- Support bulk insert by using batch_size option.
- Whole row reference is implemented by modifying the target list to select all whole row reference members and form new row for the whole row in FDW when interate foreign scan.
- Support returning system attribute (`ctid`, `tableiod`)
- Support returning system attribute (`ctid`, `tableiod`).
- Support ON CONFLICT DO NOTHING.

### Prepared Statement
(Refactoring for `select` queries to use prepared statement)

The `select` queries are now using prepared statements instead of simple
query protocol.


Usage
-----

Expand All @@ -227,6 +227,8 @@ The following parameters can be set on a MySQL foreign server object:
* `reconnect`: Enable or disable automatic reconnection to the
MySQL server if the existing connection is found to have been lost.
Default is `false`.
* `sql_mode`: Set MySQL sql_mode for established connection. Default
is `ANSI_QUOTES`.
* `ssl_key`: The path name of the client private key file.
* `ssl_cert`: The path name of the client public key certificate file.
* `ssl_ca`: The path name of the Certificate Authority (CA) certificate
Expand All @@ -239,6 +241,11 @@ The following parameters can be set on a MySQL foreign server object:
get in each fetch operation. It can be specified for a foreign table or
a foreign server. The option specified on a table overrides an option
specified for the server. The default is `100`.
* `character_set`: The character set to use for MySQL connection. Default
is `auto` which means autodetect based on the operating system setting.
Before the introduction of the character_set option, the character set
was set similar to the PostgreSQL database encoding. To get this older
behavior set the character_set to special value `PGDatabaseEncoding`.

The following parameters can be set on a MySQL foreign table object:

Expand All @@ -254,6 +261,21 @@ The following parameters need to supplied while creating user mapping.
* `username`: Username to use when connecting to MySQL.
* `password`: Password to authenticate to the MySQL server with.

The following parameters can be set on IMPORT FOREIGN SCHEMA command:

* `import_default`: This option controls whether column DEFAULT
expressions are included in the definitions of foreign tables imported
from a foreign server. The default is `false`.
* `import_not_null`: This option controls whether column NOT NULL
constraints are included in the definitions of foreign tables imported
from a foreign server. The default is `true`.
* `import_enum_as_text`: This option can be used to map MySQL ENUM type
to TEXT type in the definitions of foreign tables, otherwise emit a
warning for type to be created. The default is `false`.

The following parameters can be set on a MySQL attribute object:
* `key`: This option specify whether a column is used as primary key.

Examples
--------

Expand Down Expand Up @@ -314,6 +336,13 @@ Limit (cost=10.00..11.00 rows=1 width=36)
Remote query: SELECT `warehouse_id`, `warehouse_name` FROM `db`.`warehouse` WHERE ((`warehouse_name` LIKE BINARY 'TV'))
```

Limitation
------------
- group_concat: multiple arguments cannot combined with aggregate(ORDER BY).
- ANY ARRAY: not support pushdown when operator different =, <> or right operand like sub-query.
- MySQL stores floating-point numbers as approximate and not exact values. Therefore, comparing equality with floating-point numbers may lead to incorrect result.
- From MySQL version 8.0.31, if we insert 'infinity' and then select var_pop of it, MySQL FDW returns out of range error.

Contributing
------------
Opening issues and pull requests on GitHub are welcome.
Expand All @@ -322,7 +351,7 @@ License
-------
Copyright (c) 2021, TOSHIBA Corporation.

Copyright (c) 2011-2021, EnterpriseDB Corporation.
Copyright (c) 2011-2022, EnterpriseDB Corporation.

Permission to use, copy, modify, and distribute this software and its
documentation for any purpose, without fee, and without a written
Expand Down
110 changes: 82 additions & 28 deletions connection.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* Connection management functions for mysql_fdw
*
* Portions Copyright (c) 2012-2014, PostgreSQL Global Development Group
* Portions Copyright (c) 2004-2021, EnterpriseDB Corporation.
* Portions Copyright (c) 2004-2022, EnterpriseDB Corporation.
*
* IDENTIFICATION
* connection.c
Expand All @@ -14,10 +14,10 @@

#include "postgres.h"

#include <errmsg.h>
#if PG_VERSION_NUM >= 130000
#include "common/hashfn.h"
#endif
#include "mb/pg_wchar.h"
#include "mysql_fdw.h"
#include "utils/hsearch.h"
#include "utils/inval.h"
Expand Down Expand Up @@ -69,15 +69,16 @@ typedef struct ConnCacheEntry
static HTAB *ConnectionHash = NULL;

/* tracks whether any work is needed in callback functions */
static bool xact_got_connection = false;
static volatile bool xact_got_connection = false;

static void mysql_inval_callback(Datum arg, int cacheid, uint32 hashvalue);
static void mysql_do_sql_command(MYSQL * conn, const char *sql, int level);
static void mysql_begin_remote_xact(ConnCacheEntry *entry);
static void mysql_xact_callback(XactEvent event, void *arg);
static void mysql_reset_xact_state(ConnCacheEntry *entry, bool toplevel);
static void mysql_subxact_callback(SubXactEvent event, SubTransactionId mySubid,
SubTransactionId parentSubid, void *arg);

static void mysql_fdw_abort_cleanup(ConnCacheEntry *entry, bool toplevel);
/*
* SQL functions
*/
Expand Down Expand Up @@ -366,7 +367,7 @@ mysql_connect(mysql_opt * opt)
(errcode(ERRCODE_FDW_OUT_OF_MEMORY),
errmsg("failed to initialise the MySQL connection object")));

mysql_options(conn, MYSQL_SET_CHARSET_NAME, GetDatabaseEncodingName());
mysql_options(conn, MYSQL_SET_CHARSET_NAME, opt->character_set);
#if MYSQL_VERSION_ID < 80000
mysql_options(conn, MYSQL_SECURE_AUTH, &secure_auth);
#endif
Expand Down Expand Up @@ -566,24 +567,14 @@ mysql_xact_callback(XactEvent event, void *arg)
case XACT_EVENT_PARALLEL_ABORT:
case XACT_EVENT_ABORT:
{
elog(DEBUG3, "mysql_fdw abort transaction");

/*
* rollback if in transaction
*/
mysql_do_sql_command(entry->conn, "ROLLBACK", WARNING);
mysql_fdw_abort_cleanup(entry, true);
break;
}
}
}

/* Reset state to show we're out of a transaction */
entry->xact_depth = 0;
if (entry->invalidated || !entry->keep_connections)
{
elog(DEBUG3, "mysql_fdw discarding connection %p", entry->conn);
disconnect_mysql_server(entry);
}
mysql_reset_xact_state(entry, true);
}

/*
Expand All @@ -593,6 +584,29 @@ mysql_xact_callback(XactEvent event, void *arg)
xact_got_connection = false;
}

/*
* mysql_reset_xact_state --- Reset state to show we're out of a (sub)transaction.
*/
static void
mysql_reset_xact_state(ConnCacheEntry *entry, bool toplevel)
{
if (toplevel)
{
/* Reset state to show we're out of a transaction */
entry->xact_depth = 0;
if (entry->invalidated || !entry->keep_connections)
{
elog(DEBUG3, "mysql_fdw discarding connection %p", entry->conn);
disconnect_mysql_server(entry);
}
}
else
{
/* Reset state to show we're out of a subtransaction */
entry->xact_depth--;
}
}

/*
* mysql_subxact_callback --- cleanup at subtransaction end.
*/
Expand Down Expand Up @@ -650,18 +664,44 @@ mysql_subxact_callback(SubXactEvent event, SubTransactionId mySubid,
else
{
/* Rollback all remote subtransactions during abort */
snprintf(sql, sizeof(sql),
"ROLLBACK TO SAVEPOINT s%d",
curlevel);
mysql_do_sql_command(entry->conn, sql, ERROR);
snprintf(sql, sizeof(sql),
"RELEASE SAVEPOINT s%d",
curlevel);
mysql_do_sql_command(entry->conn, sql, ERROR);
mysql_fdw_abort_cleanup(entry, false);
}

/* OK, we're outta that level of subtransaction */
entry->xact_depth--;
mysql_reset_xact_state(entry, false);
}
}

/*
* Abort remote transaction or subtransaction.
*
* "toplevel" should be set to true if toplevel (main) transaction is
* rollbacked, false otherwise.
*/
static void
mysql_fdw_abort_cleanup(ConnCacheEntry *entry, bool toplevel)
{
if (toplevel)
{
elog(DEBUG3, "mysql_fdw abort transaction");
/*
* rollback if in transaction
*/
mysql_do_sql_command(entry->conn, "ROLLBACK", WARNING);
}
else
{
char sql[100];
int curlevel = GetCurrentTransactionNestLevel();

snprintf(sql, sizeof(sql),
"ROLLBACK TO SAVEPOINT s%d",
curlevel);
mysql_do_sql_command(entry->conn, sql, ERROR);
snprintf(sql, sizeof(sql),
"RELEASE SAVEPOINT s%d",
curlevel);
mysql_do_sql_command(entry->conn, sql, ERROR);
}
}

Expand All @@ -684,13 +724,18 @@ mysql_fdw_get_connections(PG_FUNCTION_ARGS)
{
#define MYSQL_FDW_GET_CONNECTIONS_COLS 2
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
HASH_SEQ_STATUS scan;
ConnCacheEntry *entry;
#if PG_VERSION_NUM < 150000
TupleDesc tupdesc;
Tuplestorestate *tupstore;
MemoryContext per_query_ctx;
MemoryContext oldcontext;
HASH_SEQ_STATUS scan;
ConnCacheEntry *entry;
#endif

#if PG_VERSION_NUM >= 150000
SetSingleFuncCall(fcinfo, 0);
#else
/* check to see if caller supports us returning a tuplestore */
if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
ereport(ERROR,
Expand All @@ -715,12 +760,15 @@ mysql_fdw_get_connections(PG_FUNCTION_ARGS)
rsinfo->setDesc = tupdesc;

MemoryContextSwitchTo(oldcontext);
#endif

/* If cache doesn't exist, we return no records */
if (!ConnectionHash)
{
#if PG_VERSION_NUM < 150000
/* clean up and return the tuplestore */
tuplestore_donestoring(tupstore);
#endif

PG_RETURN_VOID();
}
Expand Down Expand Up @@ -785,11 +833,17 @@ mysql_fdw_get_connections(PG_FUNCTION_ARGS)

values[1] = BoolGetDatum(!entry->invalidated);

#if PG_VERSION_NUM >= 150000
tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
#else
tuplestore_putvalues(tupstore, tupdesc, values, nulls);
#endif
}

#if PG_VERSION_NUM < 150000
/* clean up and return the tuplestore */
tuplestore_donestoring(tupstore);
#endif

PG_RETURN_VOID();
}
Expand Down
Loading

0 comments on commit 95dca57

Please sign in to comment.