0001 LIBNDRXXAPQ(8)
0002 ==============
0003 :doctype: manpage
0004
0005
0006 NAME
0007 ----
0008 libndrxxapq - Enduro/X PostgreSQL PQ XA Driver
0009
0010
0011 SYNOPSIS
0012 --------
0013 libndrxxapq.so
0014 libndrxxapq.dylib
0015
0016 --------------------------------------------------------------------------------
0017 NDRX_XA_RES_ID=1
0018 NDRX_XA_OPEN_STR={"url":"tcp:postgresql://${EX_PG_HOST}/${EX_PG_DB}"
0019 ,"user":"${EX_PG_USER}"
0020 ,"password":"${EX_PG_PASS}"
0021 ,"compat":"PGSQL|INFORMIX|INFORMIX_SE"
0022 }"
0023 NDRX_XA_CLOSE_STR=$NDRX_XA_OPEN_STR
0024 NDRX_XA_DRIVERLIB=libndrxxapq.so
0025 NDRX_XA_RMLIB=-
0026 NDRX_XA_LAZY_INIT=1
0027 --------------------------------------------------------------------------------
0028
0029 DESCRIPTION
0030 -----------
0031 This is XA driver specifically written Enduro/X needs. It provides an XA switch
0032 emulation on top of PostgreSQL prepared transactions. PostgreSQL by default
0033 does not support XA switch. Also when transaction start, there is no possibility
0034 to identify the work unit performed. The identification of work done by some
0035 process on particular connection can be done by preparing the transaction. Thus
0036 there is no such thing as "active" transaction in terms of XA specification.
0037 Also there is no possibility for other processes to join the existing work and
0038 see work done by other session. Thus for example if one server process in same
0039 transaction performs some insert and other process tries insert on table which
0040 has foreign key to first insert, it will fail, as FK will not be seen. Thus
0041 Enduro/X needs to work on branch-transactions mode without join feature. The
0042 mode of PostgreSQL driver is the same as enabled by *NDRX_XA_FLAG* with value
0043 *NOJOIN*.
0044
0045 The emulation of XA protocol is done by following steps and assumptions:
0046
0047 1. When process joins to global transaction, new branch-transaction-id is
0048 acquired. The TMSRV logs the branch with status 'u'-unknown.
0049
0050 2. When process completes the work unit (server does tpreturn(3) or tpforward(3))
0051 or initiating process performs tpcommit(3), the xa_end() is called which in-turn
0052 runs PostgreSQL "PREPARE TRANSACTION <XID_STR>". "XID_STR" is based on PosgreSQL
0053 JDBC driver format. Thus JDBC version on PQ versions of tmsrv drivers can be mixed.
0054 When transaction is prepared OK, the TMSRV is reported with 'p'-prepared status.
0055 If prepare fails, this means that transaction is aborted by PosgreSQL, and in
0056 this case 'a'-aborted status is reported to TMSRV.
0057
0058 3. When TMSRV tries to commit, and branch is in 'u'-unknown or 'a'-aborted status,
0059 the global transaction is aborted and tpcommit caller receives *TPEABORT* error.
0060 If transaction is in status 'p', the prepare phase of global transaction is
0061 skipped/no operation and then commit is executed.
0062
0063 4. In case if work unit performs too long operation and tries to xa_end() after
0064 when TMSRV is already timed-out/rolled back the global transaction, the xa_end()
0065 status call to TMSRV fails with error *TPEMATCH*. In this case local process
0066 rolls back the prepared transaction.
0067
0068 5. When tpabort is executed, the xa_end() within tpabort() process performs
0069 abort without executing prepare.
0070
0071 The connection details are encoded in JSON based string which contains the
0072 database URL, user name and password.
0073
0074 To get connection handler, used *tpgetconn(3)* function. Which is available
0075 for this driver.
0076
0077 CONNECTION PARAMETERS
0078 ---------------------
0079 *url*::
0080 This is standard PostgreSQL connection URL. Typically it contains database
0081 host, port and database name. The Enduro/X standard environment variable
0082 substitution is used here.
0083
0084 EXTERNAL SYMBOLS
0085 ----------------
0086 *ndrx_G_PG_conname*::
0087 This is connection name currently associated with thread. It is thread is
0088 stored in thread local storage (TLS). Definition is
0089 *__thread char ndrx_G_PG_conname[65]*.
0090
0091 CONFIGURATION EXAMPLE
0092 ---------------------
0093 When starting to use Enduro/X PQ XA Driver, ensure that PosgreSQL LIBPQ
0094 is installed.
0095
0096 The typical configuration is done as a standard Enduro/X XA resource configuration,
0097 which can be set directly in environment variables or in *[@global]* section in
0098 application configuration (e.g. app.ini). This gives example of app.ini configuration.
0099
0100 Sample configuration *app.ini* for CCTAG *DB1_PQ*:
0101
0102 --------------------------------------------------------------------------------
0103
0104 [@global/DB1_PQ]
0105 NDRX_XA_RES_ID=1
0106 NDRX_XA_OPEN_STR={"url":"postgresql://testuser:testuser1@localhost:5432/testdb"}
0107 NDRX_XA_CLOSE_STR=${NDRX_XA_OPEN_STR}
0108 NDRX_XA_DRIVERLIB=libndrxxapq.so
0109 NDRX_XA_RMLIB=-
0110 NDRX_XA_LAZY_INIT=1
0111
0112 --------------------------------------------------------------------------------
0113
0114 Sample configuration of transaction manager in *ndrxconfig.xml* for CCTAG *DB1_PQ*:
0115
0116 --------------------------------------------------------------------------------
0117 <servers>
0118 ...
0119 <server name="tmsrv">
0120 <max>1</max>
0121 <srvid>1650</srvid>
0122 <cctag>DB1_PQ</cctag>
0123 <sysopt>-e /tmp/tmsrv-dom1.log -r -- -t1 -l/tmp</sysopt>
0124 </server>
0125 ...
0126 </servers>
0127 --------------------------------------------------------------------------------
0128
0129 LIBPQ C EXAMPLE
0130 ---------------
0131
0132 This is example of programming database with libpq.
0133
0134 File: test_expq.c
0135 --------------------------------------------------------------------------------
0136 #include <string.h>
0137 #include <stdio.h>
0138 #include <stdlib.h>
0139 #include <atmi.h>
0140 #include <libpq-fe.h>
0141
0142 #define FAIL -1
0143 #define SUCCEED 0
0144
0145 int main(int argc, char** argv)
0146 {
0147 PGconn * conn;
0148 PGresult *res = NULL;
0149 ExecStatusType estat;
0150 int ret = SUCCEED;
0151
0152 /* open connection */
0153 if (EXSUCCEED!=tpopen())
0154 {
0155 fprintf(stderr, "Failed to open: %s\n", tpstrerror(tperrno));
0156 ret = FAIL;
0157 goto out;
0158 }
0159
0160 /* get the connection which was open by tpopen() */
0161 conn = (PGconn *)tpgetconn();
0162
0163 /* create some table... */
0164
0165 res = PQexec(conn, "CREATE TABLE manextest(userid integer UNIQUE NOT NULL);");
0166
0167 estat = PQresultStatus(res);
0168
0169 if (PGRES_COMMAND_OK != estat)
0170 {
0171 char *state = PQresultErrorField(res, PG_DIAG_SQLSTATE);
0172 char *msg = PQresultErrorField(res, PG_DIAG_MESSAGE_PRIMARY);
0173
0174 fprintf(stderr, "Failed to create table: state: [%s]: %s\n", state, msg);
0175
0176 if (0==strcmp(state, "42P07"))
0177 {
0178 fprintf(stderr, "Table already exist - ignore error\n");
0179 }
0180 else
0181 {
0182 ret = FAIL;
0183 goto out;
0184 }
0185 }
0186
0187 /* start transaction */
0188 if (EXSUCCEED!=tpbegin(60, 0))
0189 {
0190 fprintf(stderr, "Failed to begin: %s\n", tpstrerror(tperrno));
0191 ret = FAIL;
0192 goto out;
0193 }
0194
0195
0196 /* insert data */
0197
0198 PQclear(res);
0199
0200 res = PQexec(conn, "insert into manextest(userid) values ((select COALESCE(max(userid), 1)+1 from manextest));");
0201
0202 estat = PQresultStatus(res);
0203
0204 if (PGRES_COMMAND_OK != estat)
0205 {
0206 char *state = PQresultErrorField(res, PG_DIAG_SQLSTATE);
0207 char *msg = PQresultErrorField(res, PG_DIAG_MESSAGE_PRIMARY);
0208
0209 fprintf(stderr, "Failed to create table: state: [%s]: %s\n", state, msg);
0210 ret = FAIL;
0211 goto out;
0212 }
0213
0214 if (SUCCEED!=tpcommit(0))
0215 {
0216 fprintf(stderr, "TESTERROR: Commit OK, must fail!\n");
0217 ret = FAIL;
0218 goto out;
0219 }
0220
0221 out:
0222 if (SUCCEED!=ret)
0223 {
0224 tpabort(0);
0225 }
0226
0227 tpclose();
0228 tpterm();
0229
0230 }
0231
0232 --------------------------------------------------------------------------------
0233
0234 Build the program with:
0235
0236 --------------------------------------------------------------------------------
0237
0238 $ cc test_expq.c -o expqtest -I/usr/include/postgresql -lpq -latmi -lnstd -lubf -lrt
0239
0240 --------------------------------------------------------------------------------
0241
0242 Run and test:
0243
0244 --------------------------------------------------------------------------------
0245
0246 $ ./expqtest
0247 Failed to create table: state: [42P07]: relation "manextest" already exists
0248 Table already exist - ignore error
0249
0250 $ psql -U testuser -d testdb -h localhost
0251
0252 testdb=> select * from manextest;
0253 userid
0254 ========
0255 2
0256 (1 row)
0257
0258 --------------------------------------------------------------------------------
0259
0260 For more unit tests please see 'atmitest/test067_postgres' unit test folder for
0261 PQ source examples and configuration.
0262
0263 BUGS
0264 ----
0265 Report bugs to support@mavimax.com
0266
0267 SEE ALSO
0268 --------
0269 *libndrxxaecpg(8)* *ndrxconfig.xml(5)* *tmsrv(8)* *libndrxxawsmqs(8)* *libndrxxaoras(8)*
0270 *tpgetconn(3)*
0271
0272 COPYING
0273 -------
0274 (C) Mavimax, Ltd
0275