RPostgreSQL/0000755000176000001440000000000012124527403012427 5ustar ripleyusersRPostgreSQL/MD50000644000176000001440000002720712124527403012747 0ustar ripleyusers3f7fa2f8347ec616473e2918c825c4a8 *ChangeLog bf3109a70c05f48325af4218823659cd *DESCRIPTION c8af6d9e6bc5bf68e12a361ef92d8ed2 *LICENSE 07abd6526506cad69dacbcd85056df39 *NAMESPACE 2d9f70685a274782a6294593052b35c9 *R/PostgreSQL.R b56915fa57c40d3e4f0af3e59dc7b493 *R/PostgreSQLSupport.R f1e33290ef23cbc9449f04fcbce86312 *R/S4R.R ae8e0a406bd6a67e42a78955c7f52bb7 *R/dbObjectId.R c2656a583e3cdce783d45843fcff2dbf *R/zzz.R 4b5e59c53d38086590d8d8553853ab04 *cleanup cd97f90bb8f96381bc90618f20f92e37 *config.guess 1909cacd8bdd9e8b01df53649a497e74 *config.sub 8afc018fc84088e30a20cd7c3cd54207 *configure 59610639849c0de238bd133cbffd7ade *configure.in d41d8cd98f00b204e9800998ecf8427e *configure.win 530c860675440e6e1b7266ad2515b6c1 *inst/ANNOUNCEMENT d01dfae1ce37b71f11a83b4c73199d9e *inst/NEWS 86063092fe732dcbc47a4830ca72703c *inst/README b73cbf6aae0e4d6ece79307f8a86713f *inst/THANKS 0bf2e533fb61584e1944dcdf68614083 *inst/TODO 4d641c77d10b666e344bba4f2fafaa7c *inst/devTests/PostgreSQLDataTypeTest.r 9d52c4bf4d849a301af44570c89fce02 *inst/devTests/copyTest.sh 61641de7231675096668d2800bfd6c57 *inst/devTests/datetime.r b42cfbf562a28612beb8acfe0f716c61 *inst/devTests/demo.r 0cda913b0e5e9141de5ee02ce25bff4d *inst/devTests/timeTypeComparison.r 5c86f87f1eb660bf799f2a6e49e75175 *inst/devTests/transactionManagement.r cb8f0f0ce13da24f66f2ac2422cdbc01 *inst/devTests/typeTest.r 2f879f8f4c271f8c1379203ef6cff430 *inst/doc/DBI.pdf d41d8cd98f00b204e9800998ecf8427e *install-sh 3189110650497edadc574cf9deda2e7a *man/PostgreSQL.Rd 34be8b01589cc63c1e2c14fc923a0296 *man/PostgreSQLConnection-class.Rd 0c1f3f1574eb65bb535771cdf1445264 *man/PostgreSQLDriver-class.Rd e8f24a49034c617587474bd9184f4c28 *man/PostgreSQLObject-class.Rd fb8d66f2760e85ca9feb85e662b82d4b *man/PostgreSQLResult-class.Rd 78a38a9a8bcbb702d481059eac7a0bc9 *man/S4R.Rd d541cbaa9168c4d82b0d7e1e0288de9a *man/dbApply-methods.Rd 03b366bccc90c81553c337f03b174e18 *man/dbApply.Rd e8793fead8804448561a8ef74d1ec9f5 *man/dbCallProc-methods.Rd 7a0abc8f1238eb5cca55526429ddbf1d *man/dbCommit-methods.Rd d586146c693604b9b6fbd5cde0974259 *man/dbConnect-methods.Rd 9d7463dd5c62ad6702dc32ee19e3d6f0 *man/dbDataType-methods.Rd 16246c517381c4a0e74d36ffbc2aceae *man/dbDriver-methods.Rd 5e4129ab26a9e7b0f2fe1aa4f9c9a4f4 *man/dbGetInfo-methods.Rd 063fdd9be6e9440d405ada10da29bf2c *man/dbListTables-methods.Rd e5dcc62d043e378ffdb08cea2843811f *man/dbObjectId-class.Rd 36bafe436524fea4a766cac5ce3c5e4c *man/dbReadTable-methods.Rd 27c949fc943dcd0a41b61b04cc6724c4 *man/dbSendQuery-methods.Rd adbcc9466e503793f67868bad5dd9b41 *man/dbSetDataMappings-methods.Rd 9f49bb52f31cefb5e3bd8f66aecc1a35 *man/fetch-methods.Rd 1d66e31f344b817db3ea90719f14c2b3 *man/isPostgresqlIdCurrent.Rd cf55e6b7dbfc0e553833452c1e56d460 *man/make.db.names-methods.Rd 09e873e5bfb1341f94a0384fe54bd2e8 *man/postgresqlBuildTableDefinition.Rd efefe77c91468729e7f3f44d2baa9e96 *man/postgresqlDBApply.Rd a8c25b61df8cac8b0f4577119bfb3179 *man/postgresqlSupport.Rd 1fa83980e75922372ce35309a6d37ab7 *man/summary-methods.Rd d6e06acf69eb5a72bba126285917aeab *src/Makevars.in 28b4fca3fd3ae85de4b1d1bb480c0837 *src/Makevars.win 2813421b9a2f7eba64282f49b00bed8e *src/RS-DBI.c 259d16ef0b9e0f8f45a7c8a845744285 *src/RS-DBI.h 36dbad7938bb2d8b33267b7363c8ef09 *src/RS-PQescape.c 153c3a456e21502b44c3ef36ff6e5d93 *src/RS-PostgreSQL.c a097d25581003eb54dba6f63338e0ad4 *src/RS-PostgreSQL.h 9df3f59ddf2ae1c959651a25ff8377b3 *src/RS-pgsql-copy.c ad6938746ab4aed7cd921cf7aa185620 *src/RS-pgsql-getResult.c 3029b173216fd1941bc6c9d4fbbd3249 *src/RS-pgsql-pqexec.c b94b0a6e17f9c149155f7797bd093fd7 *src/RS-pgsql-pqexecparams.c 25f7757eb3ce49bd5c0faf5d38995a84 *src/S4R.h ef344a9f1740fa86ca1465e306fc30bf *src/libpq/COPYRIGHT 70210c09c015458c661a500f794d90cd *src/libpq/Makefile.darwin ad0f605aa54b56a24bad2eaff5f9e770 *src/libpq/Makefile.global.darwin 68fccef5a928cb81f1ac95bc34d722f2 *src/libpq/Makefile.global.win32 5383f13063f1577be46ad2ffc0a4de93 *src/libpq/Makefile.global.win64 27f3f61b48248452f421f708fcc383ca *src/libpq/Makefile.port cd612b52f4c8225182a8dbd899de2b18 *src/libpq/Makefile.port.darwin 41b44e9dffa16c318c046aaa40132309 *src/libpq/Makefile.shlib 11674cf44e470a958990dbf33e7b2d21 *src/libpq/Makefile.win 92c6d2478320dcb7596b189e1404f462 *src/libpq/README 81fa40bc86309f5f19a5173a0691fc0e *src/libpq/bcc32.mak f6603683fd65a79d90fe3e5036416d98 *src/libpq/blibpqdll.def 7e3d6085467e76c82e87bdea1d207cfa *src/libpq/c.h 8c1864c274b66b0b9ee86360bc69cc40 *src/libpq/chklocale.c a136bad0db3049adfdb6427e5a71e003 *src/libpq/crypt.c 5b01b0fceaff0e0744dda81db4a557e2 *src/libpq/encnames.c 18eb6554589f4b28308ec33e04b11fc0 *src/libpq/exports.txt caed6c7c7ca3bba344a6651fb530614e *src/libpq/fe-auth.c 0980f2f606a489c7cf628664e461535f *src/libpq/fe-auth.h 6d33f07c44e05a2acfa54b777aa919bb *src/libpq/fe-connect.c 18f794fca077daa4e13b155279a3b7f1 *src/libpq/fe-exec.c 9d8420fcd4daf54a38fa49fd2a82e5a2 *src/libpq/fe-lobj.c 8b30c827e58ac1cc6b9af8f5bcf8078d *src/libpq/fe-misc.c b6912e592c3cd685ff215a02b5c5c57c *src/libpq/fe-print.c ca4db5c3bed90289825dc97c1645089f *src/libpq/fe-protocol2.c 8002a285b31897f9ab2140a8f33e9809 *src/libpq/fe-protocol3.c b42de4a87499436f38f4dc990f08d2b7 *src/libpq/fe-secure.c 35e68a9b154334d7d8c21e5226191f46 *src/libpq/getaddrinfo.c 76855922e8fd0f21cc447dde44a0049a *src/libpq/getaddrinfo.h 320944de061a55634f09b43d114fde9f *src/libpq/inet_aton.c 432749fd6aec100b5f505eedc59b77d8 *src/libpq/inet_net_ntop.c 30a26446249c4d896e21bc296154caa4 *src/libpq/ip.c d360c0096fea3d40a9e30d301e75e2d6 *src/libpq/libpq-dist.rc 8ce61fe52cabb3b5e207b94f18c9f69b *src/libpq/libpq-events.c 4e034f61abfbcb0b2b406a06ebf82c92 *src/libpq/libpq-events.h f0916ce17f26a197442fcc362a2a8266 *src/libpq/libpq-fe.h e5088316cb91185f60e0966cf1746ef8 *src/libpq/libpq-int.h 006be1656b963c89f42e9e319a9508c5 *src/libpq/libpq.rc 33f08f69c00a2d521283846ba13805f5 *src/libpq/libpq.rc.in b778fffcc85a1a1d117e10b0e1bf5672 *src/libpq/libpq/auth.h ab3602b78db70993aa5328580a3c6d05 *src/libpq/libpq/be-fsstubs.h 6c80e679af9b1aeec19a6b76b0821158 *src/libpq/libpq/crypt.h 459c24cca99e57c8826f00db6536ac78 *src/libpq/libpq/hba.h df0b12651bba2e39be079a05820b5c65 *src/libpq/libpq/ip.h 9105345fb512b8ca3f4c72cf9d2212af *src/libpq/libpq/libpq-be.h 9fb5ec06a5add40ea44285bbeb7f9ae8 *src/libpq/libpq/libpq-fs.h 1b62b74134a923abcb1a0cb308604676 *src/libpq/libpq/libpq.h dae625c0859abe055affa9c6ea36bb30 *src/libpq/libpq/md5.h f462f30f5e2ccd9ea96cf0286a90128a *src/libpq/libpq/pqcomm.h 9dc4fff9d646f11b72fdc61a33761cb3 *src/libpq/libpq/pqformat.h df5e18f46a6386c191caf8314b2b8ccf *src/libpq/libpq/pqsignal.h c544bf6c9ee787e0fbf5ca281f19b3c9 *src/libpq/libpqddll.def 5dbd31ecc66e578f0975bd09f5893f4f *src/libpq/libpqdll.def a0dac5fc25df3d478c46fcdf859a4a77 *src/libpq/mb/pg_wchar.h 58ea4a0910632af9a7c5bc1bdfbc5119 *src/libpq/md5.c 0f530ef990e31c4d1d8846355b21433d *src/libpq/nls.mk 591fcbd4602ea8aa38d3933a2fd8edc8 *src/libpq/noblock.c 53c7cba0a18f270cb27ca5cd0a8fe39a *src/libpq/open.c 2ee708f79f469f49d70e9f32f114f8ee *src/libpq/pg_config.h.darwin a7f14b752cf6cfc80f5805462f097445 *src/libpq/pg_config.h.win 6e87ad70bd75ee52979dbd79dd2757ed *src/libpq/pg_config_manual.h a37d3d0227d5546d364f4364152aea1b *src/libpq/pg_config_os.h.darwin 925f82c05f230d1a1660bb0600cf41f0 *src/libpq/pg_config_os.h.win 5d38f79637e5d954690553ea6c886b81 *src/libpq/pg_config_paths.h.darwin 5d38f79637e5d954690553ea6c886b81 *src/libpq/pg_config_paths.h.win 67dd9d47c05e99220210707dbbe8fe13 *src/libpq/pg_service.conf.sample 2fc8987699670052720f0e50d9aa65b7 *src/libpq/pgsleep.c 1ddedb705fd0c2d3dac3ac4007583795 *src/libpq/pgstrcasecmp.c e7629acdfe627335381defd82d6c6d36 *src/libpq/port.h 49b1a8226c7f0d3c89de874baa26826f *src/libpq/postgres_ext.h 4dcb82bdf25f69dc07545ede7d20b739 *src/libpq/postgres_fe.h 37107eff1c6654ab7286dea62d1870bb *src/libpq/pqexpbuffer.c dce5ee7a0dc21e9e8f9900833862a979 *src/libpq/pqexpbuffer.h 783cd7b7525d6764ad390f6baba56411 *src/libpq/pqsignal.c c6509da073988f5cf798504688442e63 *src/libpq/pqsignal.h c18860b10e49a49e546ac4c081a2bb7c *src/libpq/pthread-win32.c 1508c7669b0ecac16eb52594ce521b03 *src/libpq/pthread-win32.h 9a0df9e44a33b8a4dba5f37c7fbf375b *src/libpq/snprintf.c 074de10a61155a67b9f2414a516e8bbb *src/libpq/strlcpy.c b16f3a73527079d3dbf0470f80c96a3f *src/libpq/thread.c 80097bb3b80795f3a1f79c5569fece88 *src/libpq/wchar.c ae5ff84a1464a71dc36f0030c7c93423 *src/libpq/win32.c 6411c74abfb7e08ff4ea01a680cbb346 *src/libpq/win32.h 19c6c698b953b2ae1a55834df9e9a032 *src/libpq/win32.mak 35c3dfe3358e7534e18549b2d70bfe24 *src/libpq/win32error.c 09c2f2968550edddb77f5a1213f939f5 *src/libpq/win32setlocale.c 4cae11cc0c3bf77885b72b91efbee2fa *src/libpq/wininclude/arpa/inet.h cfed432d1e862194c9d7d4ad3825152c *src/libpq/wininclude/netdb.h 598821c8d2b484bb02ac46b9bd19b6bf *src/libpq/wininclude/netinet/in.h ee8cd495cd23d4dec2eefbdc537f33f4 *src/libpq/wininclude/pwd.h d982865355149572df8b37929da4894a *src/libpq/wininclude/sys/socket.h 328dc7600d5a2acd6b82acc37cb6b7ce *src/libpq/wininclude/sys/wait.h f62197ce4f6f73cf0f62b9c99493d736 *tests/connectWithNull.R bc4feb5f45590b44f80befe2930a8a21 *tests/connectWithNull.Rout.save 3f379b98fb19a5875ee1f50bfaa4401a *tests/createTableMixedCaseTest.R d9adf68fe977b8a2f019d509bed22418 *tests/createTableMixedCaseTest.Rout.save e312e82ea55ce3ae4e334d4a033b7186 *tests/dataTypeTests.R 12ea74767ddf32212282b3638e0331e2 *tests/dataTypeTests.Rout.save a21f53ad7089fb53ab0e99e7a72152ef *tests/dateTZ.R e606772d639a4584fdf627ff9e4bc5a4 *tests/dateTZ.Rout.save 5dd14260ac121755f95804a805845639 *tests/datetimeTests.R 1c26ec805ee49b912b72c1a64fecca4b *tests/datetimeTests.Rout.save 426a085a5107df0ff90abfcbfdc7aa2f *tests/datetimestampwrite.R b0e89adfef654419f9535a4a27a0fb05 *tests/datetimestampwrite.Rout.save 068d06765ebc0b4193679458681f5492 *tests/dbColumnInfo.R cfd0aed69408e4a8dd0e16849fad502c *tests/dbColumnInfo.Rout.save 728c6b4d298bde0a78fa0b6bdba9b6e6 *tests/dbExistsIssue.R 9ec0ad71ef0d45c84f3b577e4e534cfb *tests/dbExistsIssue.Rout.save 84ed5ec8c2418f4f502ccdda3c09f7f9 *tests/dbExistsq.R 3683a308c16552827c0ecfe0f220bc19 *tests/dbExistsq.Rout.save 7cdfa345c748deaa09d12a425dc27274 *tests/dbExistsqc.R dfda2558194715178599544633b91ac3 *tests/dbExistsqc.Rout.save 2452d72357ecbb7644f853277d73ecbc *tests/dbGetQueryParams.R 8c83ee42b8de354904ad510e0f23c976 *tests/dbGetQueryParams.Rout.save 7ede6c5869d6aceaa8e7fdf71d272f0c *tests/dbListFields.R 85b4a7a761329f7e5860426086a2b7ab *tests/dbListFields.Rout.save 780ac2b734047a7e32a2fc7929b2f50e *tests/dbTransactionTests.R 58dfaf1772f7b287f6d2f68b917245d6 *tests/dbTransactionTests.Rout.save 2c6f2e4af6002c96fd9370f6a882fa28 *tests/dbWriteTableFailTest.R fc95e0249d08c8b06c7fd2b3c68177ec *tests/dbWriteTableFailTest.Rout.save 817a51900be6d35839f958f8c03fde3d *tests/dbWriteTableSchema.R 334de98ade8e6371f9d3b527505ee172 *tests/dbWriteTableSchema.Rout.save cce64727d6f71c31443f2bd15a91fda3 *tests/dbWriteTableTest.R 7fc7ebfe4fa48b09ceb13590e81b335e *tests/dbWriteTableTest.Rout.save 4402efb6f7f026dc991e377fe6f16b12 *tests/dbWriteTabletypes.R 73504ebbb74fba62c333e7e2f5dd13c9 *tests/dbWriteTabletypes.Rout.save 2a3b7cc53200dfa695523381227dfeaf *tests/dbtemptable.R c78e8ab0cf63864cf885fe1f6a737239 *tests/dbtemptable.Rout.save 54a3acc43b0214be8b3ecae3197eeb9d *tests/escape.R fbcdd68af9bf187137ed3b3382aff6e9 *tests/escape.Rout.save 580af6ae7d31aa856eb39f9028ecdc78 *tests/loadDriverAndConnect.R 45f20321adb6219f15b462e5e161ca97 *tests/loadDriverAndConnect.Rout.save 1c45b989cd5bb3125fca11bd30d41a97 *tests/openSendQuery.R 8522ca7bcfecc0574099c74488eb8f82 *tests/openSendQuery.Rout.save 2eea86fb5f793df420647561bcddd07c *tests/selectWhereZero.R 417ab0d9cc3cbc6fbe3217f4eb2ab757 *tests/selectWhereZero.Rout.save 2bdcf2cc399042c30814e59107dc1170 *tests/selectWithAlias.R 4de3eac64338973043b7293c196e8e7c *tests/selectWithAlias.Rout.save e2da0d437b3951cfdcd12ff309032764 *tests/unknowntype.R f91af8ad0eeecc03a8bf41428ac790c5 *tests/unknowntype.Rout.save RPostgreSQL/cleanup0000755000176000001440000000017011455242163014005 0ustar ripleyusersrm -f config.log config.status rm -rf autom4te.cache rm -rf src/*.o src/*.so src/Makevars rm -rf .RData typeTest.r.Rout RPostgreSQL/src/0000755000176000001440000000000012124517222013214 5ustar ripleyusersRPostgreSQL/src/RS-pgsql-copy.c0000644000176000001440000002362712124517222016012 0ustar ripleyusers/* * RS-pgsql-copy.c * * $Id: RS-pgsql-copy.c 212 2011-11-22 10:58:50Z tomoakin@kenroku.kanazawa-u.ac.jp $ */ #include "RS-PostgreSQL.h" #include #include /* for Calloc/Free */ #include #include #include #define COPY_IN_BUFSIZE 8192 typedef struct { char *data; size_t bufsize; size_t defaultSize; } R_StringBuffer; /* adapter for PQputCopyData and PQputCopyEnd which is used in conjunction with COPY table from STDIN */ /* * Copies all content of the file specified with filename to the conHandle which * has opened connection previously issued the COPY table from STDIN query * the data is read from file sent to the database with PQputCopyData * in chunks of COPY_IN_BUFSIZE. * The copy ends when 0 byte could be read from the file and then the * PQputCopyEnd is called to complete the copying. */ static inline void chkpqcopydataerr(PGconn *, int); s_object * RS_PostgreSQL_CopyIn(Con_Handle * conHandle, s_object * filename) { S_EVALUATOR RS_DBI_connection * con; PGconn *my_connection; char *dyn_filename; char copybuf[COPY_IN_BUFSIZE]; FILE* filehandle; size_t len; int pqretcode; con = RS_DBI_getConnection(conHandle); my_connection = (PGconn *) con->drvConnection; dyn_filename = RS_DBI_copyString(CHR_EL(filename, 0)); filehandle=fopen(dyn_filename, "r"); if(filehandle == NULL){ char errmsg[1024]; snprintf(errmsg, 1024, "could not open file: %s", dyn_filename); RS_DBI_errorMessage(dyn_filename, RS_DBI_ERROR); return S_NULL_ENTRY; } while((len = fread(copybuf,1,COPY_IN_BUFSIZE, filehandle))){ pqretcode = PQputCopyData(my_connection, copybuf, len); chkpqcopydataerr(my_connection, pqretcode); } PQputCopyEnd(my_connection, NULL); fclose(filehandle); free(dyn_filename); return S_NULL_ENTRY; } void *R_AllocStringBuffer(size_t blen, R_StringBuffer *buf) { size_t blen1, bsize = buf->defaultSize; if(blen < buf->bufsize) return buf->data; blen1 = blen = (blen + 1); blen = (blen / bsize) * bsize; if(blen < blen1) blen += bsize; if(buf->data == NULL) { buf->data = (char *) malloc(blen); buf->data[0] = '\0'; } else buf->data = (char *) realloc(buf->data, blen); buf->bufsize = blen; if(!buf->data) { buf->bufsize = 0; /* don't translate internal error message */ error("could not allocate memory (%u Mb) in C function 'R_AllocStringBuffer'", (unsigned int) blen/1024/1024); } return buf->data; } void R_FreeStringBuffer(R_StringBuffer *buf) { if (buf->data != NULL) { free(buf->data); buf->bufsize = 0; buf->data = NULL; } } static Rboolean isna(SEXP x, int indx) { Rcomplex rc; switch(TYPEOF(x)) { case LGLSXP: return LOGICAL(x)[indx] == NA_LOGICAL; break; case INTSXP: return INTEGER(x)[indx] == NA_INTEGER; break; case REALSXP: return ISNAN(REAL(x)[indx]); break; case STRSXP: return STRING_ELT(x, indx) == NA_STRING; break; case CPLXSXP: rc = COMPLEX(x)[indx]; return ISNAN(rc.r) || ISNAN(rc.i); break; default: break; } return FALSE; } /* a version of EncodeElement with different escaping of char strings */ static const char *EncodeElementS(SEXP x, int indx, R_StringBuffer *buff, char cdec) { switch(TYPEOF(x)) { case STRSXP: { const char *s = translateCharUTF8(STRING_ELT(x, indx)); char *u, *cbuf; int j, len, blen, offset; len = strlen(s); blen = len * 2 + 1; R_AllocStringBuffer(blen, buff); u = cbuf = buff->data; offset = 0; for (j = 0; j < len; j++){ switch(s[offset+j]){ /* http://www.postgresql.org/docs/8.1/static/sql-copy.html */ case '\b': *u++ = '\\'; *u++ = 'b'; break; case '\f': *u++ = '\\'; *u++ = 'f'; break; case '\n': *u++ = '\\'; *u++ = 'n'; break; case '\r': *u++ = '\\'; *u++ = 'r'; break; case '\t': *u++ = '\\'; *u++ = 't'; break; case '\v': *u++ = '\\'; *u++ = 'v'; break; case '\\': *u++ = '\\'; *u++ = '\\'; break; default: *u++ = s[offset+j]; } } *u = '\0'; return buff->data; } case LGLSXP:{ int value; value = LOGICAL(x)[indx]; if(value == TRUE) return "true"; if(value == FALSE) return "false"; return "\\N"; } case INTSXP:{ int value; value = INTEGER(x)[indx]; if(ISNA(value)) return "\\N"; snprintf(buff->data, buff->bufsize, "%d", value); return buff->data; } case REALSXP:{ double value = REAL(x)[indx]; if (!R_FINITE(value)) { if(ISNA(value)) return "\\N"; else if(ISNAN(value)) return "NaN"; else if(value > 0) return "Inf"; else return "-Inf"; } snprintf(buff->data, buff->bufsize, "%.15g", value); return buff->data; } default: return NULL; } return NULL; } static inline void chkpqcopydataerr(PGconn *my_connection, int pqretcode) { if(pqretcode == -1){ char * pqerrmsg = PQerrorMessage(my_connection); char * rserrmsg; char * format = "PQputCopyData failed: %s"; size_t len = strlen(pqerrmsg) + strlen(format) + 1; rserrmsg = malloc(len); if(rserrmsg){ snprintf(rserrmsg, len, format, pqerrmsg); RS_DBI_errorMessage(rserrmsg, RS_DBI_ERROR); }else{ RS_DBI_errorMessage("malloc failed while reporting error in PQputCopyData", RS_DBI_ERROR); } } } SEXP RS_PostgreSQL_CopyInDataframe(Con_Handle * conHandle, SEXP x, SEXP nrow, SEXP ncol) { S_EVALUATOR RS_DBI_connection * con; int nr, nc, i, j; const char *cna ="\\N", *tmp=NULL /* -Wall */; char cdec = '.'; PGconn *my_connection; int pqretcode; nr = asInteger(nrow); nc = asInteger(ncol); const int buff_threshold = 8000; con = RS_DBI_getConnection(conHandle); my_connection = (PGconn *) con->drvConnection; if(isVectorList(x)) { /* A data frame */ R_StringBuffer rstrbuf = {NULL, 0, 10000}; char *strBuf = Calloc(buff_threshold * 2 + 2, char); /* + 2 for '\t' or '\n' plus '\0'*/ char *strendp = strBuf; SEXP *levels; *strendp = '\0'; R_AllocStringBuffer(10000, &rstrbuf); /* handle factors internally, check integrity */ levels = (SEXP *) R_alloc(nc, sizeof(SEXP)); for(j = 0; j < nc; j++) { SEXP xj; xj = VECTOR_ELT(x, j); if(LENGTH(xj) != nr) error(("corrupt data frame -- length of column %d does not not match nrows"), j+1); if(inherits(xj, "factor")) { levels[j] = getAttrib(xj, R_LevelsSymbol); } else levels[j] = R_NilValue; } for(i = 0; i < nr; i++) { for(j = 0; j < nc; j++) { SEXP xj; xj = VECTOR_ELT(x, j); if(j > 0){ *strendp++ = '\t';/*need no size count check here*/ } if(isna(xj, i)) tmp = cna; else { if(!isNull(levels[j])) { /* We cannot assume factors have integer levels */ if(TYPEOF(xj) == INTSXP){ tmp = EncodeElementS(levels[j], INTEGER(xj)[i] - 1, &rstrbuf, cdec); }else if(TYPEOF(xj) == REALSXP){ tmp = EncodeElementS(levels[j], REAL(xj)[i] - 1, &rstrbuf, cdec); }else error("column %s claims to be a factor but does not have numeric codes", j+1); } else { tmp = EncodeElementS(xj, i, &rstrbuf, cdec); } } { size_t n; size_t len = strendp - strBuf; n = strlen(tmp); if (len + n < buff_threshold){ memcpy(strendp, tmp, n);/* we already know the length */ strendp += n; }else if(n < buff_threshold){ /*copy and flush*/ memcpy(strendp, tmp, n);/* we already know the length */ pqretcode = PQputCopyData(my_connection, strBuf, len + n); chkpqcopydataerr(my_connection, pqretcode); strendp = strBuf; }else{ /*flush and copy current*/ if(len > 0){ pqretcode = PQputCopyData(my_connection, strBuf, len); chkpqcopydataerr(my_connection, pqretcode); strendp = strBuf; } pqretcode = PQputCopyData(my_connection, tmp, n); chkpqcopydataerr(my_connection, pqretcode); } } } *strendp = '\n'; strendp +=1; *strendp='\0'; } pqretcode = PQputCopyData(my_connection, strBuf, strendp - strBuf); chkpqcopydataerr(my_connection, pqretcode); Free(strBuf); R_FreeStringBuffer(&rstrbuf); } PQputCopyEnd(my_connection, NULL); return R_NilValue; } RPostgreSQL/src/RS-DBI.h0000644000176000001440000002545412124517222014317 0ustar ripleyusers#ifndef _RS_DBI_H #define _RS_DBI_H 1 /* * RS-DBI.h * * $Id: RS-DBI.h 227 2012-02-27 09:58:29Z tomoakin@kenroku.kanazawa-u.ac.jp $ * * This package was developed as a part of Summer of Code program organized by Google. * Thanks to David A. James & Saikat DebRoy, the authors of RMySQL package. * Code from RMySQL package was reused with the permission from the authors. * Also Thanks to my GSoC mentor Dirk Eddelbuettel for helping me in the development. * * Processed with * indent --verbose -br -brs -i4 -nut --line-length120 --comment-line-length120 --leave-preprocessor-space -npcs * */ /* The following include file defines a number of C macros that hide * differences between R and S (e.g., the macro for type "Sint" expand * to "long" in the case of S and to int in the case of R, etc.) */ #ifdef __cplusplus extern "C" { #endif #include "S4R.h" #ifdef WIN32 #include #else #include #endif #include /* NOTE:added this header because of using isalpha in RS-DBI.c -sameer */ // pid_t getpid(); /* We now define 4 important data structures: * RS_DBI_manager, RS_DBI_connection, RS_DBI_resultSet, and * RS_DBI_fields, corresponding to dbManager, dbConnection, * dbResultSet, and list of field descriptions. */ /* In R/S a dbObject is a foreign reference consisting of a vector * of 1, 2 or 3 integers. In the C implementation we use these * R/S vectors as handles (we could have use pointers). */ typedef enum enum_dbi_exception { RS_DBI_MESSAGE, RS_DBI_WARNING, RS_DBI_ERROR, RS_DBI_TERMINATE } DBI_EXCEPTION; /* dbObject handles are simple S/R integer vectors of 1, 2, or 3 integers * the *_ID macros extract the appropriate scalar. */ #define Mgr_Handle s_object #define Con_Handle s_object #define Res_Handle s_object #define Db_Handle s_object /* refers to any one of the above */ /* The integer value for the following enum's needs to equal * GET_LENGTH(handle) for the various handles. */ typedef enum enum_handle_type { MGR_HANDLE_TYPE = 1, /* dbManager handle */ CON_HANDLE_TYPE = 2, /* dbConnection handle */ RES_HANDLE_TYPE = 3 /* dbResult handle */ } HANDLE_TYPE; #define MGR_ID(handle) INT_EL((handle),0) /* the actual scalar mgr id */ #define CON_ID(handle) INT_EL((handle),1) #define RES_ID(handle) INT_EL((handle),2) /* First, the following fully describes the field output by a select * (or select-like) statement, and the mappings from the internal * database types to S classes. This structure contains the info we need * to build the R/S list (or data.frame) that will receive the SQL * output. It still needs some work to handle arbitrty BLOB's (namely * methods to map BLOBs into user-defined S objects). * Each element is an array of num_fields, this flds->Sclass[3] stores * the S class for the 4th output fields. */ typedef struct st_sdbi_fields { int num_fields; char **name; /* DBMS field names */ Sint *type; /* DBMS internal types */ Sint *length; /* DBMS lengths in bytes */ Sint *precision; /* DBMS num of digits for numeric types */ Sint *scale; /* DBMS num of decimals for numeric types */ Sint *nullOk; /* DBMS indicator for DBMS' NULL type */ Sint *isVarLength; /* DBMS variable-length char type */ Stype *Sclass; /* R/S class (type) -- may be overriden */ /* TODO: Need a table of fun pointers to converters */ } RS_DBI_fields; typedef struct st_sdbi_exception { DBI_EXCEPTION exceptionType; /* one of RS_DBI_WARN, RS_RBI_ERROR, etc */ int errorNum; /* SQL error number (possibly driver-dependent */ char *errorMsg; /* SQL error message */ } RS_DBI_exception; /* The RS-DBI resultSet consists of a pointer to the actual DBMS * resultSet (e.g., MySQL, Oracle) possibly NULL, plus the fields * defined by the RS-DBI implementation. */ typedef struct st_sdbi_resultset { void *drvResultSet; /* the actual (driver's) cursor/result set */ void *drvData; /* a pointer to driver-specific data */ Sint managerId; /* the 3 *Id's are used for */ Sint connectionId; /* validating stuff coming from S */ Sint resultSetId; Sint isSelect; /* boolean for testing SELECTs */ char *statement; /* SQL statement */ Sint rowsAffected; /* used by non-SELECT statements */ Sint rowCount; /* rows fetched so far (SELECT-types) */ Sint completed; /* have we fetched all rows? */ RS_DBI_fields *fields; } RS_DBI_resultSet; /* A dbConnection consists of a pointer to the actual implementation * (MySQL, Oracle, etc.) connection plus a resultSet and other * goodies used by the RS-DBI implementation. * The connection parameters (user, password, database name, etc.) are * defined by the actual driver -- we just set aside a void pointer. */ typedef struct st_sdbi_connection { void *conParams; /* pointer to connection params (host, user, etc) */ void *drvConnection; /* pointer to the actual DBMS connection struct */ void *drvData; /* to be used at will by individual drivers */ RS_DBI_resultSet **resultSets; /* vector to result set ptrs */ Sint *resultSetIds; Sint length; /* max num of concurrent resultSets */ Sint num_res; /* num of open resultSets */ Sint counter; /* total number of queries */ Sint managerId; Sint connectionId; RS_DBI_exception *exception; } RS_DBI_connection; /* dbManager */ typedef struct st_sdbi_manager { char *drvName; /* what driver are we implementing? */ void *drvData; /* to be used by the drv implementation */ RS_DBI_connection **connections; /* list of dbConnections */ Sint *connectionIds; /* array of connectionIds */ Sint length; /* max num of concurrent connections */ Sint num_con; /* num of opened connections */ Sint counter; /* num of connections handled so far */ Sint fetch_default_rec; /* default num of records per fetch */ Sint managerId; /* typically, process id */ RS_DBI_exception *exception; } RS_DBI_manager; /* All RS_DBI functions and their signatures */ /* Note: the following alloc functions allocate the space for the * corresponding manager, connection, resultSet; they all * return handles. All DBI functions (free/get/etc) use the handle * to work with the various dbObjects. */ Mgr_Handle *RS_DBI_allocManager(const char *drvName, Sint max_con, Sint fetch_default_rec, Sint force_realloc); void RS_DBI_freeManager(Mgr_Handle * mgrHandle); RS_DBI_manager *RS_DBI_getManager(Db_Handle * handle); Mgr_Handle *RS_DBI_asMgrHandle(Sint pid); s_object *RS_DBI_managerInfo(Mgr_Handle * mgrHandle); /* dbConnection */ Con_Handle *RS_DBI_allocConnection(Mgr_Handle * mgrHandle, Sint max_res); void RS_DBI_freeConnection(Con_Handle * conHandle); RS_DBI_connection *RS_DBI_getConnection(Db_Handle * handle); Con_Handle *RS_DBI_asConHandle(Sint mgrId, Sint conId); s_object *RS_DBI_connectionInfo(Con_Handle * con_Handle); /* dbResultSet */ Res_Handle *RS_DBI_allocResultSet(Con_Handle * conHandle); void RS_DBI_freeResultSet(Res_Handle * rsHandle); RS_DBI_resultSet *RS_DBI_getResultSet(Res_Handle * rsHandle); Res_Handle *RS_DBI_asResHandle(Sint pid, Sint conId, Sint resId); s_object *RS_DBI_resultSetInfo(Res_Handle * rsHandle); /* utility funs */ s_object *RS_DBI_validHandle(Db_Handle * handle); /* callable from S/R */ int is_validHandle(Db_Handle * handle, HANDLE_TYPE handleType); /* a simple object database (mapping table) -- it uses simple linear * search (we don't expect to have more than a handful of simultaneous * connections and/or resultSets. If this is not the case, we could * use a hash table, but I doubt it's worth it (famous last words!). * These are used for storing/retrieving object ids, such as * connection ids from the manager object, and resultSet ids from a * connection object; of course, this is transparent to the various * drivers -- they should deal with handles exclusively. */ Sint RS_DBI_newEntry(Sint * table, Sint length); Sint RS_DBI_lookup(Sint * table, Sint length, Sint obj_id); Sint RS_DBI_listEntries(Sint * table, Sint length, Sint * entries); void RS_DBI_freeEntry(Sint * table, Sint indx); /* description of the fields in a result set */ RS_DBI_fields *RS_DBI_allocFields(int num_fields); s_object *RS_DBI_getFieldDescriptions(RS_DBI_fields * flds); void RS_DBI_freeFields(RS_DBI_fields * flds); /* we (re)allocate the actual output list in here (with the help of * RS_DBI_fields). This should be some kind of R/S "relation" * table, not a dataframe nor a list. */ void RS_DBI_allocOutput(s_object * output, RS_DBI_fields * flds, Sint num_rec, Sint expand); void RS_DBI_makeDataFrame(s_object * data); /* TODO: We need to elevate RS_DBI_errorMessage to either * dbManager and/or dbConnection methods. I still need to * go back and re-code the error-handling throughout, darn! */ void RS_DBI_errorMessage(char *msg, DBI_EXCEPTION exceptionType); void RS_DBI_setException(Db_Handle * handle, DBI_EXCEPTION exceptionType, int errorNum, const char *errorMsg); /* utility funs (copy strings, convert from R/S types to string, etc. */ char *RS_DBI_copyString(const char *str); char *RS_DBI_nCopyString(const char *str, size_t len, int del_blanks); /* We now define a generic data type name-Id mapping struct * and initialize the RS_dataTypeTable[]. Each driver could * define similar table for generating friendly type names */ struct data_types { char *typeName; Sint typeId; }; /* return the primitive type name for a primitive type id */ const char *RS_DBI_getTypeName(Sint typeCode, const struct data_types table[]); /* same, but callable from S/R and vectorized */ s_object *RS_DBI_SclassNames(s_object * types); s_object *RS_DBI_createNamedList(char **names, Stype * types, Sint * lengths, Sint n); s_object *RS_DBI_copyFields(RS_DBI_fields * flds); void RS_na_set(void *ptr, Stype type); int RS_is_na(void *ptr, Stype type); extern const struct data_types RS_dataTypeTable[]; #ifdef __cplusplus } #endif #endif /* _RS_DBI_H */ RPostgreSQL/src/RS-DBI.c0000644000176000001440000011465412124517222014313 0ustar ripleyusers/* * RS-DBI.c * * $Id: RS-DBI.c 245 2012-12-19 13:06:53Z tomoakin@kenroku.kanazawa-u.ac.jp $ * * This package was developed as a part of Summer of Code program organized by Google. * Thanks to David A. James & Saikat DebRoy, the authors of RMySQL package. * Code from RMySQL package was reused with the permission from the authors. * Also Thanks to my GSoC mentor Dirk Eddelbuettel for helping me in the development. * * Source processed by: * indent -br -i4 -nut --line-length120 --comment-line-length120 --leave-preprocessor-space -npcs RS-DBI.c * */ #include "RS-DBI.h" /* TODO: monitor memory/object size consumption against S limits * in $SHOME/include/options.h we find "max_memory". We then * mem_size to make sure we're not bumping into problems. * But, is mem_size() reliable? How should we do this? * * TODO: invoke user-specified generators * * TODO: Implement exception objects for each dbObject. */ static RS_DBI_manager *dbManager = NULL; Mgr_Handle * RS_DBI_allocManager(const char *drvName, Sint max_con, Sint fetch_default_rec, Sint force_realloc) { /* Currently, the dbManager is a singleton (therefore we don't * completly free all the space). Here we alloc space * for the dbManager and return its mgrHandle. force_realloc * means to re-allocate number of connections, etc. (in this case * we require to have all connections closed). (Note that if we * re-allocate, we don't re-set the counter, and thus we make sure * we don't recycle connection Ids in a giver S/R session). */ Mgr_Handle *mgrHandle; RS_DBI_manager *mgr; Sint counter; Sint mgr_id = (Sint) getpid(); int i; PROTECT(mgrHandle = RS_DBI_asMgrHandle(mgr_id)); if (!dbManager) { /* alloc for the first time */ counter = 0; /* connections handled so far */ mgr = (RS_DBI_manager *) malloc(sizeof(RS_DBI_manager)); } else { /* we're re-entering */ if (dbManager->connections) { /* and mgr is valid */ if (!force_realloc) { UNPROTECT(1); return mgrHandle; } else { RS_DBI_freeManager(mgrHandle); /* i.e., free connection arrays */ } } counter = dbManager->counter; mgr = dbManager; } /* Ok, we're here to expand number of connections, etc. */ if (!mgr) { RS_DBI_errorMessage("could not malloc the dbManger", RS_DBI_ERROR); } mgr->drvName = RS_DBI_copyString(drvName); mgr->drvData = (void *) NULL; mgr->managerId = mgr_id; mgr->connections = (RS_DBI_connection **) calloc((size_t) max_con, sizeof(RS_DBI_connection)); if (!mgr->connections) { free(mgr->drvName); free(mgr); RS_DBI_errorMessage("could not calloc RS_DBI_connections", RS_DBI_ERROR); } mgr->connectionIds = (Sint *) calloc((size_t) max_con, sizeof(Sint)); if (!mgr->connectionIds) { free(mgr->drvName); free(mgr->connections); free(mgr); RS_DBI_errorMessage("could not calloc vector of connection Ids", RS_DBI_ERROR); } mgr->counter = counter; mgr->length = max_con; mgr->num_con = (Sint) 0; mgr->fetch_default_rec = fetch_default_rec; for (i = 0; i < max_con; i++) { mgr->connectionIds[i] = -1; mgr->connections[i] = (RS_DBI_connection *) NULL; } dbManager = mgr; UNPROTECT(1); return mgrHandle; } /* We don't want to completely free the dbManager, but rather we * re-initialize all the fields except for mgr->counter to ensure we don't * re-cycle connection ids across R/S DBI sessions in the the same pid * (S/R session). */ void RS_DBI_freeManager(Mgr_Handle * mgrHandle) { RS_DBI_manager *mgr; int i; mgr = RS_DBI_getManager(mgrHandle); if (mgr->num_con > 0) { char *errMsg = "all opened connections were forcebly closed"; RS_DBI_errorMessage(errMsg, RS_DBI_WARNING); } if (mgr->drvData) { char *errMsg = "mgr->drvData was not freed (some memory leaked)"; RS_DBI_errorMessage(errMsg, RS_DBI_WARNING); } if (mgr->drvName) { free(mgr->drvName); mgr->drvName = (char *) NULL; } if (mgr->connections) { for (i = 0; i < mgr->num_con; i++) { if (mgr->connections[i]) { free(mgr->connections[i]); } } free(mgr->connections); mgr->connections = (RS_DBI_connection **) NULL; } if (mgr->connectionIds) { free(mgr->connectionIds); mgr->connectionIds = (Sint *) NULL; } return; } Con_Handle * RS_DBI_allocConnection(Mgr_Handle * mgrHandle, Sint max_res) { RS_DBI_manager *mgr; RS_DBI_connection *con; Con_Handle *conHandle; Sint i, indx, con_id; mgr = RS_DBI_getManager(mgrHandle); indx = RS_DBI_newEntry(mgr->connectionIds, mgr->length); if (indx < 0) { char buf[128], msg[128]; (void) strcat(msg, "cannot allocate a new connection -- maximum of "); (void) strcat(msg, "%d connections already opened"); (void) sprintf(buf, msg, (int) mgr->length); RS_DBI_errorMessage(buf, RS_DBI_ERROR); } con = (RS_DBI_connection *) malloc(sizeof(RS_DBI_connection)); if (!con) { char *errMsg = "could not malloc dbConnection"; RS_DBI_freeEntry(mgr->connectionIds, indx); RS_DBI_errorMessage(errMsg, RS_DBI_ERROR); } con->managerId = MGR_ID(mgrHandle); con_id = mgr->counter; con->connectionId = con_id; con->drvConnection = (void *) NULL; con->drvData = (void *) NULL; /* to be used by the driver in any way */ con->conParams = (void *) NULL; con->counter = (Sint) 0; con->length = max_res; /* length of resultSet vector */ /* result sets for this connection */ con->resultSets = (RS_DBI_resultSet **) calloc((size_t) max_res, sizeof(RS_DBI_resultSet)); if (!con->resultSets) { char *errMsg = "could not calloc resultSets for the dbConnection"; RS_DBI_freeEntry(mgr->connectionIds, indx); free(con); RS_DBI_errorMessage(errMsg, RS_DBI_ERROR); } con->num_res = (Sint) 0; con->resultSetIds = (Sint *) calloc((size_t) max_res, sizeof(Sint)); if (!con->resultSetIds) { char *errMsg = "could not calloc vector of resultSet Ids"; free(con->resultSets); free(con); RS_DBI_freeEntry(mgr->connectionIds, indx); RS_DBI_errorMessage(errMsg, RS_DBI_ERROR); } for (i = 0; i < max_res; i++) { con->resultSets[i] = (RS_DBI_resultSet *) NULL; con->resultSetIds[i] = -1; } /* Finally, update connection table in mgr */ mgr->num_con += (Sint) 1; mgr->counter += (Sint) 1; mgr->connections[indx] = con; mgr->connectionIds[indx] = con_id; conHandle = RS_DBI_asConHandle(MGR_ID(mgrHandle), con_id); return conHandle; } /* the invoking (freeing) function must provide a function for * freeing the conParams, and by setting the (*free_drvConParams)(void *) * pointer. */ void RS_DBI_freeConnection(Con_Handle * conHandle) { RS_DBI_connection *con; RS_DBI_manager *mgr; Sint indx; con = RS_DBI_getConnection(conHandle); mgr = RS_DBI_getManager(conHandle); /* Are there open resultSets? If so, free them first */ if (con->num_res > 0) { char *errMsg = "opened resultSet(s) forcebly closed"; int i; Res_Handle *rsHandle; for (i = 0; i < con->num_res; i++) { rsHandle = RS_DBI_asResHandle(con->managerId, con->connectionId, (Sint) con->resultSetIds[i]); RS_DBI_freeResultSet(rsHandle); } RS_DBI_errorMessage(errMsg, RS_DBI_WARNING); } if (con->drvConnection) { char *errMsg = "internal error in RS_DBI_freeConnection: driver might have left open its connection on the server"; RS_DBI_errorMessage(errMsg, RS_DBI_WARNING); } if (con->conParams) { char *errMsg = "internal error in RS_DBI_freeConnection: non-freed con->conParams (tiny memory leaked)"; RS_DBI_errorMessage(errMsg, RS_DBI_WARNING); } if (con->drvData) { char *errMsg = "internal error in RS_DBI_freeConnection: non-freed con->drvData (some memory leaked)"; RS_DBI_errorMessage(errMsg, RS_DBI_WARNING); } /* delete this connection from manager's connection table */ if (con->resultSets) { free(con->resultSets); } if (con->resultSetIds) { free(con->resultSetIds); } /* update the manager's connection table */ indx = RS_DBI_lookup(mgr->connectionIds, mgr->length, con->connectionId); RS_DBI_freeEntry(mgr->connectionIds, indx); mgr->connections[indx] = (RS_DBI_connection *) NULL; mgr->num_con -= (Sint) 1; free(con); con = (RS_DBI_connection *) NULL; return; } Res_Handle * RS_DBI_allocResultSet(Con_Handle * conHandle) { RS_DBI_connection *con = NULL; RS_DBI_resultSet *result = NULL; Res_Handle *rsHandle; Sint indx, res_id; con = RS_DBI_getConnection(conHandle); indx = RS_DBI_newEntry(con->resultSetIds, con->length); if (indx < 0) { char msg[128], fmt[128]; (void) strcpy(fmt, "cannot allocate a new resultSet -- "); (void) strcat(fmt, "maximum of %d resultSets already reached"); (void) sprintf(msg, fmt, con->length); RS_DBI_errorMessage(msg, RS_DBI_ERROR); } result = (RS_DBI_resultSet *) malloc(sizeof(RS_DBI_resultSet)); if (!result) { char *errMsg = "could not malloc dbResultSet"; RS_DBI_freeEntry(con->resultSetIds, indx); RS_DBI_errorMessage(errMsg, RS_DBI_ERROR); } result->drvResultSet = (void *) NULL; /* driver's own resultSet (cursor) */ result->drvData = (void *) NULL; /* this can be used by driver */ result->statement = (char *) NULL; result->managerId = MGR_ID(conHandle); result->connectionId = CON_ID(conHandle); result->resultSetId = con->counter; result->isSelect = (Sint) - 1; result->rowsAffected = (Sint) - 1; result->rowCount = (Sint) 0; result->completed = (Sint) - 1; result->fields = (RS_DBI_fields *) NULL; /* update connection's resultSet table */ res_id = con->counter; con->num_res += (Sint) 1; con->counter += (Sint) 1; con->resultSets[indx] = result; con->resultSetIds[indx] = res_id; rsHandle = RS_DBI_asResHandle(MGR_ID(conHandle), CON_ID(conHandle), res_id); return rsHandle; } void RS_DBI_freeResultSet(Res_Handle * rsHandle) { RS_DBI_resultSet *result; RS_DBI_connection *con; Sint indx; con = RS_DBI_getConnection(rsHandle); result = RS_DBI_getResultSet(rsHandle); if (result->drvResultSet) { char *errMsg = "internal error in RS_DBI_freeResultSet: non-freed result->drvResultSet (some memory leaked)"; RS_DBI_errorMessage(errMsg, RS_DBI_ERROR); } if (result->drvData) { char *errMsg = "internal error in RS_DBI_freeResultSet: non-freed result->drvData (some memory leaked)"; RS_DBI_errorMessage(errMsg, RS_DBI_WARNING); } if (result->statement) { free(result->statement); } if (result->fields) { RS_DBI_freeFields(result->fields); } free(result); result = (RS_DBI_resultSet *) NULL; /* update connection's resultSet table */ indx = RS_DBI_lookup(con->resultSetIds, con->length, RES_ID(rsHandle)); RS_DBI_freeEntry(con->resultSetIds, indx); con->resultSets[indx] = (RS_DBI_resultSet *) NULL; con->num_res -= (Sint) 1; return; } RS_DBI_fields * RS_DBI_allocFields(int num_fields) { RS_DBI_fields *flds; size_t n; flds = (RS_DBI_fields *) malloc(sizeof(RS_DBI_fields)); if (!flds) { char *errMsg = "could not malloc RS_DBI_fields"; RS_DBI_errorMessage(errMsg, RS_DBI_ERROR); } n = (size_t) num_fields; flds->num_fields = num_fields; flds->name = (char **) calloc(n, sizeof(char *)); flds->type = (Sint *) calloc(n, sizeof(Sint)); flds->length = (Sint *) calloc(n, sizeof(Sint)); flds->precision = (Sint *) calloc(n, sizeof(Sint)); flds->scale = (Sint *) calloc(n, sizeof(Sint)); flds->nullOk = (Sint *) calloc(n, sizeof(Sint)); flds->isVarLength = (Sint *) calloc(n, sizeof(Sint)); flds->Sclass = (Stype *) calloc(n, sizeof(Stype)); return flds; } void RS_DBI_freeFields(RS_DBI_fields * flds) { int i; if (flds->name) { /* (as per Jeff Horner's patch) */ for (i = 0; i < flds->num_fields; i++) { if (flds->name[i]) { free(flds->name[i]); } } free(flds->name); } if (flds->type) { free(flds->type); } if (flds->length) { free(flds->length); } if (flds->precision) { free(flds->precision); } if (flds->scale) { free(flds->scale); } if (flds->nullOk) { free(flds->nullOk); } if (flds->isVarLength) { free(flds->isVarLength); } if (flds->Sclass) { free(flds->Sclass); } free(flds); flds = (RS_DBI_fields *) NULL; return; } /* Make a data.frame from a named list by adding row.names, and class * attribute. Use "1", "2", .. as row.names. * NOTE: Only tested under R (not tested at all under S4 or Splus5+). */ void RS_DBI_makeDataFrame(s_object * data) { S_EVALUATOR s_object *row_names, *df_class_name; #ifndef USING_R s_object *S_RowNamesSymbol; /* mimic Rinternal.h R_RowNamesSymbol */ s_object *S_ClassSymbol; #endif Sint i, n; char buf[1024]; #ifndef USING_R if (IS_LIST(data)) { data = AS_LIST(data); } else { RS_DBI_errorMessage ("internal error in RS_DBI_makeDataFrame: could not corce named-list into data.frame", RS_DBI_ERROR); } #endif MEM_PROTECT(data); MEM_PROTECT(df_class_name = NEW_CHARACTER((Sint) 1)); SET_CHR_EL(df_class_name, 0, C_S_CPY("data.frame")); /* row.names */ n = GET_LENGTH(LST_EL(data, 0)); /* length(data[[1]]) */ MEM_PROTECT(row_names = NEW_CHARACTER(n)); for (i = 0; i < n; i++) { (void) sprintf(buf, "%d", i + 1); SET_CHR_EL(row_names, i, C_S_CPY(buf)); } #ifdef USING_R SET_ROWNAMES(data, row_names); SET_CLASS_NAME(data, df_class_name); #else /* untested S4/Splus code */ MEM_PROTECT(S_RowNamesSymbol = NEW_CHARACTER((Sint) 1)); SET_CHR_EL(S_RowNamesSymbol, 0, C_S_CPY("row.names")); MEM_PROTECT(S_ClassSymbol = NEW_CHARACTER((Sint) 1)); SET_CHR_EL(S_ClassSymbol, 0, C_S_CPY("class")); /* Note: the fun attribute() is just an educated guess as to * which function to use for setting attributes (see S.h) */ (void) attribute(data, S_ClassSymbol, df_class_name); MEM_UNPROTECT(2); #endif MEM_UNPROTECT(3); return; } void RS_DBI_allocOutput(s_object * output, RS_DBI_fields * flds, Sint num_rec, Sint expand) { s_object *names, *s_tmp; Sint j; int num_fields; Stype *fld_Sclass; #ifndef USING_R if (IS_LIST(output)) { output = AS_LIST(output); } else { RS_DBI_errorMessage("internal error in RS_DBI_allocOutput: could not (re)allocate output list", RS_DBI_ERROR); } #endif MEM_PROTECT(output); num_fields = flds->num_fields; if (expand) { for (j = 0; j < (Sint) num_fields; j++) { /* Note that in R-1.2.3 (at least) we need to protect SET_LENGTH */ s_tmp = LST_EL(output, j); MEM_PROTECT(SET_LENGTH(s_tmp, num_rec)); SET_ELEMENT(output, j, s_tmp); MEM_UNPROTECT(1); } #ifndef USING_R output = AS_LIST(output); /* this is only for S4's sake */ #endif MEM_UNPROTECT(1); return; } fld_Sclass = flds->Sclass; for (j = 0; j < (Sint) num_fields; j++) { switch ((int) fld_Sclass[j]) { case LOGICAL_TYPE: SET_ELEMENT(output, j, NEW_LOGICAL(num_rec)); break; case CHARACTER_TYPE: SET_ELEMENT(output, j, NEW_CHARACTER(num_rec)); break; case INTEGER_TYPE: SET_ELEMENT(output, j, NEW_INTEGER(num_rec)); break; case NUMERIC_TYPE: SET_ELEMENT(output, j, NEW_NUMERIC(num_rec)); break; case LIST_TYPE: SET_ELEMENT(output, j, NEW_LIST(num_rec)); break; #ifndef USING_R case RAW: /* we use a list as a container for raw objects */ SET_ELEMENT(output, j, NEW_LIST(num_rec)); break; #endif default: RS_DBI_errorMessage("unsupported data type in allocOutput", RS_DBI_ERROR); } } MEM_PROTECT(names = NEW_CHARACTER((Sint) num_fields)); for (j = 0; j < (Sint) num_fields; j++) { SET_CHR_EL(names, j, C_S_CPY(flds->name[j])); } SET_NAMES(output, names); #ifndef USING_R output = AS_LIST(output); /* again this is required only for S4 */ #endif MEM_UNPROTECT(2); return; } s_object * /* boolean */ RS_DBI_validHandle(Db_Handle * handle) { S_EVALUATOR s_object *valid; int handleType = 0; switch ((int) GET_LENGTH(handle)) { case MGR_HANDLE_TYPE: handleType = MGR_HANDLE_TYPE; break; case CON_HANDLE_TYPE: handleType = CON_HANDLE_TYPE; break; case RES_HANDLE_TYPE: handleType = RES_HANDLE_TYPE; break; } MEM_PROTECT(valid = NEW_LOGICAL((Sint) 1)); LGL_EL(valid, 0) = (Sint) is_validHandle(handle, handleType); MEM_UNPROTECT(1); return valid; } void RS_DBI_setException(Db_Handle * handle, DBI_EXCEPTION exceptionType, int errorNum, const char *errorMsg) { HANDLE_TYPE handleType; handleType = (int) GET_LENGTH(handle); if (handleType == MGR_HANDLE_TYPE) { RS_DBI_manager *obj; obj = RS_DBI_getManager(handle); obj->exception->exceptionType = exceptionType; obj->exception->errorNum = errorNum; obj->exception->errorMsg = RS_DBI_copyString(errorMsg); } else if (handleType == CON_HANDLE_TYPE) { RS_DBI_connection *obj; obj = RS_DBI_getConnection(handle); obj->exception->exceptionType = exceptionType; obj->exception->errorNum = errorNum; obj->exception->errorMsg = RS_DBI_copyString(errorMsg); } else { RS_DBI_errorMessage("internal error in RS_DBI_setException: could not setException", RS_DBI_ERROR); } return; } void RS_DBI_errorMessage(char *msg, DBI_EXCEPTION exception_type) { char *driver = "RS-DBI"; /* TODO: use the actual driver name */ switch (exception_type) { case RS_DBI_MESSAGE: PROBLEM "%s driver message: (%s)", driver, msg WARN; /* was PRINT_IT */ break; case RS_DBI_WARNING: PROBLEM "%s driver warning: (%s)", driver, msg WARN; break; case RS_DBI_ERROR: PROBLEM "%s driver: (%s)", driver, msg ERROR; break; case RS_DBI_TERMINATE: PROBLEM "%s driver fatal: (%s)", driver, msg ERROR; /* was TERMINATE */ break; } return; } /* wrapper to strcpy */ char * RS_DBI_copyString(const char *str) { char *buffer; buffer = (char *) malloc((size_t) strlen(str) + 1); if (!buffer) { RS_DBI_errorMessage("internal error in RS_DBI_copyString: could not alloc string space", RS_DBI_ERROR); } return strcpy(buffer, str); } /* wrapper to strncpy, plus (optionally) deleting trailing spaces */ char * RS_DBI_nCopyString(const char *str, size_t len, int del_blanks) { char *str_buffer, *end; str_buffer = (char *) malloc(len + 1); if (!str_buffer) { char errMsg[128]; (void) sprintf(errMsg, "could not malloc %ld bytes in RS_DBI_nCopyString", (long) len + 1); RS_DBI_errorMessage(errMsg, RS_DBI_ERROR); } if (len == 0) { *str_buffer = '\0'; return str_buffer; } (void) strncpy(str_buffer, str, len); /* null terminate string whether we delete trailing blanks or not */ if (del_blanks) { for (end = str_buffer + len - 1; end >= str_buffer; end--) { if (*end != ' ') { end++; break; } } *end = '\0'; } else { end = str_buffer + len; *end = '\0'; } return str_buffer; } s_object * RS_DBI_copyfields(RS_DBI_fields * flds) { S_EVALUATOR s_object *S_fields; Sint n = (Sint) 8; char *desc[] = { "name", "Sclass", "type", "len", "precision", "scale", "isVarLength", "nullOK" }; Stype types[] = { CHARACTER_TYPE, INTEGER_TYPE, INTEGER_TYPE, INTEGER_TYPE, INTEGER_TYPE, INTEGER_TYPE, LOGICAL_TYPE, LOGICAL_TYPE }; Sint lengths[8]; int i, j, num_fields; num_fields = flds->num_fields; for (j = 0; j < n; j++) { lengths[j] = (Sint) num_fields; } PROTECT(S_fields = RS_DBI_createNamedList(desc, types, lengths, n)); /* copy contentes from flds into an R/S list */ for (i = 0; i < num_fields; i++) { SET_LST_CHR_EL(S_fields, 0, i, C_S_CPY(flds->name[i])); LST_INT_EL(S_fields, 1, i) = (Sint) flds->Sclass[i]; LST_INT_EL(S_fields, 2, i) = (Sint) flds->type[i]; LST_INT_EL(S_fields, 3, i) = (Sint) flds->length[i]; LST_INT_EL(S_fields, 4, i) = (Sint) flds->precision[i]; LST_INT_EL(S_fields, 5, i) = (Sint) flds->scale[i]; LST_INT_EL(S_fields, 6, i) = (Sint) flds->isVarLength[i]; LST_INT_EL(S_fields, 7, i) = (Sint) flds->nullOk[i]; } UNPROTECT(1); return S_fields; } s_object * RS_DBI_createNamedList(char **names, Stype * types, Sint * lengths, Sint n) { S_EVALUATOR s_object *output, *output_names, *obj = S_NULL_ENTRY; Sint num_elem; int j; MEM_PROTECT(output = NEW_LIST(n)); MEM_PROTECT(output_names = NEW_CHARACTER(n)); for (j = 0; j < n; j++) { num_elem = lengths[j]; switch ((int) types[j]) { case LOGICAL_TYPE: MEM_PROTECT(obj = NEW_LOGICAL(num_elem)); break; case INTEGER_TYPE: MEM_PROTECT(obj = NEW_INTEGER(num_elem)); break; case NUMERIC_TYPE: MEM_PROTECT(obj = NEW_NUMERIC(num_elem)); break; case CHARACTER_TYPE: MEM_PROTECT(obj = NEW_CHARACTER(num_elem)); break; case LIST_TYPE: MEM_PROTECT(obj = NEW_LIST(num_elem)); break; #ifndef USING_R case RAW_TYPE: MEM_PROTECT(obj = NEW_RAW(num_elem)); break; #endif default: { char msg[256]; sprintf(msg,"unsupported data type in createNamedList: %i in list %i (%s)", types[j], j, names[j]); RS_DBI_errorMessage(msg, RS_DBI_ERROR); } } SET_ELEMENT(output, (Sint) j, obj); SET_CHR_EL(output_names, j, C_S_CPY(names[j])); } SET_NAMES(output, output_names); MEM_UNPROTECT(n + 2); return (output); } s_object * RS_DBI_SclassNames(s_object * type) { s_object *typeNames; Sint *typeCodes; Sint n; int i; const char *s; PROTECT(type = AS_INTEGER(type)); n = LENGTH(type); typeCodes = INTEGER_DATA(type); PROTECT(typeNames = NEW_CHARACTER(n)); for (i = 0; i < n; i++) { s = RS_DBI_getTypeName(typeCodes[i], RS_dataTypeTable); if (!s) { RS_DBI_errorMessage("internal error RS_DBI_SclassNames: unrecognized S type", RS_DBI_ERROR); } SET_CHR_EL(typeNames, i, C_S_CPY(s)); } UNPROTECT(2); return typeNames; } /* The following functions roughly implement a simple object * database. */ Mgr_Handle * RS_DBI_asMgrHandle(Sint mgrId) { Mgr_Handle *mgrHandle; MEM_PROTECT(mgrHandle = NEW_INTEGER((Sint) 1)); MGR_ID(mgrHandle) = mgrId; MEM_UNPROTECT(1); return mgrHandle; } Con_Handle * RS_DBI_asConHandle(Sint mgrId, Sint conId) { Con_Handle *conHandle; MEM_PROTECT(conHandle = NEW_INTEGER((Sint) 2)); MGR_ID(conHandle) = mgrId; CON_ID(conHandle) = conId; MEM_UNPROTECT(1); return conHandle; } Res_Handle * RS_DBI_asResHandle(Sint mgrId, Sint conId, Sint resId) { Res_Handle *resHandle; MEM_PROTECT(resHandle = NEW_INTEGER((Sint) 3)); MGR_ID(resHandle) = mgrId; CON_ID(resHandle) = conId; RES_ID(resHandle) = resId; MEM_UNPROTECT(1); return resHandle; } RS_DBI_manager * RS_DBI_getManager(Mgr_Handle * handle) { RS_DBI_manager *mgr; if (!is_validHandle(handle, MGR_HANDLE_TYPE)) { RS_DBI_errorMessage("invalid dbManager handle", RS_DBI_ERROR); } mgr = dbManager; if (!mgr) { RS_DBI_errorMessage("internal error in RS_DBI_getManager: corrupt dbManager handle", RS_DBI_ERROR); } return mgr; } RS_DBI_connection * RS_DBI_getConnection(Con_Handle * conHandle) { RS_DBI_manager *mgr; Sint indx; mgr = RS_DBI_getManager(conHandle); indx = RS_DBI_lookup(mgr->connectionIds, mgr->length, CON_ID(conHandle)); if (indx < 0) { RS_DBI_errorMessage("internal error in RS_DBI_getConnection: corrupt connection handle", RS_DBI_ERROR); } if (!mgr->connections[indx]) { RS_DBI_errorMessage("internal error in RS_DBI_getConnection: corrupt connection object", RS_DBI_ERROR); } return mgr->connections[indx]; } RS_DBI_resultSet * RS_DBI_getResultSet(Res_Handle * rsHandle) { RS_DBI_connection *con; Sint indx; con = RS_DBI_getConnection(rsHandle); indx = RS_DBI_lookup(con->resultSetIds, con->length, RES_ID(rsHandle)); if (indx < 0) { RS_DBI_errorMessage ("internal error in RS_DBI_getResultSet: could not find resultSet in connection", RS_DBI_ERROR); } if (!con->resultSets[indx]) { RS_DBI_errorMessage("internal error in RS_DBI_getResultSet: missing resultSet", RS_DBI_ERROR); } return con->resultSets[indx]; } /* Very simple objectId (mapping) table. newEntry() returns an index * to an empty cell in table, and lookup() returns the position in the * table of obj_id. Notice that we decided not to touch the entries * themselves to give total control to the invoking functions (this * simplify error management in the invoking routines.) */ Sint RS_DBI_newEntry(Sint * table, Sint length) { Sint i, indx, empty_val; indx = empty_val = (Sint) - 1; for (i = 0; i < length; i++) { if (table[i] == empty_val) { indx = i; break; } } return indx; } Sint RS_DBI_lookup(Sint * table, Sint length, Sint obj_id) { Sint i, indx; indx = (Sint) - 1; for (i = 0; i < length; ++i) { if (table[i] == obj_id) { indx = i; break; } } return indx; } /* return a list of entries pointed by *entries (we allocate the space, * but the caller should free() it). The function returns the number * of entries. */ Sint RS_DBI_listEntries(Sint * table, Sint length, Sint * entries) { int i, n; for (i = n = 0; i < length; i++) { if (table[i] < 0) { continue; } entries[n++] = table[i]; } return n; } void RS_DBI_freeEntry(Sint * table, Sint indx) { /* no error checking!!! */ Sint empty_val = (Sint) - 1; table[indx] = empty_val; return; } int is_validHandle(Db_Handle * handle, HANDLE_TYPE handleType) { Sint mgr_id, len, indx; RS_DBI_manager *mgr; RS_DBI_connection *con; if (IS_INTEGER(handle)) { handle = AS_INTEGER(handle); } else { return 0; /* non handle object */ } len = (int) GET_LENGTH(handle); if (len < handleType || handleType < 1 || handleType > 3) { return 0; } mgr_id = MGR_ID(handle); if (((Sint) getpid()) != mgr_id) { return 0; } /* at least we have a potential valid dbManager */ mgr = dbManager; if (!mgr || !mgr->connections) { return 0; /* expired manager */ } if (handleType == MGR_HANDLE_TYPE) { return 1; /* valid manager id */ } /* ... on to connections */ indx = RS_DBI_lookup(mgr->connectionIds, mgr->length, CON_ID(handle)); if (indx < 0) { return 0; } con = mgr->connections[indx]; if (!con) { return 0; } if (!con->resultSets) { return 0; /* un-initialized (invalid) */ } if (handleType == CON_HANDLE_TYPE) { return 1; /* valid connection id */ } /* .. on to resultSets */ indx = RS_DBI_lookup(con->resultSetIds, con->length, RES_ID(handle)); if (indx < 0) { return 0; } if (!con->resultSets[indx]) { return 0; } return 1; } /* The following 3 routines provide metadata for the 3 main objects * dbManager, dbConnection and dbResultSet. These functions * an object Id and return a list with all the meta-data. In R/S we * simply invoke one of these and extract the metadata piece we need, * which can be NULL if non-existent or un-implemented. * * Actually, each driver should modify these functions to add the * driver-specific info, such as server version, client version, etc. * That's how the various RS_MySQL_managerInfo, etc., were implemented. */ s_object * /* named list */ RS_DBI_managerInfo(Mgr_Handle * mgrHandle) { S_EVALUATOR RS_DBI_manager *mgr; s_object *output; Sint i, num_con; Sint n = (Sint) 7; char *mgrDesc[] = { "connectionIds", "fetch_default_rec", "managerId", "length", "num_con", "counter", "clientVersion" }; Stype mgrType[] = { INTEGER_TYPE, INTEGER_TYPE, INTEGER_TYPE, INTEGER_TYPE, INTEGER_TYPE, INTEGER_TYPE, CHARACTER_TYPE }; Sint mgrLen[] = { 1, 1, 1, 1, 1, 1, 1 }; mgr = RS_DBI_getManager(mgrHandle); num_con = (Sint) mgr->num_con; mgrLen[0] = num_con; PROTECT(output = RS_DBI_createNamedList(mgrDesc, mgrType, mgrLen, n)); for (i = 0; i < num_con; i++) { LST_INT_EL(output, 0, i) = (Sint) mgr->connectionIds[i]; } LST_INT_EL(output, 1, 0) = (Sint) mgr->fetch_default_rec; LST_INT_EL(output, 2, 0) = (Sint) mgr->managerId; LST_INT_EL(output, 3, 0) = (Sint) mgr->length; LST_INT_EL(output, 4, 0) = (Sint) mgr->num_con; LST_INT_EL(output, 5, 0) = (Sint) mgr->counter; SET_LST_CHR_EL(output, 6, 0, C_S_CPY("NA")); /* client versions? */ UNPROTECT(1); return output; } /* The following should be considered templetes to be * implemented by individual drivers. */ s_object * /* return a named list */ RS_DBI_connectionInfo(Con_Handle * conHandle) { S_EVALUATOR RS_DBI_connection *con; s_object *output; Sint i; Sint n = (Sint) 8; char *conDesc[] = { "host", "port", "user", "dbname" "serverVersion", "protocolVersion", "threadId", "rsHandle" }; Stype conType[] = { CHARACTER_TYPE, CHARACTER_TYPE, CHARACTER_TYPE, CHARACTER_TYPE, CHARACTER_TYPE, INTEGER_TYPE, INTEGER_TYPE, INTEGER_TYPE }; Sint conLen[] = { 1, 1, 1, 1, 1, 1, 1, -1 }; con = RS_DBI_getConnection(conHandle); conLen[7] = con->num_res; PROTECT(output = RS_DBI_createNamedList(conDesc, conType, conLen, n)); /* dummy */ SET_LST_CHR_EL(output, 0, 0, C_S_CPY("NA")); /* host */ SET_LST_CHR_EL(output, 1, 0, C_S_CPY("NA")); /* port */ SET_LST_CHR_EL(output, 2, 0, C_S_CPY("NA")); /* dbname */ SET_LST_CHR_EL(output, 3, 0, C_S_CPY("NA")); /* user */ SET_LST_CHR_EL(output, 4, 0, C_S_CPY("NA")); /* serverVersion */ LST_INT_EL(output, 5, 0) = (Sint) - 1; /* protocolVersion */ LST_INT_EL(output, 6, 0) = (Sint) - 1; /* threadId */ for (i = 0; i < con->num_res; i++) { LST_INT_EL(output, 7, (Sint) i) = con->resultSetIds[i]; } UNPROTECT(1); return output; } s_object * /* return a named list */ RS_DBI_resultSetInfo(Res_Handle * rsHandle) { S_EVALUATOR RS_DBI_resultSet *result; s_object *output, *flds; Sint n = (Sint) 6; char *rsDesc[] = { "statement", "isSelect", "rowsAffected", "rowCount", "completed", "fields" }; Stype rsType[] = { CHARACTER_TYPE, INTEGER_TYPE, INTEGER_TYPE, INTEGER_TYPE, INTEGER_TYPE, LIST_TYPE }; Sint rsLen[] = { 1, 1, 1, 1, 1, 1 }; result = RS_DBI_getResultSet(rsHandle); if (result->fields) { PROTECT(flds = RS_DBI_copyfields(result->fields)); } else { PROTECT(flds = S_NULL_ENTRY); } PROTECT(output = RS_DBI_createNamedList(rsDesc, rsType, rsLen, n)); SET_LST_CHR_EL(output, 0, 0, C_S_CPY(result->statement)); LST_INT_EL(output, 1, 0) = result->isSelect; LST_INT_EL(output, 2, 0) = result->rowsAffected; LST_INT_EL(output, 3, 0) = result->rowCount; LST_INT_EL(output, 4, 0) = result->completed; SET_ELEMENT(LST_EL(output, 5), (Sint) 0, flds); UNPROTECT(2); return output; } s_object * /* named list */ RS_DBI_getFieldDescriptions(RS_DBI_fields * flds) { S_EVALUATOR s_object *S_fields; Sint n = (Sint) 7; Sint lengths[7]; char *desc[] = { "name", "Sclass", "type", "len", "precision", "scale", "nullOK" }; Stype types[] = { CHARACTER_TYPE, INTEGER_TYPE, INTEGER_TYPE, INTEGER_TYPE, INTEGER_TYPE, INTEGER_TYPE, LOGICAL_TYPE }; Sint i, j; int num_fields; num_fields = flds->num_fields; for (j = 0; j < n; j++) { lengths[j] = (Sint) num_fields; } PROTECT(S_fields = RS_DBI_createNamedList(desc, types, lengths, n)); /* copy contentes from flds into an R/S list */ for (i = 0; i < (Sint) num_fields; i++) { SET_LST_CHR_EL(S_fields, 0, i, C_S_CPY(flds->name[i])); LST_INT_EL(S_fields, 1, i) = (Sint) flds->Sclass[i]; LST_INT_EL(S_fields, 2, i) = (Sint) flds->type[i]; LST_INT_EL(S_fields, 3, i) = (Sint) flds->length[i]; LST_INT_EL(S_fields, 4, i) = (Sint) flds->precision[i]; LST_INT_EL(S_fields, 5, i) = (Sint) flds->scale[i]; LST_INT_EL(S_fields, 6, i) = (Sint) flds->nullOk[i]; } UNPROTECT(1); return (S_fields); } /* given a type id return its human-readable name. * We define an RS_DBI_dataTypeTable */ const char * RS_DBI_getTypeName(Sint t, const struct data_types table[]) { int i; char buf[128]; for (i = 0; table[i].typeName != (char *) 0; i++) { if (table[i].typeId == t) { return table[i].typeName; } } sprintf(buf, "unknown (%ld)", (long) t); RS_DBI_errorMessage(buf, RS_DBI_WARNING); return "UNKNOWN"; } /* Translate R/S identifiers (and only R/S names!!!) into * valid SQL identifiers; overwrite input vector. Currently, * (1) translate "." into "_". * (2) first character should be a letter (traslate to "X" if not), * but a double quote signals a "delimited identifier" * (3) check that length <= 18, but only warn, since most (all?) * dbms allow much longer identifiers. * (4) SQL reserved keywords are handled in the R/S calling * function make.SQL.names(), not here. * BUG: Compound SQL identifiers are not handled properly. * Note the the dot "." is a valid SQL delimiter, used for specifying * user/table in a compound identifier. Thus, it's possible that * such compound name is mapped into a legal R/S identifier (preserving * the "."), and then we incorrectly map such delimiting "dot" into "_" * thus loosing the original SQL compound identifier. */ #define RS_DBI_MAX_IDENTIFIER_LENGTH 18 /* as per SQL92 */ s_object * RS_DBI_makeSQLNames(s_object * snames) { S_EVALUATOR long nstrings; char *name, c; char errMsg[128]; size_t len; Sint i; nstrings = (Sint) GET_LENGTH(snames); for (i = 0; i < nstrings; i++) { name = (char *) CHR_EL(snames, i); /* NOTE: Sameer.... casted RHS using (char*) */ if (strlen(name) > RS_DBI_MAX_IDENTIFIER_LENGTH) { (void) sprintf(errMsg, "SQL identifier %s longer than %d chars", name, RS_DBI_MAX_IDENTIFIER_LENGTH); RS_DBI_errorMessage(errMsg, RS_DBI_WARNING); } /* check for delimited-identifiers (those in double-quotes); * if missing closing double-quote, warn and treat as non-delim */ c = *name; len = strlen(name); if (c == '"' && name[len - 1] == '"') { continue; } if (!isalpha(c) && c != '"') { *name = 'X'; } name++; while ((c = *name)) { /* TODO: recognize SQL delim "." instances that may have * originated in SQL and R/S make.names() left alone */ if (c == '.') { *name = '_'; } name++; } } return snames; } #ifdef USING_R /* These 2 R-specific functions are used by the C macros IS_NA(p,t) * and NA_SET(p,t) (in this way one simply use macros to test and set * NA's regardless whether we're using R or S. */ void RS_na_set(void *ptr, Stype type) { double *d; Sint *i; switch (type) { case INTEGER_TYPE: i = (Sint *) ptr; *i = NA_INTEGER; break; case LOGICAL_TYPE: i = (Sint *) ptr; *i = NA_LOGICAL; break; case NUMERIC_TYPE: d = (double *) ptr; *d = NA_REAL; break; } } int RS_is_na(void *ptr, Stype type) { int *i, out = -2; char *c; double *d; switch (type) { case INTEGER_TYPE: case LOGICAL_TYPE: i = (int *) ptr; out = (int) ((*i) == NA_INTEGER); break; case NUMERIC_TYPE: d = (double *) ptr; out = ISNA(*d); break; case STRING_TYPE: c = (char *) ptr; out = (int) (strcmp(c, CHR_EL(NA_STRING, 0)) == 0); break; } return out; } #endif /* the codes come from from R/src/main/util.c */ const struct data_types RS_dataTypeTable[] = { #ifdef USING_R {"NULL", NILSXP}, /* real types */ {"symbol", SYMSXP}, {"pairlist", LISTSXP}, {"closure", CLOSXP}, {"environment", ENVSXP}, {"promise", PROMSXP}, {"language", LANGSXP}, {"special", SPECIALSXP}, {"builtin", BUILTINSXP}, {"char", CHARSXP}, {"logical", LGLSXP}, {"integer", INTSXP}, {"double", REALSXP}, /*- "real", for R <= 0.61.x */ {"complex", CPLXSXP}, {"character", STRSXP}, {"...", DOTSXP}, {"any", ANYSXP}, {"expression", EXPRSXP}, {"list", VECSXP}, /* aliases : */ {"numeric", REALSXP}, {"name", SYMSXP}, {(char *) 0, -1} #else {"logical", LGL}, {"integer", INT}, {"single", REAL}, {"numeric", DOUBLE}, {"character", CHAR}, {"list", LIST}, {"complex", COMPLEX}, {"raw", RAW}, {"any", ANY}, {"structure", STRUCTURE}, {(char *) 0, -1} #endif }; RPostgreSQL/src/RS-pgsql-pqexecparams.c0000644000176000001440000000717012124517222017524 0ustar ripleyusers/* * RS-pgsql-pqexecparam.c * * $Id: RS-pgsql-pqexecparam.c $ * */ #include #include "RS-PostgreSQL.h" #include /* Execute (currently) one sql statement (INSERT, DELETE, SELECT, etc.), * set coercion type mappings between the server internal data types and * S classes. Don't drag the return value. */ /* should call with .External */ SEXP RS_PostgreSQL_pqexecparams(SEXP args) { S_EVALUATOR RS_DBI_connection * con; SEXP retval; PGconn *my_connection; PGresult *my_result; R_len_t nparams; Con_Handle * conHandle; s_object * statement; s_object * params; Sint is_select=0; const char *dyn_statement; const char ** pqparams; RS_DBI_resultSet *result; conHandle = CADR(args); statement = CADDR(args); params = CADDDR(args); con = RS_DBI_getConnection(conHandle); my_connection = (PGconn *) con->drvConnection; dyn_statement = CHR_EL(statement, 0); nparams = length(params); pqparams = calloc(nparams, sizeof(char*)); for (R_len_t i = 0; i < nparams; i++){ pqparams[i] = CHR_EL(params, i); } /* http://www.postgresql.org/docs/9.2/static/libpq-exec.html * PGresult *PQexecParams(PGconn *conn, * const char *command, * int nParams, * const Oid *paramTypes, * const char * const *paramValues, * const int *paramLengths, * const int *paramFormats, * int resultFormat); */ my_result = PQexecParams(my_connection, dyn_statement, nparams, NULL, pqparams, NULL, NULL, 0); if (my_result == NULL) { char *errMsg; const char *omsg; size_t len; omsg = PQerrorMessage(my_connection); len = strlen(omsg); errMsg = malloc(len + 80); /* 80 should be larger than the length of "could not ..."*/ snprintf(errMsg, len + 80, "could not run statement: %s", omsg); RS_DBI_errorMessage(errMsg, RS_DBI_ERROR); free(errMsg); } if (PQresultStatus(my_result) == PGRES_TUPLES_OK) { is_select = (Sint) TRUE; } if (PQresultStatus(my_result) == PGRES_COMMAND_OK) { is_select = (Sint) FALSE; } if (strcmp(PQresultErrorMessage(my_result), "") != 0) { char *errResultMsg; const char *omsg; size_t len; omsg = PQerrorMessage(my_connection); len = strlen(omsg); errResultMsg = malloc(len + 80); /* 80 should be larger than the length of "could not ..."*/ snprintf(errResultMsg, len + 80, "could not Retrieve the result : %s", omsg); RS_DBI_errorMessage(errResultMsg, RS_DBI_ERROR); free(errResultMsg); /* Frees the storage associated with a PGresult. * void PQclear(PGresult *res); */ PQclear(my_result); } /* we now create the wrapper and copy values */ PROTECT(retval = RS_DBI_allocResultSet(conHandle)); result = RS_DBI_getResultSet(retval); result->statement = RS_DBI_copyString(dyn_statement); result->drvResultSet = (void *) my_result; result->rowCount = (Sint) 0; result->isSelect = is_select; /* Returns the number of rows affected by the SQL command. * * char *PQcmdTuples(PGresult *res); * */ if (!is_select) { result->rowsAffected = (Sint) atoi(PQcmdTuples(my_result)); result->completed = 1; } else { result->rowsAffected = (Sint) - 1; result->completed = 0; } if (is_select) { result->fields = RS_PostgreSQL_createDataMappings(retval); } UNPROTECT(1); return retval; } RPostgreSQL/src/RS-pgsql-getResult.c0000644000176000001440000000543712124517222017015 0ustar ripleyusers/* * RS-pgsql-copy.c * * $Id: RS-pgsql-getResult.c 237 2012-10-04 14:54:29Z tomoakin@kenroku.kanazawa-u.ac.jp $ */ #include "RS-PostgreSQL.h" #define COPY_IN_BUFSIZE 8192 /* adapter for PQputCopyData and PQputCopyEnd which is used in conjunction with COPY table from STDIN */ /* * RS_PostgreSQL_CopyIn copies all content of the file specified with filename * to the conHandle which has opened connection previously issued the COPY * table from STDIN query the data is read from file sent to the database with * PQputCopyData in chunks of COPY_IN_BUFSIZE. * The copy ends when 0 byte could be read from the file and then the * PQputCopyEnd is called to complete the copying. */ /* * RS_PostgreSQL_getResult is the implementation of postgresqlgetResult() * * RS_PostgreSQL_getResult will be called after CopyIn * for cheching the result of CopyIn * * postgresqlCopyInDataframe(new.con, value) * rs<-postgresqlgetResult(new.con) */ s_object * RS_PostgreSQL_getResult(Con_Handle * conHandle) { S_EVALUATOR RS_DBI_connection * con; S_EVALUATOR RS_DBI_resultSet * result; PGconn *my_connection; Res_Handle *rsHandle; Sint res_id; PGresult *my_result; con = RS_DBI_getConnection(conHandle); my_connection = (PGconn *) con->drvConnection; if (con->num_res > 0) { res_id = (Sint) con->resultSetIds[0]; rsHandle = RS_DBI_asResHandle(MGR_ID(conHandle), CON_ID(conHandle), res_id); result = RS_DBI_getResultSet(rsHandle); if (result->completed == 0) { RS_DBI_errorMessage("connection with pending rows, close resultSet before continuing", RS_DBI_ERROR); } else { RS_PostgreSQL_closeResultSet(rsHandle); } } my_result = PQgetResult(my_connection); if(my_result == NULL) return S_NULL_ENTRY; if (strcmp(PQresultErrorMessage(my_result), "") != 0) { char *errResultMsg; const char *omsg; size_t len; omsg = PQerrorMessage(my_connection); len = strlen(omsg); errResultMsg = malloc(len + 80); /* 80 should be larger than the length of "could not ..."*/ snprintf(errResultMsg, len + 80, "could not Retrieve the result : %s", omsg); RS_DBI_errorMessage(errResultMsg, RS_DBI_ERROR); free(errResultMsg); /* Frees the storage associated with a PGresult. * void PQclear(PGresult *res); */ PQclear(my_result); } /* we now create the wrapper and copy values */ PROTECT(rsHandle = RS_DBI_allocResultSet(conHandle)); result = RS_DBI_getResultSet(rsHandle); result->drvResultSet = (void *) my_result; result->rowCount = (Sint) 0; result->isSelect = 0; result->rowsAffected = 0; result->completed = 1; UNPROTECT(1); return rsHandle; } RPostgreSQL/src/RS-PQescape.c0000644000176000001440000000203412124517222015402 0ustar ripleyusers/* * RS-PQescape.c * * $Id: RS-PQescape.c 212 2011-11-22 10:58:50Z tomoakin@kenroku.kanazawa-u.ac.jp $ */ #include "RS-PostgreSQL.h" /* * Adapter function to PQescapeStringConn() * This function should properly escape the string argument * appropriately depending on the encoding etc. that is specific to * connection. * Note the single quote is not attached in the return val. */ SEXP RS_PostgreSQL_escape(SEXP conHandle, SEXP preescapestring) { S_EVALUATOR PGconn * my_connection; RS_DBI_connection *con; SEXP output; size_t length; const char *statement_cstr; char *escapedstring; con = RS_DBI_getConnection(conHandle); my_connection = (PGconn *) con->drvConnection; statement_cstr = CHR_EL(preescapestring, 0); length = strlen(statement_cstr); escapedstring = R_alloc(length * 2 + 1, 1); PQescapeStringConn(my_connection, escapedstring, statement_cstr, length, NULL); output = allocVector(STRSXP, 1); SET_STRING_ELT(output, 0, mkChar(escapedstring)); return output; } RPostgreSQL/src/libpq/0000755000176000001440000000000012124517222014323 5ustar ripleyusersRPostgreSQL/src/libpq/pqsignal.h0000644000176000001440000000125012124517222016310 0ustar ripleyusers/*------------------------------------------------------------------------- * * pqsignal.h * prototypes for the reliable BSD-style signal(2) routine. * * * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/interfaces/libpq/pqsignal.h * * NOTES * This shouldn't be in libpq, but the monitor and some other * things need it... * *------------------------------------------------------------------------- */ #ifndef PQSIGNAL_H #define PQSIGNAL_H typedef void (*pqsigfunc) (int); extern pqsigfunc pqsignal(int signo, pqsigfunc func); #endif /* PQSIGNAL_H */ RPostgreSQL/src/libpq/Makefile.port0000644000176000001440000000354511660061757016770 0ustar ripleyusers# src/makefiles/Makefile.win32 # Use replacement include files for those missing on Win32 override CPPFLAGS+="-I$(top_srcdir)/src/include/port/win32" ifdef PGXS BE_DLLLIBS= -L$(libdir) -lpostgres else BE_DLLLIBS= -L$(top_builddir)/src/backend -lpostgres endif AROPT = crs DLSUFFIX = .dll CFLAGS_SL = ifneq (,$(findstring backend,$(subdir))) ifeq (,$(findstring conversion_procs,$(subdir))) ifeq (,$(findstring snowball,$(subdir))) ifeq (,$(findstring libpqwalreceiver,$(subdir))) override CPPFLAGS+= -DBUILDING_DLL endif endif endif endif ifneq (,$(findstring timezone,$(subdir))) override CPPFLAGS+= -DBUILDING_DLL endif ifneq (,$(findstring ecpg/ecpglib,$(subdir))) override CPPFLAGS+= -DBUILDING_DLL endif # required by Python headers ifneq (,$(findstring src/pl/plpython,$(subdir))) override CPPFLAGS+= -DUSE_DL_IMPORT endif # special win32 headers are provided here ifdef PGXS override CPPFLAGS+= -I$(includedir_server)/port/win32 endif # it is better to install shared-libraries anyway? # may be overriden with make MAKE_DLL=false install ifndef MAKE_DLL MAKE_DLL = true endif # Build rules to add versioninfo resources to win32 binaries WIN32RES += win32ver.o ifeq ($(PGFILESHLIB),1) PGFTYPE = VFT_DLL else PGFTYPE = VFT_APP endif ifneq (,$(PGAPPICON)) PGICOSTR = $(subst /,\/,IDI_ICON ICON \"$(top_builddir)/src/port/$(PGAPPICON).ico\") endif win32ver.rc: $(top_srcdir)/src/port/win32ver.rc sed -e 's;FILEDESC;$(PGFILEDESC);' -e 's;VFT_APP;$(PGFTYPE);' -e 's;_ICO_;$(PGICOSTR);' -e 's;\(VERSION.*\),0 *$$;\1,'`date '+%y%j' | sed 's/^0*//'`';' $< >$@ win32ver.o: win32ver.rc $(WINDRES) -i $< -o $@ --include-dir=$(top_builddir)/src/include --include-dir=$(srcdir) # Rule for building a shared library from a single .o file %.dll: %.o $(DLLTOOL) --export-all --output-def $*.def $< $(DLLWRAP) -o $@ --def $*.def $< $(LDFLAGS) $(LDFLAGS_SL) $(BE_DLLLIBS) rm -f $*.def RPostgreSQL/src/libpq/Makefile.darwin0000644000176000001440000001035011663173071017254 0ustar ripleyusers#------------------------------------------------------------------------- # # Makefile for src/interfaces/libpq library # # Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/interfaces/libpq/Makefile # #------------------------------------------------------------------------- top_builddir = .. include Makefile.global.darwin all: pg_config.h pg_config_os.h pg_config.h: pg_config.h.darwin cp pg_config.h.darwin pg_config.h pg_config_os.h: pg_config_os.h.darwin cp pg_config_os.h.darwin pg_config_os.h pg_config_paths.h: pg_config_paths.h.darwin cp pg_config_paths.h.darwin pg_config_paths.h # shared library parameters NAME= pq SO_MAJOR_VERSION= 5 SO_MINOR_VERSION= 4 override CPPFLAGS := -DFRONTEND -DUNSAFE_STAT_OK -I$(srcdir) $(CPPFLAGS) ifneq ($(PORTNAME), win32) override CFLAGS += $(PTHREAD_CFLAGS) endif # Need to recompile any external C files because we need # all object files to use the same compile flags as libpq; some # platforms require special flags. LIBS := $(LIBS:-lpgport=) # We can't use Makefile variables here because the MSVC build system scrapes # OBJS from this file. OBJS= fe-auth.o fe-connect.o fe-exec.o fe-misc.o fe-print.o fe-lobj.o \ fe-protocol2.o fe-protocol3.o pqexpbuffer.o pqsignal.o fe-secure.o \ libpq-events.o # libpgport C files we always use OBJS += chklocale.o inet_net_ntop.o noblock.o pgstrcasecmp.o thread.o # libpgport C files that are needed if identified by configure OBJS += $(filter crypt.o getaddrinfo.o getpeereid.o inet_aton.o open.o snprintf.o strerror.o strlcpy.o win32error.o win32setlocale.o, $(LIBOBJS)) # backend/libpq OBJS += ip.o md5.o # utils/mb OBJS += encnames.o wchar.o ifeq ($(PORTNAME), cygwin) override shlib = cyg$(NAME)$(DLSUFFIX) endif ifeq ($(PORTNAME), win32) # pgsleep.o is from libpgport OBJS += pgsleep.o win32.o libpqrc.o libpqrc.o: libpq.rc $(WINDRES) -i $< -o $@ ifeq ($(enable_thread_safety), yes) OBJS += pthread-win32.o endif endif # Add libraries that libpq depends (or might depend) on into the # shared library link. (The order in which you list them here doesn't # matter.) ifneq ($(PORTNAME), win32) SHLIB_LINK += $(filter -lcrypt -ldes -lcom_err -lcrypto -lk5crypto -lkrb5 -lgssapi_krb5 -lgss -lgssapi -lssl -lsocket -lnsl -lresolv -lintl, $(LIBS)) $(LDAP_LIBS_FE) $(PTHREAD_LIBS) else SHLIB_LINK += $(filter -lcrypt -ldes -lcom_err -lcrypto -lk5crypto -lkrb5 -lgssapi32 -lssl -lsocket -lnsl -lresolv -lintl $(PTHREAD_LIBS), $(LIBS)) $(LDAP_LIBS_FE) endif ifeq ($(PORTNAME), win32) SHLIB_LINK += -lshfolder -lwsock32 -lws2_32 -lsecur32 $(filter -leay32 -lssleay32 -lcomerr32 -lkrb5_32, $(LIBS)) endif SHLIB_EXPORTS = exports.txt all: all-lib # Shared library stuff include Makefile.shlib distprep: libpq-dist.rc libpq.rc libpq-dist.rc: libpq.rc.in sed -e 's/\(VERSION.*\),0 *$$/\1,'`date '+%y%j' | sed 's/^0*//'`'/' $< >$@ # Depend on Makefile.global to force rebuild on re-run of configure. # (But libpq-dist.rc is shipped in the distribution for shell-less # installations and is only updated by distprep.) fe-connect.o: fe-connect.c pg_config_paths.h install: all installdirs install-lib $(INSTALL_DATA) $(srcdir)/libpq-fe.h '$(DESTDIR)$(includedir)' $(INSTALL_DATA) $(srcdir)/libpq-events.h '$(DESTDIR)$(includedir)' $(INSTALL_DATA) $(srcdir)/libpq-int.h '$(DESTDIR)$(includedir_internal)' $(INSTALL_DATA) $(srcdir)/pqexpbuffer.h '$(DESTDIR)$(includedir_internal)' $(INSTALL_DATA) $(srcdir)/pg_service.conf.sample '$(DESTDIR)$(datadir)/pg_service.conf.sample' installdirs: installdirs-lib $(MKDIR_P) '$(DESTDIR)$(includedir)' '$(DESTDIR)$(includedir_internal)' uninstall: uninstall-lib rm -f '$(DESTDIR)$(includedir)/libpq-fe.h' rm -f '$(DESTDIR)$(includedir)/libpq-events.h' rm -f '$(DESTDIR)$(includedir_internal)/libpq-int.h' rm -f '$(DESTDIR)$(includedir_internal)/pqexpbuffer.h' rm -f '$(DESTDIR)$(datadir)/pg_service.conf.sample' clean distclean: clean-lib rm -f $(OBJS) pthread.h libpq.rc rm -f libpq.dylib libpq.$(SO_MAJOR_VERSION).dylib libpq.$(SO_MAJOR_VERSION).$(SO_MINOR_VERSION).dylib # Might be left over from a Win32 client-only build rm -f pg_config.h rm -f pg_config_os.h rm -f pg_config_paths.h maintainer-clean: distclean maintainer-clean-lib rm -f libpq-dist.rc RPostgreSQL/src/libpq/libpqdll.def0000644000176000001440000001310311660061757016617 0ustar ripleyusers; DEF file for MS VC++ LIBRARY LIBPQ EXPORTS PQconnectdb @ 1 PQsetdbLogin @ 2 PQconndefaults @ 3 PQfinish @ 4 PQreset @ 5 PQrequestCancel @ 6 PQdb @ 7 PQuser @ 8 PQpass @ 9 PQhost @ 10 PQport @ 11 PQtty @ 12 PQoptions @ 13 PQstatus @ 14 PQerrorMessage @ 15 PQsocket @ 16 PQbackendPID @ 17 PQtrace @ 18 PQuntrace @ 19 PQsetNoticeProcessor @ 20 PQexec @ 21 PQnotifies @ 22 PQsendQuery @ 23 PQgetResult @ 24 PQisBusy @ 25 PQconsumeInput @ 26 PQgetline @ 27 PQputline @ 28 PQgetlineAsync @ 29 PQputnbytes @ 30 PQendcopy @ 31 PQfn @ 32 PQresultStatus @ 33 PQntuples @ 34 PQnfields @ 35 PQbinaryTuples @ 36 PQfname @ 37 PQfnumber @ 38 PQftype @ 39 PQfsize @ 40 PQfmod @ 41 PQcmdStatus @ 42 PQoidStatus @ 43 PQcmdTuples @ 44 PQgetvalue @ 45 PQgetlength @ 46 PQgetisnull @ 47 PQclear @ 48 PQmakeEmptyPGresult @ 49 PQprint @ 50 PQdisplayTuples @ 51 PQprintTuples @ 52 lo_open @ 53 lo_close @ 54 lo_read @ 55 lo_write @ 56 lo_lseek @ 57 lo_creat @ 58 lo_tell @ 59 lo_unlink @ 60 lo_import @ 61 lo_export @ 62 pgresStatus @ 63 PQmblen @ 64 PQresultErrorMessage @ 65 PQresStatus @ 66 termPQExpBuffer @ 67 appendPQExpBufferChar @ 68 initPQExpBuffer @ 69 resetPQExpBuffer @ 70 PQoidValue @ 71 PQclientEncoding @ 72 PQenv2encoding @ 73 appendBinaryPQExpBuffer @ 74 appendPQExpBufferStr @ 75 destroyPQExpBuffer @ 76 createPQExpBuffer @ 77 PQconninfoFree @ 78 PQconnectPoll @ 79 PQconnectStart @ 80 PQflush @ 81 PQisnonblocking @ 82 PQresetPoll @ 83 PQresetStart @ 84 PQsetClientEncoding @ 85 PQsetnonblocking @ 86 PQfreeNotify @ 87 PQescapeString @ 88 PQescapeBytea @ 89 printfPQExpBuffer @ 90 appendPQExpBuffer @ 91 pg_encoding_to_char @ 92 pg_utf_mblen @ 93 PQunescapeBytea @ 94 PQfreemem @ 95 PQtransactionStatus @ 96 PQparameterStatus @ 97 PQprotocolVersion @ 98 PQsetErrorVerbosity @ 99 PQsetNoticeReceiver @ 100 PQexecParams @ 101 PQsendQueryParams @ 102 PQputCopyData @ 103 PQputCopyEnd @ 104 PQgetCopyData @ 105 PQresultErrorField @ 106 PQftable @ 107 PQftablecol @ 108 PQfformat @ 109 PQexecPrepared @ 110 PQsendQueryPrepared @ 111 PQdsplen @ 112 PQserverVersion @ 113 PQgetssl @ 114 pg_char_to_encoding @ 115 pg_valid_server_encoding @ 116 pqsignal @ 117 PQprepare @ 118 PQsendPrepare @ 119 PQgetCancel @ 120 PQfreeCancel @ 121 PQcancel @ 122 lo_create @ 123 PQinitSSL @ 124 PQregisterThreadLock @ 125 PQescapeStringConn @ 126 PQescapeByteaConn @ 127 PQencryptPassword @ 128 PQisthreadsafe @ 129 enlargePQExpBuffer @ 130 PQnparams @ 131 PQparamtype @ 132 PQdescribePrepared @ 133 PQdescribePortal @ 134 PQsendDescribePrepared @ 135 PQsendDescribePortal @ 136 lo_truncate @ 137 PQconnectionUsedPassword @ 138 pg_valid_server_encoding_id @ 139 PQconnectionNeedsPassword @ 140 lo_import_with_oid @ 141 PQcopyResult @ 142 PQsetResultAttrs @ 143 PQsetvalue @ 144 PQresultAlloc @ 145 PQregisterEventProc @ 146 PQinstanceData @ 147 PQsetInstanceData @ 148 PQresultInstanceData @ 149 PQresultSetInstanceData @ 150 PQfireResultCreateEvents @ 151 PQconninfoParse @ 152 PQinitOpenSSL @ 153 PQescapeLiteral @ 154 PQescapeIdentifier @ 155 PQconnectdbParams @ 156 PQconnectStartParams @ 157 PQping @ 158 PQpingParams @ 159 PQlibVersion @ 160 RPostgreSQL/src/libpq/fe-auth.c0000644000176000001440000006465212124517222016035 0ustar ripleyusers/*------------------------------------------------------------------------- * * fe-auth.c * The front-end (client) authorization routines * * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION * src/interfaces/libpq/fe-auth.c * *------------------------------------------------------------------------- */ /* * INTERFACE ROUTINES * frontend (client) routines: * pg_fe_sendauth send authentication information * pg_fe_getauthname get user's name according to the client side * of the authentication system */ #include "postgres_fe.h" #ifdef WIN32 #include "win32.h" #else #include #include #include /* for MAXHOSTNAMELEN on most */ #include #ifdef HAVE_SYS_UCRED_H #include #endif #ifndef MAXHOSTNAMELEN #include /* for MAXHOSTNAMELEN on some */ #endif #include #endif #include "libpq-fe.h" #include "fe-auth.h" #include "libpq/md5.h" #ifdef KRB5 /* * MIT Kerberos authentication system - protocol version 5 */ #include /* Some old versions of Kerberos do not include in */ #if !defined(__COM_ERR_H) && !defined(__COM_ERR_H__) #include #endif /* * Heimdal doesn't have a free function for unparsed names. Just pass it to * standard free() which should work in these cases. */ #ifndef HAVE_KRB5_FREE_UNPARSED_NAME static void krb5_free_unparsed_name(krb5_context context, char *val) { free(val); } #endif /* * pg_an_to_ln -- return the local name corresponding to an authentication * name * * XXX Assumes that the first aname component is the user name. This is NOT * necessarily so, since an aname can actually be something out of your * worst X.400 nightmare, like * ORGANIZATION=U. C. Berkeley/NAME=Paul M. Aoki@CS.BERKELEY.EDU * Note that the MIT an_to_ln code does the same thing if you don't * provide an aname mapping database...it may be a better idea to use * krb5_an_to_ln, except that it punts if multiple components are found, * and we can't afford to punt. * * For WIN32, convert username to lowercase because the Win32 kerberos library * generates tickets with the username as the user entered it instead of as * it is entered in the directory. */ static char * pg_an_to_ln(char *aname) { char *p; if ((p = strchr(aname, '/')) || (p = strchr(aname, '@'))) *p = '\0'; #ifdef WIN32 for (p = aname; *p; p++) *p = pg_tolower((unsigned char) *p); #endif return aname; } /* * Various krb5 state which is not connection specific, and a flag to * indicate whether we have initialised it yet. */ /* static int pg_krb5_initialised; static krb5_context pg_krb5_context; static krb5_ccache pg_krb5_ccache; static krb5_principal pg_krb5_client; static char *pg_krb5_name; */ struct krb5_info { int pg_krb5_initialised; krb5_context pg_krb5_context; krb5_ccache pg_krb5_ccache; krb5_principal pg_krb5_client; char *pg_krb5_name; }; static int pg_krb5_init(PQExpBuffer errorMessage, struct krb5_info * info) { krb5_error_code retval; if (info->pg_krb5_initialised) return STATUS_OK; retval = krb5_init_context(&(info->pg_krb5_context)); if (retval) { printfPQExpBuffer(errorMessage, "pg_krb5_init: krb5_init_context: %s\n", error_message(retval)); return STATUS_ERROR; } retval = krb5_cc_default(info->pg_krb5_context, &(info->pg_krb5_ccache)); if (retval) { printfPQExpBuffer(errorMessage, "pg_krb5_init: krb5_cc_default: %s\n", error_message(retval)); krb5_free_context(info->pg_krb5_context); return STATUS_ERROR; } retval = krb5_cc_get_principal(info->pg_krb5_context, info->pg_krb5_ccache, &(info->pg_krb5_client)); if (retval) { printfPQExpBuffer(errorMessage, "pg_krb5_init: krb5_cc_get_principal: %s\n", error_message(retval)); krb5_cc_close(info->pg_krb5_context, info->pg_krb5_ccache); krb5_free_context(info->pg_krb5_context); return STATUS_ERROR; } retval = krb5_unparse_name(info->pg_krb5_context, info->pg_krb5_client, &(info->pg_krb5_name)); if (retval) { printfPQExpBuffer(errorMessage, "pg_krb5_init: krb5_unparse_name: %s\n", error_message(retval)); krb5_free_principal(info->pg_krb5_context, info->pg_krb5_client); krb5_cc_close(info->pg_krb5_context, info->pg_krb5_ccache); krb5_free_context(info->pg_krb5_context); return STATUS_ERROR; } info->pg_krb5_name = pg_an_to_ln(info->pg_krb5_name); info->pg_krb5_initialised = 1; return STATUS_OK; } static void pg_krb5_destroy(struct krb5_info * info) { krb5_free_principal(info->pg_krb5_context, info->pg_krb5_client); krb5_cc_close(info->pg_krb5_context, info->pg_krb5_ccache); krb5_free_unparsed_name(info->pg_krb5_context, info->pg_krb5_name); krb5_free_context(info->pg_krb5_context); } /* * pg_krb5_sendauth -- client routine to send authentication information to * the server */ static int pg_krb5_sendauth(PGconn *conn) { krb5_error_code retval; int ret; krb5_principal server; krb5_auth_context auth_context = NULL; krb5_error *err_ret = NULL; struct krb5_info info; info.pg_krb5_initialised = 0; if (!(conn->pghost && conn->pghost[0] != '\0')) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("host name must be specified\n")); return STATUS_ERROR; } ret = pg_krb5_init(&conn->errorMessage, &info); if (ret != STATUS_OK) return ret; retval = krb5_sname_to_principal(info.pg_krb5_context, conn->pghost, conn->krbsrvname, KRB5_NT_SRV_HST, &server); if (retval) { printfPQExpBuffer(&conn->errorMessage, "pg_krb5_sendauth: krb5_sname_to_principal: %s\n", error_message(retval)); pg_krb5_destroy(&info); return STATUS_ERROR; } /* * libpq uses a non-blocking socket. But kerberos needs a blocking socket, * and we have to block somehow to do mutual authentication anyway. So we * temporarily make it blocking. */ if (!pg_set_block(conn->sock)) { char sebuf[256]; printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not set socket to blocking mode: %s\n"), pqStrerror(errno, sebuf, sizeof(sebuf))); krb5_free_principal(info.pg_krb5_context, server); pg_krb5_destroy(&info); return STATUS_ERROR; } retval = krb5_sendauth(info.pg_krb5_context, &auth_context, (krb5_pointer) &conn->sock, (char *) conn->krbsrvname, info.pg_krb5_client, server, AP_OPTS_MUTUAL_REQUIRED, NULL, 0, /* no creds, use ccache instead */ info.pg_krb5_ccache, &err_ret, NULL, NULL); if (retval) { if (retval == KRB5_SENDAUTH_REJECTED && err_ret) { #if defined(HAVE_KRB5_ERROR_TEXT_DATA) printfPQExpBuffer(&conn->errorMessage, libpq_gettext("Kerberos 5 authentication rejected: %*s\n"), (int) err_ret->text.length, err_ret->text.data); #elif defined(HAVE_KRB5_ERROR_E_DATA) printfPQExpBuffer(&conn->errorMessage, libpq_gettext("Kerberos 5 authentication rejected: %*s\n"), (int) err_ret->e_data->length, (const char *) err_ret->e_data->data); #else #error "bogus configuration" #endif } else { printfPQExpBuffer(&conn->errorMessage, "krb5_sendauth: %s\n", error_message(retval)); } if (err_ret) krb5_free_error(info.pg_krb5_context, err_ret); ret = STATUS_ERROR; } krb5_free_principal(info.pg_krb5_context, server); if (!pg_set_noblock(conn->sock)) { char sebuf[256]; printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not restore non-blocking mode on socket: %s\n"), pqStrerror(errno, sebuf, sizeof(sebuf))); ret = STATUS_ERROR; } pg_krb5_destroy(&info); return ret; } #endif /* KRB5 */ #ifdef ENABLE_GSS /* * GSSAPI authentication system. */ #if defined(WIN32) && !defined(WIN32_ONLY_COMPILER) /* * MIT Kerberos GSSAPI DLL doesn't properly export the symbols for MingW * that contain the OIDs required. Redefine here, values copied * from src/athena/auth/krb5/src/lib/gssapi/generic/gssapi_generic.c */ static const gss_OID_desc GSS_C_NT_HOSTBASED_SERVICE_desc = {10, (void *) "\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x04"}; static GSS_DLLIMP gss_OID GSS_C_NT_HOSTBASED_SERVICE = &GSS_C_NT_HOSTBASED_SERVICE_desc; #endif /* * Fetch all errors of a specific type and append to "str". */ static void pg_GSS_error_int(PQExpBuffer str, const char *mprefix, OM_uint32 stat, int type) { OM_uint32 lmin_s; gss_buffer_desc lmsg; OM_uint32 msg_ctx = 0; do { gss_display_status(&lmin_s, stat, type, GSS_C_NO_OID, &msg_ctx, &lmsg); appendPQExpBuffer(str, "%s: %s\n", mprefix, (char *) lmsg.value); gss_release_buffer(&lmin_s, &lmsg); } while (msg_ctx); } /* * GSSAPI errors contain two parts; put both into conn->errorMessage. */ static void pg_GSS_error(const char *mprefix, PGconn *conn, OM_uint32 maj_stat, OM_uint32 min_stat) { resetPQExpBuffer(&conn->errorMessage); /* Fetch major error codes */ pg_GSS_error_int(&conn->errorMessage, mprefix, maj_stat, GSS_C_GSS_CODE); /* Add the minor codes as well */ pg_GSS_error_int(&conn->errorMessage, mprefix, min_stat, GSS_C_MECH_CODE); } /* * Continue GSS authentication with next token as needed. */ static int pg_GSS_continue(PGconn *conn) { OM_uint32 maj_stat, min_stat, lmin_s; maj_stat = gss_init_sec_context(&min_stat, GSS_C_NO_CREDENTIAL, &conn->gctx, conn->gtarg_nam, GSS_C_NO_OID, GSS_C_MUTUAL_FLAG, 0, GSS_C_NO_CHANNEL_BINDINGS, (conn->gctx == GSS_C_NO_CONTEXT) ? GSS_C_NO_BUFFER : &conn->ginbuf, NULL, &conn->goutbuf, NULL, NULL); if (conn->gctx != GSS_C_NO_CONTEXT) { free(conn->ginbuf.value); conn->ginbuf.value = NULL; conn->ginbuf.length = 0; } if (conn->goutbuf.length != 0) { /* * GSS generated data to send to the server. We don't care if it's the * first or subsequent packet, just send the same kind of password * packet. */ if (pqPacketSend(conn, 'p', conn->goutbuf.value, conn->goutbuf.length) != STATUS_OK) { gss_release_buffer(&lmin_s, &conn->goutbuf); return STATUS_ERROR; } } gss_release_buffer(&lmin_s, &conn->goutbuf); if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED) { pg_GSS_error(libpq_gettext("GSSAPI continuation error"), conn, maj_stat, min_stat); gss_release_name(&lmin_s, &conn->gtarg_nam); if (conn->gctx) gss_delete_sec_context(&lmin_s, &conn->gctx, GSS_C_NO_BUFFER); return STATUS_ERROR; } if (maj_stat == GSS_S_COMPLETE) gss_release_name(&lmin_s, &conn->gtarg_nam); return STATUS_OK; } /* * Send initial GSS authentication token */ static int pg_GSS_startup(PGconn *conn) { OM_uint32 maj_stat, min_stat; int maxlen; gss_buffer_desc temp_gbuf; if (!(conn->pghost && conn->pghost[0] != '\0')) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("host name must be specified\n")); return STATUS_ERROR; } if (conn->gctx) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("duplicate GSS authentication request\n")); return STATUS_ERROR; } /* * Import service principal name so the proper ticket can be acquired by * the GSSAPI system. */ maxlen = NI_MAXHOST + strlen(conn->krbsrvname) + 2; temp_gbuf.value = (char *) malloc(maxlen); snprintf(temp_gbuf.value, maxlen, "%s@%s", conn->krbsrvname, conn->pghost); temp_gbuf.length = strlen(temp_gbuf.value); maj_stat = gss_import_name(&min_stat, &temp_gbuf, GSS_C_NT_HOSTBASED_SERVICE, &conn->gtarg_nam); free(temp_gbuf.value); if (maj_stat != GSS_S_COMPLETE) { pg_GSS_error(libpq_gettext("GSSAPI name import error"), conn, maj_stat, min_stat); return STATUS_ERROR; } /* * Initial packet is the same as a continuation packet with no initial * context. */ conn->gctx = GSS_C_NO_CONTEXT; return pg_GSS_continue(conn); } #endif /* ENABLE_GSS */ #ifdef ENABLE_SSPI /* * SSPI authentication system (Windows only) */ static void pg_SSPI_error(PGconn *conn, const char *mprefix, SECURITY_STATUS r) { char sysmsg[256]; if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, r, 0, sysmsg, sizeof(sysmsg), NULL) == 0) printfPQExpBuffer(&conn->errorMessage, "%s: SSPI error %x", mprefix, (unsigned int) r); else printfPQExpBuffer(&conn->errorMessage, "%s: %s (%x)", mprefix, sysmsg, (unsigned int) r); } /* * Continue SSPI authentication with next token as needed. */ static int pg_SSPI_continue(PGconn *conn) { SECURITY_STATUS r; CtxtHandle newContext; ULONG contextAttr; SecBufferDesc inbuf; SecBufferDesc outbuf; SecBuffer OutBuffers[1]; SecBuffer InBuffers[1]; if (conn->sspictx != NULL) { /* * On runs other than the first we have some data to send. Put this * data in a SecBuffer type structure. */ inbuf.ulVersion = SECBUFFER_VERSION; inbuf.cBuffers = 1; inbuf.pBuffers = InBuffers; InBuffers[0].pvBuffer = conn->ginbuf.value; InBuffers[0].cbBuffer = conn->ginbuf.length; InBuffers[0].BufferType = SECBUFFER_TOKEN; } OutBuffers[0].pvBuffer = NULL; OutBuffers[0].BufferType = SECBUFFER_TOKEN; OutBuffers[0].cbBuffer = 0; outbuf.cBuffers = 1; outbuf.pBuffers = OutBuffers; outbuf.ulVersion = SECBUFFER_VERSION; r = InitializeSecurityContext(conn->sspicred, conn->sspictx, conn->sspitarget, ISC_REQ_ALLOCATE_MEMORY, 0, SECURITY_NETWORK_DREP, (conn->sspictx == NULL) ? NULL : &inbuf, 0, &newContext, &outbuf, &contextAttr, NULL); if (r != SEC_E_OK && r != SEC_I_CONTINUE_NEEDED) { pg_SSPI_error(conn, libpq_gettext("SSPI continuation error"), r); return STATUS_ERROR; } if (conn->sspictx == NULL) { /* On first run, transfer retreived context handle */ conn->sspictx = malloc(sizeof(CtxtHandle)); if (conn->sspictx == NULL) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("out of memory\n")); return STATUS_ERROR; } memcpy(conn->sspictx, &newContext, sizeof(CtxtHandle)); } else { /* * On subsequent runs when we had data to send, free buffers that * contained this data. */ free(conn->ginbuf.value); conn->ginbuf.value = NULL; conn->ginbuf.length = 0; } /* * If SSPI returned any data to be sent to the server (as it normally * would), send this data as a password packet. */ if (outbuf.cBuffers > 0) { if (outbuf.cBuffers != 1) { /* * This should never happen, at least not for Kerberos * authentication. Keep check in case it shows up with other * authentication methods later. */ printfPQExpBuffer(&conn->errorMessage, "SSPI returned invalid number of output buffers\n"); return STATUS_ERROR; } /* * If the negotiation is complete, there may be zero bytes to send. * The server is at this point not expecting any more data, so don't * send it. */ if (outbuf.pBuffers[0].cbBuffer > 0) { if (pqPacketSend(conn, 'p', outbuf.pBuffers[0].pvBuffer, outbuf.pBuffers[0].cbBuffer)) { FreeContextBuffer(outbuf.pBuffers[0].pvBuffer); return STATUS_ERROR; } } FreeContextBuffer(outbuf.pBuffers[0].pvBuffer); } /* Cleanup is handled by the code in freePGconn() */ return STATUS_OK; } /* * Send initial SSPI authentication token. * If use_negotiate is 0, use kerberos authentication package which is * compatible with Unix. If use_negotiate is 1, use the negotiate package * which supports both kerberos and NTLM, but is not compatible with Unix. */ static int pg_SSPI_startup(PGconn *conn, int use_negotiate) { SECURITY_STATUS r; TimeStamp expire; conn->sspictx = NULL; /* * Retreive credentials handle */ conn->sspicred = malloc(sizeof(CredHandle)); if (conn->sspicred == NULL) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("out of memory\n")); return STATUS_ERROR; } r = AcquireCredentialsHandle(NULL, use_negotiate ? "negotiate" : "kerberos", SECPKG_CRED_OUTBOUND, NULL, NULL, NULL, NULL, conn->sspicred, &expire); if (r != SEC_E_OK) { pg_SSPI_error(conn, libpq_gettext("could not acquire SSPI credentials"), r); free(conn->sspicred); conn->sspicred = NULL; return STATUS_ERROR; } /* * Compute target principal name. SSPI has a different format from GSSAPI, * but not more complex. We can skip the @REALM part, because Windows will * fill that in for us automatically. */ if (!(conn->pghost && conn->pghost[0] != '\0')) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("host name must be specified\n")); return STATUS_ERROR; } conn->sspitarget = malloc(strlen(conn->krbsrvname) + strlen(conn->pghost) + 2); if (!conn->sspitarget) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("out of memory\n")); return STATUS_ERROR; } sprintf(conn->sspitarget, "%s/%s", conn->krbsrvname, conn->pghost); /* * Indicate that we're in SSPI authentication mode to make sure that * pg_SSPI_continue is called next time in the negotiation. */ conn->usesspi = 1; return pg_SSPI_continue(conn); } #endif /* ENABLE_SSPI */ /* * Respond to AUTH_REQ_SCM_CREDS challenge. * * Note: this is dead code as of Postgres 9.1, because current backends will * never send this challenge. But we must keep it as long as libpq needs to * interoperate with pre-9.1 servers. It is believed to be needed only on * Debian/kFreeBSD (ie, FreeBSD kernel with Linux userland, so that the * getpeereid() function isn't provided by libc). */ static int pg_local_sendauth(PGconn *conn) { #ifdef HAVE_STRUCT_CMSGCRED char buf; struct iovec iov; struct msghdr msg; struct cmsghdr *cmsg; union { struct cmsghdr hdr; unsigned char buf[CMSG_SPACE(sizeof(struct cmsgcred))]; } cmsgbuf; /* * The backend doesn't care what we send here, but it wants exactly one * character to force recvmsg() to block and wait for us. */ buf = '\0'; iov.iov_base = &buf; iov.iov_len = 1; memset(&msg, 0, sizeof(msg)); msg.msg_iov = &iov; msg.msg_iovlen = 1; /* We must set up a message that will be filled in by kernel */ memset(&cmsgbuf, 0, sizeof(cmsgbuf)); msg.msg_control = &cmsgbuf.buf; msg.msg_controllen = sizeof(cmsgbuf.buf); cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_len = CMSG_LEN(sizeof(struct cmsgcred)); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_CREDS; if (sendmsg(conn->sock, &msg, 0) == -1) { char sebuf[256]; printfPQExpBuffer(&conn->errorMessage, "pg_local_sendauth: sendmsg: %s\n", pqStrerror(errno, sebuf, sizeof(sebuf))); return STATUS_ERROR; } return STATUS_OK; #else printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SCM_CRED authentication method not supported\n")); return STATUS_ERROR; #endif } static int pg_password_sendauth(PGconn *conn, const char *password, AuthRequest areq) { int ret; char *crypt_pwd; /* Encrypt the password if needed. */ switch (areq) { case AUTH_REQ_MD5: { char *crypt_pwd2; /* Allocate enough space for two MD5 hashes */ crypt_pwd = malloc(2 * (MD5_PASSWD_LEN + 1)); if (!crypt_pwd) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("out of memory\n")); return STATUS_ERROR; } crypt_pwd2 = crypt_pwd + MD5_PASSWD_LEN + 1; if (!pg_md5_encrypt(password, conn->pguser, strlen(conn->pguser), crypt_pwd2)) { free(crypt_pwd); return STATUS_ERROR; } if (!pg_md5_encrypt(crypt_pwd2 + strlen("md5"), conn->md5Salt, sizeof(conn->md5Salt), crypt_pwd)) { free(crypt_pwd); return STATUS_ERROR; } break; } case AUTH_REQ_PASSWORD: /* discard const so we can assign it */ crypt_pwd = (char *) password; break; default: return STATUS_ERROR; } /* Packet has a message type as of protocol 3.0 */ if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3) ret = pqPacketSend(conn, 'p', crypt_pwd, strlen(crypt_pwd) + 1); else ret = pqPacketSend(conn, 0, crypt_pwd, strlen(crypt_pwd) + 1); if (areq == AUTH_REQ_MD5) free(crypt_pwd); return ret; } /* * pg_fe_sendauth * client demux routine for outgoing authentication information */ int pg_fe_sendauth(AuthRequest areq, PGconn *conn) { switch (areq) { case AUTH_REQ_OK: break; case AUTH_REQ_KRB4: printfPQExpBuffer(&conn->errorMessage, libpq_gettext("Kerberos 4 authentication not supported\n")); return STATUS_ERROR; case AUTH_REQ_KRB5: #ifdef KRB5 pglock_thread(); if (pg_krb5_sendauth(conn) != STATUS_OK) { /* Error message already filled in */ pgunlock_thread(); return STATUS_ERROR; } pgunlock_thread(); break; #else printfPQExpBuffer(&conn->errorMessage, libpq_gettext("Kerberos 5 authentication not supported\n")); return STATUS_ERROR; #endif #if defined(ENABLE_GSS) || defined(ENABLE_SSPI) case AUTH_REQ_GSS: #if !defined(ENABLE_SSPI) /* no native SSPI, so use GSSAPI library for it */ case AUTH_REQ_SSPI: #endif { int r; pglock_thread(); /* * If we have both GSS and SSPI support compiled in, use SSPI * support by default. This is overridable by a connection * string parameter. Note that when using SSPI we still leave * the negotiate parameter off, since we want SSPI to use the * GSSAPI kerberos protocol. For actual SSPI negotiate * protocol, we use AUTH_REQ_SSPI. */ #if defined(ENABLE_GSS) && defined(ENABLE_SSPI) if (conn->gsslib && (pg_strcasecmp(conn->gsslib, "gssapi") == 0)) r = pg_GSS_startup(conn); else r = pg_SSPI_startup(conn, 0); #elif defined(ENABLE_GSS) && !defined(ENABLE_SSPI) r = pg_GSS_startup(conn); #elif !defined(ENABLE_GSS) && defined(ENABLE_SSPI) r = pg_SSPI_startup(conn, 0); #endif if (r != STATUS_OK) { /* Error message already filled in. */ pgunlock_thread(); return STATUS_ERROR; } pgunlock_thread(); } break; case AUTH_REQ_GSS_CONT: { int r; pglock_thread(); #if defined(ENABLE_GSS) && defined(ENABLE_SSPI) if (conn->usesspi) r = pg_SSPI_continue(conn); else r = pg_GSS_continue(conn); #elif defined(ENABLE_GSS) && !defined(ENABLE_SSPI) r = pg_GSS_continue(conn); #elif !defined(ENABLE_GSS) && defined(ENABLE_SSPI) r = pg_SSPI_continue(conn); #endif if (r != STATUS_OK) { /* Error message already filled in. */ pgunlock_thread(); return STATUS_ERROR; } pgunlock_thread(); } break; #else /* defined(ENABLE_GSS) || defined(ENABLE_SSPI) */ /* No GSSAPI *or* SSPI support */ case AUTH_REQ_GSS: case AUTH_REQ_GSS_CONT: printfPQExpBuffer(&conn->errorMessage, libpq_gettext("GSSAPI authentication not supported\n")); return STATUS_ERROR; #endif /* defined(ENABLE_GSS) || defined(ENABLE_SSPI) */ #ifdef ENABLE_SSPI case AUTH_REQ_SSPI: /* * SSPI has it's own startup message so libpq can decide which * method to use. Indicate to pg_SSPI_startup that we want SSPI * negotiation instead of Kerberos. */ pglock_thread(); if (pg_SSPI_startup(conn, 1) != STATUS_OK) { /* Error message already filled in. */ pgunlock_thread(); return STATUS_ERROR; } pgunlock_thread(); break; #else /* * No SSPI support. However, if we have GSSAPI but not SSPI * support, AUTH_REQ_SSPI will have been handled in the codepath * for AUTH_REQ_GSSAPI above, so don't duplicate the case label in * that case. */ #if !defined(ENABLE_GSS) case AUTH_REQ_SSPI: printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSPI authentication not supported\n")); return STATUS_ERROR; #endif /* !define(ENABLE_GSSAPI) */ #endif /* ENABLE_SSPI */ case AUTH_REQ_CRYPT: printfPQExpBuffer(&conn->errorMessage, libpq_gettext("Crypt authentication not supported\n")); return STATUS_ERROR; case AUTH_REQ_MD5: case AUTH_REQ_PASSWORD: conn->password_needed = true; if (conn->pgpass == NULL || conn->pgpass[0] == '\0') { printfPQExpBuffer(&conn->errorMessage, PQnoPasswordSupplied); return STATUS_ERROR; } if (pg_password_sendauth(conn, conn->pgpass, areq) != STATUS_OK) { printfPQExpBuffer(&conn->errorMessage, "fe_sendauth: error sending password authentication\n"); return STATUS_ERROR; } break; case AUTH_REQ_SCM_CREDS: if (pg_local_sendauth(conn) != STATUS_OK) return STATUS_ERROR; break; default: printfPQExpBuffer(&conn->errorMessage, libpq_gettext("authentication method %u not supported\n"), areq); return STATUS_ERROR; } return STATUS_OK; } /* * pg_fe_getauthname -- returns a pointer to dynamic space containing whatever * name the user has authenticated to the system * * if there is an error, return NULL with an error message in errorMessage */ char * pg_fe_getauthname(PQExpBuffer errorMessage) { const char *name = NULL; char *authn; #ifdef WIN32 char username[128]; DWORD namesize = sizeof(username) - 1; #else char pwdbuf[BUFSIZ]; struct passwd pwdstr; struct passwd *pw = NULL; #endif /* * Some users are using configure --enable-thread-safety-force, so we * might as well do the locking within our library to protect * pqGetpwuid(). In fact, application developers can use getpwuid() in * their application if they use the locking call we provide, or install * their own locking function using PQregisterThreadLock(). */ pglock_thread(); if (!name) { #ifdef WIN32 if (GetUserName(username, &namesize)) name = username; #else if (pqGetpwuid(geteuid(), &pwdstr, pwdbuf, sizeof(pwdbuf), &pw) == 0) name = pw->pw_name; #endif } authn = name ? strdup(name) : NULL; pgunlock_thread(); return authn; } /* * PQencryptPassword -- exported routine to encrypt a password * * This is intended to be used by client applications that wish to send * commands like ALTER USER joe PASSWORD 'pwd'. The password need not * be sent in cleartext if it is encrypted on the client side. This is * good because it ensures the cleartext password won't end up in logs, * pg_stat displays, etc. We export the function so that clients won't * be dependent on low-level details like whether the enceyption is MD5 * or something else. * * Arguments are the cleartext password, and the SQL name of the user it * is for. * * Return value is a malloc'd string, or NULL if out-of-memory. The client * may assume the string doesn't contain any special characters that would * require escaping. */ char * PQencryptPassword(const char *passwd, const char *user) { char *crypt_pwd; crypt_pwd = malloc(MD5_PASSWD_LEN + 1); if (!crypt_pwd) return NULL; if (!pg_md5_encrypt(passwd, user, strlen(user), crypt_pwd)) { free(crypt_pwd); return NULL; } return crypt_pwd; } RPostgreSQL/src/libpq/wchar.c0000644000176000001440000010622312124517222015577 0ustar ripleyusers/* * conversion functions between pg_wchar and multibyte streams. * Tatsuo Ishii * src/backend/utils/mb/wchar.c * */ /* can be used in either frontend or backend */ #ifdef FRONTEND #include "postgres_fe.h" #define Assert(condition) #else #include "postgres.h" #endif #include "mb/pg_wchar.h" /* * conversion to pg_wchar is done by "table driven." * to add an encoding support, define mb2wchar_with_len(), mblen(), dsplen() * for the particular encoding. Note that if the encoding is only * supported in the client, you don't need to define * mb2wchar_with_len() function (SJIS is the case). * * These functions generally assume that their input is validly formed. * The "verifier" functions, further down in the file, have to be more * paranoid. We expect that mblen() does not need to examine more than * the first byte of the character to discover the correct length. * * Note: for the display output of psql to work properly, the return values * of the dsplen functions must conform to the Unicode standard. In particular * the NUL character is zero width and control characters are generally * width -1. It is recommended that non-ASCII encodings refer their ASCII * subset to the ASCII routines to ensure consistency. */ /* * SQL/ASCII */ static int pg_ascii2wchar_with_len(const unsigned char *from, pg_wchar *to, int len) { int cnt = 0; while (len > 0 && *from) { *to++ = *from++; len--; cnt++; } *to = 0; return cnt; } static int pg_ascii_mblen(const unsigned char *s) { return 1; } static int pg_ascii_dsplen(const unsigned char *s) { if (*s == '\0') return 0; if (*s < 0x20 || *s == 0x7f) return -1; return 1; } /* * EUC */ static int pg_euc2wchar_with_len(const unsigned char *from, pg_wchar *to, int len) { int cnt = 0; while (len > 0 && *from) { if (*from == SS2 && len >= 2) /* JIS X 0201 (so called "1 byte * KANA") */ { from++; *to = (SS2 << 8) | *from++; len -= 2; } else if (*from == SS3 && len >= 3) /* JIS X 0212 KANJI */ { from++; *to = (SS3 << 16) | (*from++ << 8); *to |= *from++; len -= 3; } else if (IS_HIGHBIT_SET(*from) && len >= 2) /* JIS X 0208 KANJI */ { *to = *from++ << 8; *to |= *from++; len -= 2; } else /* must be ASCII */ { *to = *from++; len--; } to++; cnt++; } *to = 0; return cnt; } static inline int pg_euc_mblen(const unsigned char *s) { int len; if (*s == SS2) len = 2; else if (*s == SS3) len = 3; else if (IS_HIGHBIT_SET(*s)) len = 2; else len = 1; return len; } static inline int pg_euc_dsplen(const unsigned char *s) { int len; if (*s == SS2) len = 2; else if (*s == SS3) len = 2; else if (IS_HIGHBIT_SET(*s)) len = 2; else len = pg_ascii_dsplen(s); return len; } /* * EUC_JP */ static int pg_eucjp2wchar_with_len(const unsigned char *from, pg_wchar *to, int len) { return pg_euc2wchar_with_len(from, to, len); } static int pg_eucjp_mblen(const unsigned char *s) { return pg_euc_mblen(s); } static int pg_eucjp_dsplen(const unsigned char *s) { int len; if (*s == SS2) len = 1; else if (*s == SS3) len = 2; else if (IS_HIGHBIT_SET(*s)) len = 2; else len = pg_ascii_dsplen(s); return len; } /* * EUC_KR */ static int pg_euckr2wchar_with_len(const unsigned char *from, pg_wchar *to, int len) { return pg_euc2wchar_with_len(from, to, len); } static int pg_euckr_mblen(const unsigned char *s) { return pg_euc_mblen(s); } static int pg_euckr_dsplen(const unsigned char *s) { return pg_euc_dsplen(s); } /* * EUC_CN * */ static int pg_euccn2wchar_with_len(const unsigned char *from, pg_wchar *to, int len) { int cnt = 0; while (len > 0 && *from) { if (*from == SS2 && len >= 3) /* code set 2 (unused?) */ { from++; *to = (SS2 << 16) | (*from++ << 8); *to |= *from++; len -= 3; } else if (*from == SS3 && len >= 3) /* code set 3 (unsed ?) */ { from++; *to = (SS3 << 16) | (*from++ << 8); *to |= *from++; len -= 3; } else if (IS_HIGHBIT_SET(*from) && len >= 2) /* code set 1 */ { *to = *from++ << 8; *to |= *from++; len -= 2; } else { *to = *from++; len--; } to++; cnt++; } *to = 0; return cnt; } static int pg_euccn_mblen(const unsigned char *s) { int len; if (IS_HIGHBIT_SET(*s)) len = 2; else len = 1; return len; } static int pg_euccn_dsplen(const unsigned char *s) { int len; if (IS_HIGHBIT_SET(*s)) len = 2; else len = pg_ascii_dsplen(s); return len; } /* * EUC_TW * */ static int pg_euctw2wchar_with_len(const unsigned char *from, pg_wchar *to, int len) { int cnt = 0; while (len > 0 && *from) { if (*from == SS2 && len >= 4) /* code set 2 */ { from++; *to = (((uint32) SS2) << 24) | (*from++ << 16); *to |= *from++ << 8; *to |= *from++; len -= 4; } else if (*from == SS3 && len >= 3) /* code set 3 (unused?) */ { from++; *to = (SS3 << 16) | (*from++ << 8); *to |= *from++; len -= 3; } else if (IS_HIGHBIT_SET(*from) && len >= 2) /* code set 2 */ { *to = *from++ << 8; *to |= *from++; len -= 2; } else { *to = *from++; len--; } to++; cnt++; } *to = 0; return cnt; } static int pg_euctw_mblen(const unsigned char *s) { int len; if (*s == SS2) len = 4; else if (*s == SS3) len = 3; else if (IS_HIGHBIT_SET(*s)) len = 2; else len = 1; return len; } static int pg_euctw_dsplen(const unsigned char *s) { int len; if (*s == SS2) len = 2; else if (*s == SS3) len = 2; else if (IS_HIGHBIT_SET(*s)) len = 2; else len = pg_ascii_dsplen(s); return len; } /* * JOHAB */ static int pg_johab_mblen(const unsigned char *s) { return pg_euc_mblen(s); } static int pg_johab_dsplen(const unsigned char *s) { return pg_euc_dsplen(s); } /* * convert UTF8 string to pg_wchar (UCS-4) * caller must allocate enough space for "to", including a trailing zero! * len: length of from. * "from" not necessarily null terminated. */ static int pg_utf2wchar_with_len(const unsigned char *from, pg_wchar *to, int len) { int cnt = 0; uint32 c1, c2, c3, c4; while (len > 0 && *from) { if ((*from & 0x80) == 0) { *to = *from++; len--; } else if ((*from & 0xe0) == 0xc0) { if (len < 2) break; /* drop trailing incomplete char */ c1 = *from++ & 0x1f; c2 = *from++ & 0x3f; *to = (c1 << 6) | c2; len -= 2; } else if ((*from & 0xf0) == 0xe0) { if (len < 3) break; /* drop trailing incomplete char */ c1 = *from++ & 0x0f; c2 = *from++ & 0x3f; c3 = *from++ & 0x3f; *to = (c1 << 12) | (c2 << 6) | c3; len -= 3; } else if ((*from & 0xf8) == 0xf0) { if (len < 4) break; /* drop trailing incomplete char */ c1 = *from++ & 0x07; c2 = *from++ & 0x3f; c3 = *from++ & 0x3f; c4 = *from++ & 0x3f; *to = (c1 << 18) | (c2 << 12) | (c3 << 6) | c4; len -= 4; } else { /* treat a bogus char as length 1; not ours to raise error */ *to = *from++; len--; } to++; cnt++; } *to = 0; return cnt; } /* * Map a Unicode code point to UTF-8. utf8string must have 4 bytes of * space allocated. */ unsigned char * unicode_to_utf8(pg_wchar c, unsigned char *utf8string) { if (c <= 0x7F) { utf8string[0] = c; } else if (c <= 0x7FF) { utf8string[0] = 0xC0 | ((c >> 6) & 0x1F); utf8string[1] = 0x80 | (c & 0x3F); } else if (c <= 0xFFFF) { utf8string[0] = 0xE0 | ((c >> 12) & 0x0F); utf8string[1] = 0x80 | ((c >> 6) & 0x3F); utf8string[2] = 0x80 | (c & 0x3F); } else { utf8string[0] = 0xF0 | ((c >> 18) & 0x07); utf8string[1] = 0x80 | ((c >> 12) & 0x3F); utf8string[2] = 0x80 | ((c >> 6) & 0x3F); utf8string[3] = 0x80 | (c & 0x3F); } return utf8string; } /* * Return the byte length of a UTF8 character pointed to by s * * Note: in the current implementation we do not support UTF8 sequences * of more than 4 bytes; hence do NOT return a value larger than 4. * We return "1" for any leading byte that is either flat-out illegal or * indicates a length larger than we support. * * pg_utf2wchar_with_len(), utf8_to_unicode(), pg_utf8_islegal(), and perhaps * other places would need to be fixed to change this. */ int pg_utf_mblen(const unsigned char *s) { int len; if ((*s & 0x80) == 0) len = 1; else if ((*s & 0xe0) == 0xc0) len = 2; else if ((*s & 0xf0) == 0xe0) len = 3; else if ((*s & 0xf8) == 0xf0) len = 4; #ifdef NOT_USED else if ((*s & 0xfc) == 0xf8) len = 5; else if ((*s & 0xfe) == 0xfc) len = 6; #endif else len = 1; return len; } /* * This is an implementation of wcwidth() and wcswidth() as defined in * "The Single UNIX Specification, Version 2, The Open Group, 1997" * * * Markus Kuhn -- 2001-09-08 -- public domain * * customised for PostgreSQL * * original available at : http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c */ struct mbinterval { unsigned short first; unsigned short last; }; /* auxiliary function for binary search in interval table */ static int mbbisearch(pg_wchar ucs, const struct mbinterval * table, int max) { int min = 0; int mid; if (ucs < table[0].first || ucs > table[max].last) return 0; while (max >= min) { mid = (min + max) / 2; if (ucs > table[mid].last) min = mid + 1; else if (ucs < table[mid].first) max = mid - 1; else return 1; } return 0; } /* The following functions define the column width of an ISO 10646 * character as follows: * * - The null character (U+0000) has a column width of 0. * * - Other C0/C1 control characters and DEL will lead to a return * value of -1. * * - Non-spacing and enclosing combining characters (general * category code Mn or Me in the Unicode database) have a * column width of 0. * * - Other format characters (general category code Cf in the Unicode * database) and ZERO WIDTH SPACE (U+200B) have a column width of 0. * * - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF) * have a column width of 0. * * - Spacing characters in the East Asian Wide (W) or East Asian * FullWidth (F) category as defined in Unicode Technical * Report #11 have a column width of 2. * * - All remaining characters (including all printable * ISO 8859-1 and WGL4 characters, Unicode control characters, * etc.) have a column width of 1. * * This implementation assumes that wchar_t characters are encoded * in ISO 10646. */ static int ucs_wcwidth(pg_wchar ucs) { /* sorted list of non-overlapping intervals of non-spacing characters */ static const struct mbinterval combining[] = { {0x0300, 0x034E}, {0x0360, 0x0362}, {0x0483, 0x0486}, {0x0488, 0x0489}, {0x0591, 0x05A1}, {0x05A3, 0x05B9}, {0x05BB, 0x05BD}, {0x05BF, 0x05BF}, {0x05C1, 0x05C2}, {0x05C4, 0x05C4}, {0x064B, 0x0655}, {0x0670, 0x0670}, {0x06D6, 0x06E4}, {0x06E7, 0x06E8}, {0x06EA, 0x06ED}, {0x070F, 0x070F}, {0x0711, 0x0711}, {0x0730, 0x074A}, {0x07A6, 0x07B0}, {0x0901, 0x0902}, {0x093C, 0x093C}, {0x0941, 0x0948}, {0x094D, 0x094D}, {0x0951, 0x0954}, {0x0962, 0x0963}, {0x0981, 0x0981}, {0x09BC, 0x09BC}, {0x09C1, 0x09C4}, {0x09CD, 0x09CD}, {0x09E2, 0x09E3}, {0x0A02, 0x0A02}, {0x0A3C, 0x0A3C}, {0x0A41, 0x0A42}, {0x0A47, 0x0A48}, {0x0A4B, 0x0A4D}, {0x0A70, 0x0A71}, {0x0A81, 0x0A82}, {0x0ABC, 0x0ABC}, {0x0AC1, 0x0AC5}, {0x0AC7, 0x0AC8}, {0x0ACD, 0x0ACD}, {0x0B01, 0x0B01}, {0x0B3C, 0x0B3C}, {0x0B3F, 0x0B3F}, {0x0B41, 0x0B43}, {0x0B4D, 0x0B4D}, {0x0B56, 0x0B56}, {0x0B82, 0x0B82}, {0x0BC0, 0x0BC0}, {0x0BCD, 0x0BCD}, {0x0C3E, 0x0C40}, {0x0C46, 0x0C48}, {0x0C4A, 0x0C4D}, {0x0C55, 0x0C56}, {0x0CBF, 0x0CBF}, {0x0CC6, 0x0CC6}, {0x0CCC, 0x0CCD}, {0x0D41, 0x0D43}, {0x0D4D, 0x0D4D}, {0x0DCA, 0x0DCA}, {0x0DD2, 0x0DD4}, {0x0DD6, 0x0DD6}, {0x0E31, 0x0E31}, {0x0E34, 0x0E3A}, {0x0E47, 0x0E4E}, {0x0EB1, 0x0EB1}, {0x0EB4, 0x0EB9}, {0x0EBB, 0x0EBC}, {0x0EC8, 0x0ECD}, {0x0F18, 0x0F19}, {0x0F35, 0x0F35}, {0x0F37, 0x0F37}, {0x0F39, 0x0F39}, {0x0F71, 0x0F7E}, {0x0F80, 0x0F84}, {0x0F86, 0x0F87}, {0x0F90, 0x0F97}, {0x0F99, 0x0FBC}, {0x0FC6, 0x0FC6}, {0x102D, 0x1030}, {0x1032, 0x1032}, {0x1036, 0x1037}, {0x1039, 0x1039}, {0x1058, 0x1059}, {0x1160, 0x11FF}, {0x17B7, 0x17BD}, {0x17C6, 0x17C6}, {0x17C9, 0x17D3}, {0x180B, 0x180E}, {0x18A9, 0x18A9}, {0x200B, 0x200F}, {0x202A, 0x202E}, {0x206A, 0x206F}, {0x20D0, 0x20E3}, {0x302A, 0x302F}, {0x3099, 0x309A}, {0xFB1E, 0xFB1E}, {0xFE20, 0xFE23}, {0xFEFF, 0xFEFF}, {0xFFF9, 0xFFFB} }; /* test for 8-bit control characters */ if (ucs == 0) return 0; if (ucs < 0x20 || (ucs >= 0x7f && ucs < 0xa0) || ucs > 0x0010ffff) return -1; /* binary search in table of non-spacing characters */ if (mbbisearch(ucs, combining, sizeof(combining) / sizeof(struct mbinterval) - 1)) return 0; /* * if we arrive here, ucs is not a combining or C0/C1 control character */ return 1 + (ucs >= 0x1100 && (ucs <= 0x115f || /* Hangul Jamo init. consonants */ (ucs >= 0x2e80 && ucs <= 0xa4cf && (ucs & ~0x0011) != 0x300a && ucs != 0x303f) || /* CJK ... Yi */ (ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */ (ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility * Ideographs */ (ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */ (ucs >= 0xff00 && ucs <= 0xff5f) || /* Fullwidth Forms */ (ucs >= 0xffe0 && ucs <= 0xffe6) || (ucs >= 0x20000 && ucs <= 0x2ffff))); } /* * Convert a UTF-8 character to a Unicode code point. * This is a one-character version of pg_utf2wchar_with_len. * * No error checks here, c must point to a long-enough string. */ pg_wchar utf8_to_unicode(const unsigned char *c) { if ((*c & 0x80) == 0) return (pg_wchar) c[0]; else if ((*c & 0xe0) == 0xc0) return (pg_wchar) (((c[0] & 0x1f) << 6) | (c[1] & 0x3f)); else if ((*c & 0xf0) == 0xe0) return (pg_wchar) (((c[0] & 0x0f) << 12) | ((c[1] & 0x3f) << 6) | (c[2] & 0x3f)); else if ((*c & 0xf8) == 0xf0) return (pg_wchar) (((c[0] & 0x07) << 18) | ((c[1] & 0x3f) << 12) | ((c[2] & 0x3f) << 6) | (c[3] & 0x3f)); else /* that is an invalid code on purpose */ return 0xffffffff; } static int pg_utf_dsplen(const unsigned char *s) { return ucs_wcwidth(utf8_to_unicode(s)); } /* * convert mule internal code to pg_wchar * caller should allocate enough space for "to" * len: length of from. * "from" not necessarily null terminated. */ static int pg_mule2wchar_with_len(const unsigned char *from, pg_wchar *to, int len) { int cnt = 0; while (len > 0 && *from) { if (IS_LC1(*from) && len >= 2) { *to = *from++ << 16; *to |= *from++; len -= 2; } else if (IS_LCPRV1(*from) && len >= 3) { from++; *to = *from++ << 16; *to |= *from++; len -= 3; } else if (IS_LC2(*from) && len >= 3) { *to = *from++ << 16; *to |= *from++ << 8; *to |= *from++; len -= 3; } else if (IS_LCPRV2(*from) && len >= 4) { from++; *to = *from++ << 16; *to |= *from++ << 8; *to |= *from++; len -= 4; } else { /* assume ASCII */ *to = (unsigned char) *from++; len--; } to++; cnt++; } *to = 0; return cnt; } int pg_mule_mblen(const unsigned char *s) { int len; if (IS_LC1(*s)) len = 2; else if (IS_LCPRV1(*s)) len = 3; else if (IS_LC2(*s)) len = 3; else if (IS_LCPRV2(*s)) len = 4; else len = 1; /* assume ASCII */ return len; } static int pg_mule_dsplen(const unsigned char *s) { int len; if (IS_LC1(*s)) len = 1; else if (IS_LCPRV1(*s)) len = 1; else if (IS_LC2(*s)) len = 2; else if (IS_LCPRV2(*s)) len = 2; else len = 1; /* assume ASCII */ return len; } /* * ISO8859-1 */ static int pg_latin12wchar_with_len(const unsigned char *from, pg_wchar *to, int len) { int cnt = 0; while (len > 0 && *from) { *to++ = *from++; len--; cnt++; } *to = 0; return cnt; } static int pg_latin1_mblen(const unsigned char *s) { return 1; } static int pg_latin1_dsplen(const unsigned char *s) { return pg_ascii_dsplen(s); } /* * SJIS */ static int pg_sjis_mblen(const unsigned char *s) { int len; if (*s >= 0xa1 && *s <= 0xdf) len = 1; /* 1 byte kana? */ else if (IS_HIGHBIT_SET(*s)) len = 2; /* kanji? */ else len = 1; /* should be ASCII */ return len; } static int pg_sjis_dsplen(const unsigned char *s) { int len; if (*s >= 0xa1 && *s <= 0xdf) len = 1; /* 1 byte kana? */ else if (IS_HIGHBIT_SET(*s)) len = 2; /* kanji? */ else len = pg_ascii_dsplen(s); /* should be ASCII */ return len; } /* * Big5 */ static int pg_big5_mblen(const unsigned char *s) { int len; if (IS_HIGHBIT_SET(*s)) len = 2; /* kanji? */ else len = 1; /* should be ASCII */ return len; } static int pg_big5_dsplen(const unsigned char *s) { int len; if (IS_HIGHBIT_SET(*s)) len = 2; /* kanji? */ else len = pg_ascii_dsplen(s); /* should be ASCII */ return len; } /* * GBK */ static int pg_gbk_mblen(const unsigned char *s) { int len; if (IS_HIGHBIT_SET(*s)) len = 2; /* kanji? */ else len = 1; /* should be ASCII */ return len; } static int pg_gbk_dsplen(const unsigned char *s) { int len; if (IS_HIGHBIT_SET(*s)) len = 2; /* kanji? */ else len = pg_ascii_dsplen(s); /* should be ASCII */ return len; } /* * UHC */ static int pg_uhc_mblen(const unsigned char *s) { int len; if (IS_HIGHBIT_SET(*s)) len = 2; /* 2byte? */ else len = 1; /* should be ASCII */ return len; } static int pg_uhc_dsplen(const unsigned char *s) { int len; if (IS_HIGHBIT_SET(*s)) len = 2; /* 2byte? */ else len = pg_ascii_dsplen(s); /* should be ASCII */ return len; } /* * * GB18030 * * Added by Bill Huang , * */ static int pg_gb18030_mblen(const unsigned char *s) { int len; if (!IS_HIGHBIT_SET(*s)) len = 1; /* ASCII */ else { if ((*(s + 1) >= 0x40 && *(s + 1) <= 0x7e) || (*(s + 1) >= 0x80 && *(s + 1) <= 0xfe)) len = 2; else if (*(s + 1) >= 0x30 && *(s + 1) <= 0x39) len = 4; else len = 2; } return len; } static int pg_gb18030_dsplen(const unsigned char *s) { int len; if (IS_HIGHBIT_SET(*s)) len = 2; else len = pg_ascii_dsplen(s); /* ASCII */ return len; } /* *------------------------------------------------------------------- * multibyte sequence validators * * These functions accept "s", a pointer to the first byte of a string, * and "len", the remaining length of the string. If there is a validly * encoded character beginning at *s, return its length in bytes; else * return -1. * * The functions can assume that len > 0 and that *s != '\0', but they must * test for and reject zeroes in any additional bytes of a multibyte character. * * Note that this definition allows the function for a single-byte * encoding to be just "return 1". *------------------------------------------------------------------- */ static int pg_ascii_verifier(const unsigned char *s, int len) { return 1; } #define IS_EUC_RANGE_VALID(c) ((c) >= 0xa1 && (c) <= 0xfe) static int pg_eucjp_verifier(const unsigned char *s, int len) { int l; unsigned char c1, c2; c1 = *s++; switch (c1) { case SS2: /* JIS X 0201 */ l = 2; if (l > len) return -1; c2 = *s++; if (c2 < 0xa1 || c2 > 0xdf) return -1; break; case SS3: /* JIS X 0212 */ l = 3; if (l > len) return -1; c2 = *s++; if (!IS_EUC_RANGE_VALID(c2)) return -1; c2 = *s++; if (!IS_EUC_RANGE_VALID(c2)) return -1; break; default: if (IS_HIGHBIT_SET(c1)) /* JIS X 0208? */ { l = 2; if (l > len) return -1; if (!IS_EUC_RANGE_VALID(c1)) return -1; c2 = *s++; if (!IS_EUC_RANGE_VALID(c2)) return -1; } else /* must be ASCII */ { l = 1; } break; } return l; } static int pg_euckr_verifier(const unsigned char *s, int len) { int l; unsigned char c1, c2; c1 = *s++; if (IS_HIGHBIT_SET(c1)) { l = 2; if (l > len) return -1; if (!IS_EUC_RANGE_VALID(c1)) return -1; c2 = *s++; if (!IS_EUC_RANGE_VALID(c2)) return -1; } else /* must be ASCII */ { l = 1; } return l; } /* EUC-CN byte sequences are exactly same as EUC-KR */ #define pg_euccn_verifier pg_euckr_verifier static int pg_euctw_verifier(const unsigned char *s, int len) { int l; unsigned char c1, c2; c1 = *s++; switch (c1) { case SS2: /* CNS 11643 Plane 1-7 */ l = 4; if (l > len) return -1; c2 = *s++; if (c2 < 0xa1 || c2 > 0xa7) return -1; c2 = *s++; if (!IS_EUC_RANGE_VALID(c2)) return -1; c2 = *s++; if (!IS_EUC_RANGE_VALID(c2)) return -1; break; case SS3: /* unused */ return -1; default: if (IS_HIGHBIT_SET(c1)) /* CNS 11643 Plane 1 */ { l = 2; if (l > len) return -1; /* no further range check on c1? */ c2 = *s++; if (!IS_EUC_RANGE_VALID(c2)) return -1; } else /* must be ASCII */ { l = 1; } break; } return l; } static int pg_johab_verifier(const unsigned char *s, int len) { int l, mbl; unsigned char c; l = mbl = pg_johab_mblen(s); if (len < l) return -1; if (!IS_HIGHBIT_SET(*s)) return mbl; while (--l > 0) { c = *++s; if (!IS_EUC_RANGE_VALID(c)) return -1; } return mbl; } static int pg_mule_verifier(const unsigned char *s, int len) { int l, mbl; unsigned char c; l = mbl = pg_mule_mblen(s); if (len < l) return -1; while (--l > 0) { c = *++s; if (!IS_HIGHBIT_SET(c)) return -1; } return mbl; } static int pg_latin1_verifier(const unsigned char *s, int len) { return 1; } static int pg_sjis_verifier(const unsigned char *s, int len) { int l, mbl; unsigned char c1, c2; l = mbl = pg_sjis_mblen(s); if (len < l) return -1; if (l == 1) /* pg_sjis_mblen already verified it */ return mbl; c1 = *s++; c2 = *s; if (!ISSJISHEAD(c1) || !ISSJISTAIL(c2)) return -1; return mbl; } static int pg_big5_verifier(const unsigned char *s, int len) { int l, mbl; l = mbl = pg_big5_mblen(s); if (len < l) return -1; while (--l > 0) { if (*++s == '\0') return -1; } return mbl; } static int pg_gbk_verifier(const unsigned char *s, int len) { int l, mbl; l = mbl = pg_gbk_mblen(s); if (len < l) return -1; while (--l > 0) { if (*++s == '\0') return -1; } return mbl; } static int pg_uhc_verifier(const unsigned char *s, int len) { int l, mbl; l = mbl = pg_uhc_mblen(s); if (len < l) return -1; while (--l > 0) { if (*++s == '\0') return -1; } return mbl; } static int pg_gb18030_verifier(const unsigned char *s, int len) { int l, mbl; l = mbl = pg_gb18030_mblen(s); if (len < l) return -1; while (--l > 0) { if (*++s == '\0') return -1; } return mbl; } static int pg_utf8_verifier(const unsigned char *s, int len) { int l = pg_utf_mblen(s); if (len < l) return -1; if (!pg_utf8_islegal(s, l)) return -1; return l; } /* * Check for validity of a single UTF-8 encoded character * * This directly implements the rules in RFC3629. The bizarre-looking * restrictions on the second byte are meant to ensure that there isn't * more than one encoding of a given Unicode character point; that is, * you may not use a longer-than-necessary byte sequence with high order * zero bits to represent a character that would fit in fewer bytes. * To do otherwise is to create security hazards (eg, create an apparent * non-ASCII character that decodes to plain ASCII). * * length is assumed to have been obtained by pg_utf_mblen(), and the * caller must have checked that that many bytes are present in the buffer. */ bool pg_utf8_islegal(const unsigned char *source, int length) { unsigned char a; switch (length) { default: /* reject lengths 5 and 6 for now */ return false; case 4: a = source[3]; if (a < 0x80 || a > 0xBF) return false; /* FALL THRU */ case 3: a = source[2]; if (a < 0x80 || a > 0xBF) return false; /* FALL THRU */ case 2: a = source[1]; switch (*source) { case 0xE0: if (a < 0xA0 || a > 0xBF) return false; break; case 0xED: if (a < 0x80 || a > 0x9F) return false; break; case 0xF0: if (a < 0x90 || a > 0xBF) return false; break; case 0xF4: if (a < 0x80 || a > 0x8F) return false; break; default: if (a < 0x80 || a > 0xBF) return false; break; } /* FALL THRU */ case 1: a = *source; if (a >= 0x80 && a < 0xC2) return false; if (a > 0xF4) return false; break; } return true; } /* *------------------------------------------------------------------- * encoding info table * XXX must be sorted by the same order as enum pg_enc (in mb/pg_wchar.h) *------------------------------------------------------------------- */ pg_wchar_tbl pg_wchar_table[] = { {pg_ascii2wchar_with_len, pg_ascii_mblen, pg_ascii_dsplen, pg_ascii_verifier, 1}, /* PG_SQL_ASCII */ {pg_eucjp2wchar_with_len, pg_eucjp_mblen, pg_eucjp_dsplen, pg_eucjp_verifier, 3}, /* PG_EUC_JP */ {pg_euccn2wchar_with_len, pg_euccn_mblen, pg_euccn_dsplen, pg_euccn_verifier, 2}, /* PG_EUC_CN */ {pg_euckr2wchar_with_len, pg_euckr_mblen, pg_euckr_dsplen, pg_euckr_verifier, 3}, /* PG_EUC_KR */ {pg_euctw2wchar_with_len, pg_euctw_mblen, pg_euctw_dsplen, pg_euctw_verifier, 4}, /* PG_EUC_TW */ {pg_eucjp2wchar_with_len, pg_eucjp_mblen, pg_eucjp_dsplen, pg_eucjp_verifier, 3}, /* PG_EUC_JIS_2004 */ {pg_utf2wchar_with_len, pg_utf_mblen, pg_utf_dsplen, pg_utf8_verifier, 4}, /* PG_UTF8 */ {pg_mule2wchar_with_len, pg_mule_mblen, pg_mule_dsplen, pg_mule_verifier, 4}, /* PG_MULE_INTERNAL */ {pg_latin12wchar_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_LATIN1 */ {pg_latin12wchar_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_LATIN2 */ {pg_latin12wchar_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_LATIN3 */ {pg_latin12wchar_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_LATIN4 */ {pg_latin12wchar_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_LATIN5 */ {pg_latin12wchar_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_LATIN6 */ {pg_latin12wchar_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_LATIN7 */ {pg_latin12wchar_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_LATIN8 */ {pg_latin12wchar_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_LATIN9 */ {pg_latin12wchar_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_LATIN10 */ {pg_latin12wchar_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_WIN1256 */ {pg_latin12wchar_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_WIN1258 */ {pg_latin12wchar_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_WIN866 */ {pg_latin12wchar_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_WIN874 */ {pg_latin12wchar_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_KOI8R */ {pg_latin12wchar_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_WIN1251 */ {pg_latin12wchar_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_WIN1252 */ {pg_latin12wchar_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* ISO-8859-5 */ {pg_latin12wchar_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* ISO-8859-6 */ {pg_latin12wchar_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* ISO-8859-7 */ {pg_latin12wchar_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* ISO-8859-8 */ {pg_latin12wchar_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_WIN1250 */ {pg_latin12wchar_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_WIN1253 */ {pg_latin12wchar_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_WIN1254 */ {pg_latin12wchar_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_WIN1255 */ {pg_latin12wchar_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_WIN1257 */ {pg_latin12wchar_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_KOI8U */ {0, pg_sjis_mblen, pg_sjis_dsplen, pg_sjis_verifier, 2}, /* PG_SJIS */ {0, pg_big5_mblen, pg_big5_dsplen, pg_big5_verifier, 2}, /* PG_BIG5 */ {0, pg_gbk_mblen, pg_gbk_dsplen, pg_gbk_verifier, 2}, /* PG_GBK */ {0, pg_uhc_mblen, pg_uhc_dsplen, pg_uhc_verifier, 2}, /* PG_UHC */ {0, pg_gb18030_mblen, pg_gb18030_dsplen, pg_gb18030_verifier, 4}, /* PG_GB18030 */ {0, pg_johab_mblen, pg_johab_dsplen, pg_johab_verifier, 3}, /* PG_JOHAB */ {0, pg_sjis_mblen, pg_sjis_dsplen, pg_sjis_verifier, 2} /* PG_SHIFT_JIS_2004 */ }; /* returns the byte length of a word for mule internal code */ int pg_mic_mblen(const unsigned char *mbstr) { return pg_mule_mblen(mbstr); } /* * Returns the byte length of a multibyte character. */ int pg_encoding_mblen(int encoding, const char *mbstr) { Assert(PG_VALID_ENCODING(encoding)); return ((encoding >= 0 && encoding < sizeof(pg_wchar_table) / sizeof(pg_wchar_tbl)) ? ((*pg_wchar_table[encoding].mblen) ((const unsigned char *) mbstr)) : ((*pg_wchar_table[PG_SQL_ASCII].mblen) ((const unsigned char *) mbstr))); } /* * Returns the display length of a multibyte character. */ int pg_encoding_dsplen(int encoding, const char *mbstr) { Assert(PG_VALID_ENCODING(encoding)); return ((encoding >= 0 && encoding < sizeof(pg_wchar_table) / sizeof(pg_wchar_tbl)) ? ((*pg_wchar_table[encoding].dsplen) ((const unsigned char *) mbstr)) : ((*pg_wchar_table[PG_SQL_ASCII].dsplen) ((const unsigned char *) mbstr))); } /* * Verify the first multibyte character of the given string. * Return its byte length if good, -1 if bad. (See comments above for * full details of the mbverify API.) */ int pg_encoding_verifymb(int encoding, const char *mbstr, int len) { Assert(PG_VALID_ENCODING(encoding)); return ((encoding >= 0 && encoding < sizeof(pg_wchar_table) / sizeof(pg_wchar_tbl)) ? ((*pg_wchar_table[encoding].mbverify) ((const unsigned char *) mbstr, len)) : ((*pg_wchar_table[PG_SQL_ASCII].mbverify) ((const unsigned char *) mbstr, len))); } /* * fetch maximum length of a given encoding */ int pg_encoding_max_length(int encoding) { Assert(PG_VALID_ENCODING(encoding)); return pg_wchar_table[encoding].maxmblen; } #ifndef FRONTEND /* * fetch maximum length of the encoding for the current database */ int pg_database_encoding_max_length(void) { return pg_wchar_table[GetDatabaseEncoding()].maxmblen; } /* * Verify mbstr to make sure that it is validly encoded in the current * database encoding. Otherwise same as pg_verify_mbstr(). */ bool pg_verifymbstr(const char *mbstr, int len, bool noError) { return pg_verify_mbstr_len(GetDatabaseEncoding(), mbstr, len, noError) >= 0; } /* * Verify mbstr to make sure that it is validly encoded in the specified * encoding. */ bool pg_verify_mbstr(int encoding, const char *mbstr, int len, bool noError) { return pg_verify_mbstr_len(encoding, mbstr, len, noError) >= 0; } /* * Verify mbstr to make sure that it is validly encoded in the specified * encoding. * * mbstr is not necessarily zero terminated; length of mbstr is * specified by len. * * If OK, return length of string in the encoding. * If a problem is found, return -1 when noError is * true; when noError is false, ereport() a descriptive message. */ int pg_verify_mbstr_len(int encoding, const char *mbstr, int len, bool noError) { mbverifier mbverify; int mb_len; Assert(PG_VALID_ENCODING(encoding)); /* * In single-byte encodings, we need only reject nulls (\0). */ if (pg_encoding_max_length(encoding) <= 1) { const char *nullpos = memchr(mbstr, 0, len); if (nullpos == NULL) return len; if (noError) return -1; report_invalid_encoding(encoding, nullpos, 1); } /* fetch function pointer just once */ mbverify = pg_wchar_table[encoding].mbverify; mb_len = 0; while (len > 0) { int l; /* fast path for ASCII-subset characters */ if (!IS_HIGHBIT_SET(*mbstr)) { if (*mbstr != '\0') { mb_len++; mbstr++; len--; continue; } if (noError) return -1; report_invalid_encoding(encoding, mbstr, len); } l = (*mbverify) ((const unsigned char *) mbstr, len); if (l < 0) { if (noError) return -1; report_invalid_encoding(encoding, mbstr, len); } mbstr += l; len -= l; mb_len++; } return mb_len; } /* * check_encoding_conversion_args: check arguments of a conversion function * * "expected" arguments can be either an encoding ID or -1 to indicate that * the caller will check whether it accepts the ID. * * Note: the errors here are not really user-facing, so elog instead of * ereport seems sufficient. Also, we trust that the "expected" encoding * arguments are valid encoding IDs, but we don't trust the actuals. */ void check_encoding_conversion_args(int src_encoding, int dest_encoding, int len, int expected_src_encoding, int expected_dest_encoding) { if (!PG_VALID_ENCODING(src_encoding)) elog(ERROR, "invalid source encoding ID: %d", src_encoding); if (src_encoding != expected_src_encoding && expected_src_encoding >= 0) elog(ERROR, "expected source encoding \"%s\", but got \"%s\"", pg_enc2name_tbl[expected_src_encoding].name, pg_enc2name_tbl[src_encoding].name); if (!PG_VALID_ENCODING(dest_encoding)) elog(ERROR, "invalid destination encoding ID: %d", dest_encoding); if (dest_encoding != expected_dest_encoding && expected_dest_encoding >= 0) elog(ERROR, "expected destination encoding \"%s\", but got \"%s\"", pg_enc2name_tbl[expected_dest_encoding].name, pg_enc2name_tbl[dest_encoding].name); if (len < 0) elog(ERROR, "encoding conversion length must not be negative"); } /* * report_invalid_encoding: complain about invalid multibyte character * * note: len is remaining length of string, not length of character; * len must be greater than zero, as we always examine the first byte. */ void report_invalid_encoding(int encoding, const char *mbstr, int len) { int l = pg_encoding_mblen(encoding, mbstr); char buf[8 * 2 + 1]; char *p = buf; int j, jlimit; jlimit = Min(l, len); jlimit = Min(jlimit, 8); /* prevent buffer overrun */ for (j = 0; j < jlimit; j++) p += sprintf(p, "%02x", (unsigned char) mbstr[j]); ereport(ERROR, (errcode(ERRCODE_CHARACTER_NOT_IN_REPERTOIRE), errmsg("invalid byte sequence for encoding \"%s\": 0x%s", pg_enc2name_tbl[encoding].name, buf))); } /* * report_untranslatable_char: complain about untranslatable character * * note: len is remaining length of string, not length of character; * len must be greater than zero, as we always examine the first byte. */ void report_untranslatable_char(int src_encoding, int dest_encoding, const char *mbstr, int len) { int l = pg_encoding_mblen(src_encoding, mbstr); char buf[8 * 2 + 1]; char *p = buf; int j, jlimit; jlimit = Min(l, len); jlimit = Min(jlimit, 8); /* prevent buffer overrun */ for (j = 0; j < jlimit; j++) p += sprintf(p, "%02x", (unsigned char) mbstr[j]); ereport(ERROR, (errcode(ERRCODE_UNTRANSLATABLE_CHARACTER), errmsg("character 0x%s of encoding \"%s\" has no equivalent in \"%s\"", buf, pg_enc2name_tbl[src_encoding].name, pg_enc2name_tbl[dest_encoding].name))); } #endif RPostgreSQL/src/libpq/exports.txt0000644000176000001440000001124211660061757016603 0ustar ripleyusers# src/interfaces/libpq/exports.txt # Functions to be exported by libpq DLLs PQconnectdb 1 PQsetdbLogin 2 PQconndefaults 3 PQfinish 4 PQreset 5 PQrequestCancel 6 PQdb 7 PQuser 8 PQpass 9 PQhost 10 PQport 11 PQtty 12 PQoptions 13 PQstatus 14 PQerrorMessage 15 PQsocket 16 PQbackendPID 17 PQtrace 18 PQuntrace 19 PQsetNoticeProcessor 20 PQexec 21 PQnotifies 22 PQsendQuery 23 PQgetResult 24 PQisBusy 25 PQconsumeInput 26 PQgetline 27 PQputline 28 PQgetlineAsync 29 PQputnbytes 30 PQendcopy 31 PQfn 32 PQresultStatus 33 PQntuples 34 PQnfields 35 PQbinaryTuples 36 PQfname 37 PQfnumber 38 PQftype 39 PQfsize 40 PQfmod 41 PQcmdStatus 42 PQoidStatus 43 PQcmdTuples 44 PQgetvalue 45 PQgetlength 46 PQgetisnull 47 PQclear 48 PQmakeEmptyPGresult 49 PQprint 50 PQdisplayTuples 51 PQprintTuples 52 lo_open 53 lo_close 54 lo_read 55 lo_write 56 lo_lseek 57 lo_creat 58 lo_tell 59 lo_unlink 60 lo_import 61 lo_export 62 pgresStatus 63 PQmblen 64 PQresultErrorMessage 65 PQresStatus 66 termPQExpBuffer 67 appendPQExpBufferChar 68 initPQExpBuffer 69 resetPQExpBuffer 70 PQoidValue 71 PQclientEncoding 72 PQenv2encoding 73 appendBinaryPQExpBuffer 74 appendPQExpBufferStr 75 destroyPQExpBuffer 76 createPQExpBuffer 77 PQconninfoFree 78 PQconnectPoll 79 PQconnectStart 80 PQflush 81 PQisnonblocking 82 PQresetPoll 83 PQresetStart 84 PQsetClientEncoding 85 PQsetnonblocking 86 PQfreeNotify 87 PQescapeString 88 PQescapeBytea 89 printfPQExpBuffer 90 appendPQExpBuffer 91 pg_encoding_to_char 92 pg_utf_mblen 93 PQunescapeBytea 94 PQfreemem 95 PQtransactionStatus 96 PQparameterStatus 97 PQprotocolVersion 98 PQsetErrorVerbosity 99 PQsetNoticeReceiver 100 PQexecParams 101 PQsendQueryParams 102 PQputCopyData 103 PQputCopyEnd 104 PQgetCopyData 105 PQresultErrorField 106 PQftable 107 PQftablecol 108 PQfformat 109 PQexecPrepared 110 PQsendQueryPrepared 111 PQdsplen 112 PQserverVersion 113 PQgetssl 114 pg_char_to_encoding 115 pg_valid_server_encoding 116 pqsignal 117 PQprepare 118 PQsendPrepare 119 PQgetCancel 120 PQfreeCancel 121 PQcancel 122 lo_create 123 PQinitSSL 124 PQregisterThreadLock 125 PQescapeStringConn 126 PQescapeByteaConn 127 PQencryptPassword 128 PQisthreadsafe 129 enlargePQExpBuffer 130 PQnparams 131 PQparamtype 132 PQdescribePrepared 133 PQdescribePortal 134 PQsendDescribePrepared 135 PQsendDescribePortal 136 lo_truncate 137 PQconnectionUsedPassword 138 pg_valid_server_encoding_id 139 PQconnectionNeedsPassword 140 lo_import_with_oid 141 PQcopyResult 142 PQsetResultAttrs 143 PQsetvalue 144 PQresultAlloc 145 PQregisterEventProc 146 PQinstanceData 147 PQsetInstanceData 148 PQresultInstanceData 149 PQresultSetInstanceData 150 PQfireResultCreateEvents 151 PQconninfoParse 152 PQinitOpenSSL 153 PQescapeLiteral 154 PQescapeIdentifier 155 PQconnectdbParams 156 PQconnectStartParams 157 PQping 158 PQpingParams 159 PQlibVersion 160 RPostgreSQL/src/libpq/snprintf.c0000644000176000001440000005441012124517222016336 0ustar ripleyusers/* * Copyright (c) 1983, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights 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. Neither the name of the University 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 REGENTS 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 REGENTS 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. * * src/port/snprintf.c */ #include "c.h" #include #ifndef WIN32 #include #endif #include #ifndef NL_ARGMAX #define NL_ARGMAX 16 #endif /* * SNPRINTF, VSNPRINTF and friends * * These versions have been grabbed off the net. They have been * cleaned up to compile properly and support for most of the Single Unix * Specification has been added. Remaining unimplemented features are: * * 1. No locale support: the radix character is always '.' and the ' * (single quote) format flag is ignored. * * 2. No support for the "%n" format specification. * * 3. No support for wide characters ("lc" and "ls" formats). * * 4. No support for "long double" ("Lf" and related formats). * * 5. Space and '#' flags are not implemented. * * * The result values of these functions are not the same across different * platforms. This implementation is compatible with the Single Unix Spec: * * 1. -1 is returned only if processing is abandoned due to an invalid * parameter, such as incorrect format string. (Although not required by * the spec, this happens only when no characters have yet been transmitted * to the destination.) * * 2. For snprintf and sprintf, 0 is returned if str == NULL or count == 0; * no data has been stored. * * 3. Otherwise, the number of bytes actually transmitted to the destination * is returned (excluding the trailing '\0' for snprintf and sprintf). * * For snprintf with nonzero count, the result cannot be more than count-1 * (a trailing '\0' is always stored); it is not possible to distinguish * buffer overrun from exact fit. This is unlike some implementations that * return the number of bytes that would have been needed for the complete * result string. */ /************************************************************** * Original: * Patrick Powell Tue Apr 11 09:48:21 PDT 1995 * A bombproof version of doprnt (dopr) included. * Sigh. This sort of thing is always nasty do deal with. Note that * the version here does not include floating point. (now it does ... tgl) **************************************************************/ /* Prevent recursion */ #undef vsnprintf #undef snprintf #undef sprintf #undef vfprintf #undef fprintf #undef printf /* Info about where the formatted output is going */ typedef struct { char *bufptr; /* next buffer output position */ char *bufstart; /* first buffer element */ char *bufend; /* last buffer element, or NULL */ /* bufend == NULL is for sprintf, where we assume buf is big enough */ FILE *stream; /* eventual output destination, or NULL */ int nchars; /* # chars already sent to stream */ } PrintfTarget; /* * Info about the type and value of a formatting parameter. Note that we * don't currently support "long double", "wint_t", or "wchar_t *" data, * nor the '%n' formatting code; else we'd need more types. Also, at this * level we need not worry about signed vs unsigned values. */ typedef enum { ATYPE_NONE = 0, ATYPE_INT, ATYPE_LONG, ATYPE_LONGLONG, ATYPE_DOUBLE, ATYPE_CHARPTR } PrintfArgType; typedef union { int i; long l; int64 ll; double d; char *cptr; } PrintfArgValue; static void flushbuffer(PrintfTarget *target); static int dopr(PrintfTarget *target, const char *format, va_list args); int pg_vsnprintf(char *str, size_t count, const char *fmt, va_list args) { PrintfTarget target; if (str == NULL || count == 0) return 0; target.bufstart = target.bufptr = str; target.bufend = str + count - 1; target.stream = NULL; /* target.nchars is unused in this case */ if (dopr(&target, fmt, args)) { *(target.bufptr) = '\0'; errno = EINVAL; /* bad format */ return -1; } *(target.bufptr) = '\0'; return target.bufptr - target.bufstart; } int pg_snprintf(char *str, size_t count, const char *fmt,...) { int len; va_list args; va_start(args, fmt); len = pg_vsnprintf(str, count, fmt, args); va_end(args); return len; } static int pg_vsprintf(char *str, const char *fmt, va_list args) { PrintfTarget target; if (str == NULL) return 0; target.bufstart = target.bufptr = str; target.bufend = NULL; target.stream = NULL; /* target.nchars is unused in this case */ if (dopr(&target, fmt, args)) { *(target.bufptr) = '\0'; errno = EINVAL; /* bad format */ return -1; } *(target.bufptr) = '\0'; return target.bufptr - target.bufstart; } int pg_sprintf(char *str, const char *fmt,...) { int len; va_list args; va_start(args, fmt); len = pg_vsprintf(str, fmt, args); va_end(args); return len; } int pg_vfprintf(FILE *stream, const char *fmt, va_list args) { PrintfTarget target; char buffer[1024]; /* size is arbitrary */ if (stream == NULL) { errno = EINVAL; return -1; } target.bufstart = target.bufptr = buffer; target.bufend = buffer + sizeof(buffer) - 1; target.stream = stream; target.nchars = 0; if (dopr(&target, fmt, args)) { errno = EINVAL; /* bad format */ return -1; } /* dump any remaining buffer contents */ flushbuffer(&target); return target.nchars; } int pg_fprintf(FILE *stream, const char *fmt,...) { int len; va_list args; va_start(args, fmt); len = pg_vfprintf(stream, fmt, args); va_end(args); return len; } int pg_printf(const char *fmt,...) { int len; va_list args; va_start(args, fmt); len = pg_vfprintf(stdout, fmt, args); va_end(args); return len; } /* call this only when stream is defined */ static void flushbuffer(PrintfTarget *target) { size_t nc = target->bufptr - target->bufstart; if (nc > 0) target->nchars += fwrite(target->bufstart, 1, nc, target->stream); target->bufptr = target->bufstart; } static void fmtstr(char *value, int leftjust, int minlen, int maxwidth, int pointflag, PrintfTarget *target); static void fmtptr(void *value, PrintfTarget *target); static void fmtint(int64 value, char type, int forcesign, int leftjust, int minlen, int zpad, int precision, int pointflag, PrintfTarget *target); static void fmtchar(int value, int leftjust, int minlen, PrintfTarget *target); static void fmtfloat(double value, char type, int forcesign, int leftjust, int minlen, int zpad, int precision, int pointflag, PrintfTarget *target); static void dostr(const char *str, int slen, PrintfTarget *target); static void dopr_outch(int c, PrintfTarget *target); static int adjust_sign(int is_negative, int forcesign, int *signvalue); static void adjust_padlen(int minlen, int vallen, int leftjust, int *padlen); static void leading_pad(int zpad, int *signvalue, int *padlen, PrintfTarget *target); static void trailing_pad(int *padlen, PrintfTarget *target); /* * dopr(): poor man's version of doprintf */ static int dopr(PrintfTarget *target, const char *format, va_list args) { const char *format_start = format; int ch; bool have_dollar; bool have_non_dollar; bool have_star; bool afterstar; int accum; int longlongflag; int longflag; int pointflag; int leftjust; int fieldwidth; int precision; int zpad; int forcesign; int last_dollar; int fmtpos; int cvalue; int64 numvalue; double fvalue; char *strvalue; int i; PrintfArgType argtypes[NL_ARGMAX + 1]; PrintfArgValue argvalues[NL_ARGMAX + 1]; /* * Parse the format string to determine whether there are %n$ format * specs, and identify the types and order of the format parameters. */ have_dollar = have_non_dollar = false; last_dollar = 0; MemSet(argtypes, 0, sizeof(argtypes)); while ((ch = *format++) != '\0') { if (ch != '%') continue; longflag = longlongflag = pointflag = 0; fmtpos = accum = 0; afterstar = false; nextch1: ch = *format++; if (ch == '\0') break; /* illegal, but we don't complain */ switch (ch) { case '-': case '+': goto nextch1; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': accum = accum * 10 + (ch - '0'); goto nextch1; case '.': pointflag = 1; accum = 0; goto nextch1; case '*': if (afterstar) have_non_dollar = true; /* multiple stars */ afterstar = true; accum = 0; goto nextch1; case '$': have_dollar = true; if (accum <= 0 || accum > NL_ARGMAX) return -1; if (afterstar) { if (argtypes[accum] && argtypes[accum] != ATYPE_INT) return -1; argtypes[accum] = ATYPE_INT; last_dollar = Max(last_dollar, accum); afterstar = false; } else fmtpos = accum; accum = 0; goto nextch1; case 'l': if (longflag) longlongflag = 1; else longflag = 1; goto nextch1; case 'h': case '\'': /* ignore these */ goto nextch1; case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': if (fmtpos) { PrintfArgType atype; if (longlongflag) atype = ATYPE_LONGLONG; else if (longflag) atype = ATYPE_LONG; else atype = ATYPE_INT; if (argtypes[fmtpos] && argtypes[fmtpos] != atype) return -1; argtypes[fmtpos] = atype; last_dollar = Max(last_dollar, fmtpos); } else have_non_dollar = true; break; case 'c': if (fmtpos) { if (argtypes[fmtpos] && argtypes[fmtpos] != ATYPE_INT) return -1; argtypes[fmtpos] = ATYPE_INT; last_dollar = Max(last_dollar, fmtpos); } else have_non_dollar = true; break; case 's': case 'p': if (fmtpos) { if (argtypes[fmtpos] && argtypes[fmtpos] != ATYPE_CHARPTR) return -1; argtypes[fmtpos] = ATYPE_CHARPTR; last_dollar = Max(last_dollar, fmtpos); } else have_non_dollar = true; break; case 'e': case 'E': case 'f': case 'g': case 'G': if (fmtpos) { if (argtypes[fmtpos] && argtypes[fmtpos] != ATYPE_DOUBLE) return -1; argtypes[fmtpos] = ATYPE_DOUBLE; last_dollar = Max(last_dollar, fmtpos); } else have_non_dollar = true; break; case '%': break; } /* * If we finish the spec with afterstar still set, there's a * non-dollar star in there. */ if (afterstar) have_non_dollar = true; } /* Per spec, you use either all dollar or all not. */ if (have_dollar && have_non_dollar) return -1; /* * In dollar mode, collect the arguments in physical order. */ for (i = 1; i <= last_dollar; i++) { switch (argtypes[i]) { case ATYPE_NONE: return -1; /* invalid format */ case ATYPE_INT: argvalues[i].i = va_arg(args, int); break; case ATYPE_LONG: argvalues[i].l = va_arg(args, long); break; case ATYPE_LONGLONG: argvalues[i].ll = va_arg(args, int64); break; case ATYPE_DOUBLE: argvalues[i].d = va_arg(args, double); break; case ATYPE_CHARPTR: argvalues[i].cptr = va_arg(args, char *); break; } } /* * At last we can parse the format for real. */ format = format_start; while ((ch = *format++) != '\0') { if (ch != '%') { dopr_outch(ch, target); continue; } fieldwidth = precision = zpad = leftjust = forcesign = 0; longflag = longlongflag = pointflag = 0; fmtpos = accum = 0; have_star = afterstar = false; nextch2: ch = *format++; if (ch == '\0') break; /* illegal, but we don't complain */ switch (ch) { case '-': leftjust = 1; goto nextch2; case '+': forcesign = 1; goto nextch2; case '0': /* set zero padding if no nonzero digits yet */ if (accum == 0 && !pointflag) zpad = '0'; /* FALL THRU */ case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': accum = accum * 10 + (ch - '0'); goto nextch2; case '.': if (have_star) have_star = false; else fieldwidth = accum; pointflag = 1; accum = 0; goto nextch2; case '*': if (have_dollar) { /* process value after reading n$ */ afterstar = true; } else { /* fetch and process value now */ int starval = va_arg(args, int); if (pointflag) { precision = starval; if (precision < 0) { precision = 0; pointflag = 0; } } else { fieldwidth = starval; if (fieldwidth < 0) { leftjust = 1; fieldwidth = -fieldwidth; } } } have_star = true; accum = 0; goto nextch2; case '$': if (afterstar) { /* fetch and process star value */ int starval = argvalues[accum].i; if (pointflag) { precision = starval; if (precision < 0) { precision = 0; pointflag = 0; } } else { fieldwidth = starval; if (fieldwidth < 0) { leftjust = 1; fieldwidth = -fieldwidth; } } afterstar = false; } else fmtpos = accum; accum = 0; goto nextch2; case 'l': if (longflag) longlongflag = 1; else longflag = 1; goto nextch2; case 'h': case '\'': /* ignore these */ goto nextch2; case 'd': case 'i': if (!have_star) { if (pointflag) precision = accum; else fieldwidth = accum; } if (have_dollar) { if (longlongflag) numvalue = argvalues[fmtpos].ll; else if (longflag) numvalue = argvalues[fmtpos].l; else numvalue = argvalues[fmtpos].i; } else { if (longlongflag) numvalue = va_arg(args, int64); else if (longflag) numvalue = va_arg(args, long); else numvalue = va_arg(args, int); } fmtint(numvalue, ch, forcesign, leftjust, fieldwidth, zpad, precision, pointflag, target); break; case 'o': case 'u': case 'x': case 'X': if (!have_star) { if (pointflag) precision = accum; else fieldwidth = accum; } if (have_dollar) { if (longlongflag) numvalue = (uint64) argvalues[fmtpos].ll; else if (longflag) numvalue = (unsigned long) argvalues[fmtpos].l; else numvalue = (unsigned int) argvalues[fmtpos].i; } else { if (longlongflag) numvalue = (uint64) va_arg(args, int64); else if (longflag) numvalue = (unsigned long) va_arg(args, long); else numvalue = (unsigned int) va_arg(args, int); } fmtint(numvalue, ch, forcesign, leftjust, fieldwidth, zpad, precision, pointflag, target); break; case 'c': if (!have_star) { if (pointflag) precision = accum; else fieldwidth = accum; } if (have_dollar) cvalue = (unsigned char) argvalues[fmtpos].i; else cvalue = (unsigned char) va_arg(args, int); fmtchar(cvalue, leftjust, fieldwidth, target); break; case 's': if (!have_star) { if (pointflag) precision = accum; else fieldwidth = accum; } if (have_dollar) strvalue = argvalues[fmtpos].cptr; else strvalue = va_arg(args, char *); fmtstr(strvalue, leftjust, fieldwidth, precision, pointflag, target); break; case 'p': /* fieldwidth/leftjust are ignored ... */ if (have_dollar) strvalue = argvalues[fmtpos].cptr; else strvalue = va_arg(args, char *); fmtptr((void *) strvalue, target); break; case 'e': case 'E': case 'f': case 'g': case 'G': if (!have_star) { if (pointflag) precision = accum; else fieldwidth = accum; } if (have_dollar) fvalue = argvalues[fmtpos].d; else fvalue = va_arg(args, double); fmtfloat(fvalue, ch, forcesign, leftjust, fieldwidth, zpad, precision, pointflag, target); break; case '%': dopr_outch('%', target); break; } } return 0; } static size_t pg_strnlen(const char *str, size_t maxlen) { const char *p = str; while (maxlen-- > 0 && *p) p++; return p - str; } static void fmtstr(char *value, int leftjust, int minlen, int maxwidth, int pointflag, PrintfTarget *target) { int padlen, vallen; /* amount to pad */ /* * If a maxwidth (precision) is specified, we must not fetch more bytes * than that. */ if (pointflag) vallen = pg_strnlen(value, maxwidth); else vallen = strlen(value); adjust_padlen(minlen, vallen, leftjust, &padlen); while (padlen > 0) { dopr_outch(' ', target); --padlen; } dostr(value, vallen, target); trailing_pad(&padlen, target); } static void fmtptr(void *value, PrintfTarget *target) { int vallen; char convert[64]; /* we rely on regular C library's sprintf to do the basic conversion */ vallen = sprintf(convert, "%p", value); dostr(convert, vallen, target); } static void fmtint(int64 value, char type, int forcesign, int leftjust, int minlen, int zpad, int precision, int pointflag, PrintfTarget *target) { uint64 base; int dosign; const char *cvt = "0123456789abcdef"; int signvalue = 0; char convert[64]; int vallen = 0; int padlen = 0; /* amount to pad */ int zeropad; /* extra leading zeroes */ switch (type) { case 'd': case 'i': base = 10; dosign = 1; break; case 'o': base = 8; dosign = 0; break; case 'u': base = 10; dosign = 0; break; case 'x': base = 16; dosign = 0; break; case 'X': cvt = "0123456789ABCDEF"; base = 16; dosign = 0; break; default: return; /* keep compiler quiet */ } /* Handle +/- */ if (dosign && adjust_sign((value < 0), forcesign, &signvalue)) value = -value; /* * SUS: the result of converting 0 with an explicit precision of 0 is no * characters */ if (value == 0 && pointflag && precision == 0) vallen = 0; else { /* make integer string */ uint64 uvalue = (uint64) value; do { convert[vallen++] = cvt[uvalue % base]; uvalue = uvalue / base; } while (uvalue); } zeropad = Max(0, precision - vallen); adjust_padlen(minlen, vallen + zeropad, leftjust, &padlen); leading_pad(zpad, &signvalue, &padlen, target); while (zeropad-- > 0) dopr_outch('0', target); while (vallen > 0) dopr_outch(convert[--vallen], target); trailing_pad(&padlen, target); } static void fmtchar(int value, int leftjust, int minlen, PrintfTarget *target) { int padlen = 0; /* amount to pad */ adjust_padlen(minlen, 1, leftjust, &padlen); while (padlen > 0) { dopr_outch(' ', target); --padlen; } dopr_outch(value, target); trailing_pad(&padlen, target); } static void fmtfloat(double value, char type, int forcesign, int leftjust, int minlen, int zpad, int precision, int pointflag, PrintfTarget *target) { int signvalue = 0; int vallen; char fmt[32]; char convert[512]; int padlen = 0; /* amount to pad */ /* we rely on regular C library's sprintf to do the basic conversion */ if (pointflag) sprintf(fmt, "%%.%d%c", precision, type); else sprintf(fmt, "%%%c", type); if (adjust_sign((value < 0), forcesign, &signvalue)) value = -value; vallen = sprintf(convert, fmt, value); adjust_padlen(minlen, vallen, leftjust, &padlen); leading_pad(zpad, &signvalue, &padlen, target); dostr(convert, vallen, target); trailing_pad(&padlen, target); } static void dostr(const char *str, int slen, PrintfTarget *target) { while (slen > 0) { int avail; if (target->bufend != NULL) avail = target->bufend - target->bufptr; else avail = slen; if (avail <= 0) { /* buffer full, can we dump to stream? */ if (target->stream == NULL) return; /* no, lose the data */ flushbuffer(target); continue; } avail = Min(avail, slen); memmove(target->bufptr, str, avail); target->bufptr += avail; str += avail; slen -= avail; } } static void dopr_outch(int c, PrintfTarget *target) { if (target->bufend != NULL && target->bufptr >= target->bufend) { /* buffer full, can we dump to stream? */ if (target->stream == NULL) return; /* no, lose the data */ flushbuffer(target); } *(target->bufptr++) = c; } static int adjust_sign(int is_negative, int forcesign, int *signvalue) { if (is_negative) { *signvalue = '-'; return true; } else if (forcesign) *signvalue = '+'; return false; } static void adjust_padlen(int minlen, int vallen, int leftjust, int *padlen) { *padlen = minlen - vallen; if (*padlen < 0) *padlen = 0; if (leftjust) *padlen = -(*padlen); } static void leading_pad(int zpad, int *signvalue, int *padlen, PrintfTarget *target) { if (*padlen > 0 && zpad) { if (*signvalue) { dopr_outch(*signvalue, target); --(*padlen); *signvalue = 0; } while (*padlen > 0) { dopr_outch(zpad, target); --(*padlen); } } while (*padlen > (*signvalue != 0)) { dopr_outch(' ', target); --(*padlen); } if (*signvalue) { dopr_outch(*signvalue, target); if (*padlen > 0) --(*padlen); else if (*padlen < 0) ++(*padlen); } } static void trailing_pad(int *padlen, PrintfTarget *target) { while (*padlen < 0) { dopr_outch(' ', target); ++(*padlen); } } RPostgreSQL/src/libpq/fe-protocol3.c0000644000176000001440000014422512124517222017013 0ustar ripleyusers/*------------------------------------------------------------------------- * * fe-protocol3.c * functions that are specific to frontend/backend protocol version 3 * * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * src/interfaces/libpq/fe-protocol3.c * *------------------------------------------------------------------------- */ #include "postgres_fe.h" #include #include #include "libpq-fe.h" #include "libpq-int.h" #include "mb/pg_wchar.h" #ifdef WIN32 #include "win32.h" #else #include #include #ifdef HAVE_NETINET_TCP_H #include #endif #include #endif /* * This macro lists the backend message types that could be "long" (more * than a couple of kilobytes). */ #define VALID_LONG_MESSAGE_TYPE(id) \ ((id) == 'T' || (id) == 'D' || (id) == 'd' || (id) == 'V' || \ (id) == 'E' || (id) == 'N' || (id) == 'A') static void handleSyncLoss(PGconn *conn, char id, int msgLength); static int getRowDescriptions(PGconn *conn); static int getParamDescriptions(PGconn *conn); static int getAnotherTuple(PGconn *conn, int msgLength); static int getParameterStatus(PGconn *conn); static int getNotify(PGconn *conn); static int getCopyStart(PGconn *conn, ExecStatusType copytype); static int getReadyForQuery(PGconn *conn); static void reportErrorPosition(PQExpBuffer msg, const char *query, int loc, int encoding); static int build_startup_packet(const PGconn *conn, char *packet, const PQEnvironmentOption *options); /* * parseInput: if appropriate, parse input data from backend * until input is exhausted or a stopping state is reached. * Note that this function will NOT attempt to read more data from the backend. */ void pqParseInput3(PGconn *conn) { char id; int msgLength; int avail; /* * Loop to parse successive complete messages available in the buffer. */ for (;;) { /* * Try to read a message. First get the type code and length. Return * if not enough data. */ conn->inCursor = conn->inStart; if (pqGetc(&id, conn)) return; if (pqGetInt(&msgLength, 4, conn)) return; /* * Try to validate message type/length here. A length less than 4 is * definitely broken. Large lengths should only be believed for a few * message types. */ if (msgLength < 4) { handleSyncLoss(conn, id, msgLength); return; } if (msgLength > 30000 && !VALID_LONG_MESSAGE_TYPE(id)) { handleSyncLoss(conn, id, msgLength); return; } /* * Can't process if message body isn't all here yet. */ msgLength -= 4; avail = conn->inEnd - conn->inCursor; if (avail < msgLength) { /* * Before returning, enlarge the input buffer if needed to hold * the whole message. This is better than leaving it to * pqReadData because we can avoid multiple cycles of realloc() * when the message is large; also, we can implement a reasonable * recovery strategy if we are unable to make the buffer big * enough. */ if (pqCheckInBufferSpace(conn->inCursor + (size_t) msgLength, conn)) { /* * XXX add some better recovery code... plan is to skip over * the message using its length, then report an error. For the * moment, just treat this like loss of sync (which indeed it * might be!) */ handleSyncLoss(conn, id, msgLength); } return; } /* * NOTIFY and NOTICE messages can happen in any state; always process * them right away. * * Most other messages should only be processed while in BUSY state. * (In particular, in READY state we hold off further parsing until * the application collects the current PGresult.) * * However, if the state is IDLE then we got trouble; we need to deal * with the unexpected message somehow. * * ParameterStatus ('S') messages are a special case: in IDLE state we * must process 'em (this case could happen if a new value was adopted * from config file due to SIGHUP), but otherwise we hold off until * BUSY state. */ if (id == 'A') { if (getNotify(conn)) return; } else if (id == 'N') { if (pqGetErrorNotice3(conn, false)) return; } else if (conn->asyncStatus != PGASYNC_BUSY) { /* If not IDLE state, just wait ... */ if (conn->asyncStatus != PGASYNC_IDLE) return; /* * Unexpected message in IDLE state; need to recover somehow. * ERROR messages are displayed using the notice processor; * ParameterStatus is handled normally; anything else is just * dropped on the floor after displaying a suitable warning * notice. (An ERROR is very possibly the backend telling us why * it is about to close the connection, so we don't want to just * discard it...) */ if (id == 'E') { if (pqGetErrorNotice3(conn, false /* treat as notice */ )) return; } else if (id == 'S') { if (getParameterStatus(conn)) return; } else { pqInternalNotice(&conn->noticeHooks, "message type 0x%02x arrived from server while idle", id); /* Discard the unexpected message */ conn->inCursor += msgLength; } } else { /* * In BUSY state, we can process everything. */ switch (id) { case 'C': /* command complete */ if (pqGets(&conn->workBuffer, conn)) return; if (conn->result == NULL) { conn->result = PQmakeEmptyPGresult(conn, PGRES_COMMAND_OK); if (!conn->result) return; } strncpy(conn->result->cmdStatus, conn->workBuffer.data, CMDSTATUS_LEN); conn->asyncStatus = PGASYNC_READY; break; case 'E': /* error return */ if (pqGetErrorNotice3(conn, true)) return; conn->asyncStatus = PGASYNC_READY; break; case 'Z': /* backend is ready for new query */ if (getReadyForQuery(conn)) return; conn->asyncStatus = PGASYNC_IDLE; break; case 'I': /* empty query */ if (conn->result == NULL) { conn->result = PQmakeEmptyPGresult(conn, PGRES_EMPTY_QUERY); if (!conn->result) return; } conn->asyncStatus = PGASYNC_READY; break; case '1': /* Parse Complete */ /* If we're doing PQprepare, we're done; else ignore */ if (conn->queryclass == PGQUERY_PREPARE) { if (conn->result == NULL) { conn->result = PQmakeEmptyPGresult(conn, PGRES_COMMAND_OK); if (!conn->result) return; } conn->asyncStatus = PGASYNC_READY; } break; case '2': /* Bind Complete */ case '3': /* Close Complete */ /* Nothing to do for these message types */ break; case 'S': /* parameter status */ if (getParameterStatus(conn)) return; break; case 'K': /* secret key data from the backend */ /* * This is expected only during backend startup, but it's * just as easy to handle it as part of the main loop. * Save the data and continue processing. */ if (pqGetInt(&(conn->be_pid), 4, conn)) return; if (pqGetInt(&(conn->be_key), 4, conn)) return; break; case 'T': /* Row Description */ if (conn->result == NULL || conn->queryclass == PGQUERY_DESCRIBE) { /* First 'T' in a query sequence */ if (getRowDescriptions(conn)) return; /* * If we're doing a Describe, we're ready to pass the * result back to the client. */ if (conn->queryclass == PGQUERY_DESCRIBE) conn->asyncStatus = PGASYNC_READY; } else { /* * A new 'T' message is treated as the start of * another PGresult. (It is not clear that this is * really possible with the current backend.) We stop * parsing until the application accepts the current * result. */ conn->asyncStatus = PGASYNC_READY; return; } break; case 'n': /* No Data */ /* * NoData indicates that we will not be seeing a * RowDescription message because the statement or portal * inquired about doesn't return rows. * * If we're doing a Describe, we have to pass something * back to the client, so set up a COMMAND_OK result, * instead of TUPLES_OK. Otherwise we can just ignore * this message. */ if (conn->queryclass == PGQUERY_DESCRIBE) { if (conn->result == NULL) { conn->result = PQmakeEmptyPGresult(conn, PGRES_COMMAND_OK); if (!conn->result) return; } conn->asyncStatus = PGASYNC_READY; } break; case 't': /* Parameter Description */ if (getParamDescriptions(conn)) return; break; case 'D': /* Data Row */ if (conn->result != NULL && conn->result->resultStatus == PGRES_TUPLES_OK) { /* Read another tuple of a normal query response */ if (getAnotherTuple(conn, msgLength)) return; } else if (conn->result != NULL && conn->result->resultStatus == PGRES_FATAL_ERROR) { /* * We've already choked for some reason. Just discard * tuples till we get to the end of the query. */ conn->inCursor += msgLength; } else { /* Set up to report error at end of query */ printfPQExpBuffer(&conn->errorMessage, libpq_gettext("server sent data (\"D\" message) without prior row description (\"T\" message)\n")); pqSaveErrorResult(conn); /* Discard the unexpected message */ conn->inCursor += msgLength; } break; case 'G': /* Start Copy In */ if (getCopyStart(conn, PGRES_COPY_IN)) return; conn->asyncStatus = PGASYNC_COPY_IN; break; case 'H': /* Start Copy Out */ if (getCopyStart(conn, PGRES_COPY_OUT)) return; conn->asyncStatus = PGASYNC_COPY_OUT; conn->copy_already_done = 0; break; case 'W': /* Start Copy Both */ if (getCopyStart(conn, PGRES_COPY_BOTH)) return; conn->asyncStatus = PGASYNC_COPY_BOTH; conn->copy_already_done = 0; break; case 'd': /* Copy Data */ /* * If we see Copy Data, just silently drop it. This would * only occur if application exits COPY OUT mode too * early. */ conn->inCursor += msgLength; break; case 'c': /* Copy Done */ /* * If we see Copy Done, just silently drop it. This is * the normal case during PQendcopy. We will keep * swallowing data, expecting to see command-complete for * the COPY command. */ break; default: printfPQExpBuffer(&conn->errorMessage, libpq_gettext( "unexpected response from server; first received character was \"%c\"\n"), id); /* build an error result holding the error message */ pqSaveErrorResult(conn); /* not sure if we will see more, so go to ready state */ conn->asyncStatus = PGASYNC_READY; /* Discard the unexpected message */ conn->inCursor += msgLength; break; } /* switch on protocol character */ } /* Successfully consumed this message */ if (conn->inCursor == conn->inStart + 5 + msgLength) { /* Normal case: parsing agrees with specified length */ conn->inStart = conn->inCursor; } else { /* Trouble --- report it */ printfPQExpBuffer(&conn->errorMessage, libpq_gettext("message contents do not agree with length in message type \"%c\"\n"), id); /* build an error result holding the error message */ pqSaveErrorResult(conn); conn->asyncStatus = PGASYNC_READY; /* trust the specified message length as what to skip */ conn->inStart += 5 + msgLength; } } } /* * handleSyncLoss: clean up after loss of message-boundary sync * * There isn't really a lot we can do here except abandon the connection. */ static void handleSyncLoss(PGconn *conn, char id, int msgLength) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext( "lost synchronization with server: got message type \"%c\", length %d\n"), id, msgLength); /* build an error result holding the error message */ pqSaveErrorResult(conn); conn->asyncStatus = PGASYNC_READY; /* drop out of GetResult wait loop */ pqsecure_close(conn); closesocket(conn->sock); conn->sock = -1; conn->status = CONNECTION_BAD; /* No more connection to backend */ } /* * parseInput subroutine to read a 'T' (row descriptions) message. * We'll build a new PGresult structure (unless called for a Describe * command for a prepared statement) containing the attribute data. * Returns: 0 if completed message, EOF if not enough data yet. * * Note that if we run out of data, we have to release the partially * constructed PGresult, and rebuild it again next time. Fortunately, * that shouldn't happen often, since 'T' messages usually fit in a packet. */ static int getRowDescriptions(PGconn *conn) { PGresult *result; int nfields; int i; /* * When doing Describe for a prepared statement, there'll already be a * PGresult created by getParamDescriptions, and we should fill data into * that. Otherwise, create a new, empty PGresult. */ if (conn->queryclass == PGQUERY_DESCRIBE) { if (conn->result) result = conn->result; else result = PQmakeEmptyPGresult(conn, PGRES_COMMAND_OK); } else result = PQmakeEmptyPGresult(conn, PGRES_TUPLES_OK); if (!result) goto failure; /* parseInput already read the 'T' label and message length. */ /* the next two bytes are the number of fields */ if (pqGetInt(&(result->numAttributes), 2, conn)) goto failure; nfields = result->numAttributes; /* allocate space for the attribute descriptors */ if (nfields > 0) { result->attDescs = (PGresAttDesc *) pqResultAlloc(result, nfields * sizeof(PGresAttDesc), TRUE); if (!result->attDescs) goto failure; MemSet(result->attDescs, 0, nfields * sizeof(PGresAttDesc)); } /* result->binary is true only if ALL columns are binary */ result->binary = (nfields > 0) ? 1 : 0; /* get type info */ for (i = 0; i < nfields; i++) { int tableid; int columnid; int typid; int typlen; int atttypmod; int format; if (pqGets(&conn->workBuffer, conn) || pqGetInt(&tableid, 4, conn) || pqGetInt(&columnid, 2, conn) || pqGetInt(&typid, 4, conn) || pqGetInt(&typlen, 2, conn) || pqGetInt(&atttypmod, 4, conn) || pqGetInt(&format, 2, conn)) { goto failure; } /* * Since pqGetInt treats 2-byte integers as unsigned, we need to * coerce these results to signed form. */ columnid = (int) ((int16) columnid); typlen = (int) ((int16) typlen); format = (int) ((int16) format); result->attDescs[i].name = pqResultStrdup(result, conn->workBuffer.data); if (!result->attDescs[i].name) goto failure; result->attDescs[i].tableid = tableid; result->attDescs[i].columnid = columnid; result->attDescs[i].format = format; result->attDescs[i].typid = typid; result->attDescs[i].typlen = typlen; result->attDescs[i].atttypmod = atttypmod; if (format != 1) result->binary = 0; } /* Success! */ conn->result = result; return 0; failure: /* * Discard incomplete result, unless it's from getParamDescriptions. * * Note that if we hit a bufferload boundary while handling the * describe-statement case, we'll forget any PGresult space we just * allocated, and then reallocate it on next try. This will bloat the * PGresult a little bit but the space will be freed at PQclear, so it * doesn't seem worth trying to be smarter. */ if (result != conn->result) PQclear(result); return EOF; } /* * parseInput subroutine to read a 't' (ParameterDescription) message. * We'll build a new PGresult structure containing the parameter data. * Returns: 0 if completed message, EOF if not enough data yet. * * Note that if we run out of data, we have to release the partially * constructed PGresult, and rebuild it again next time. Fortunately, * that shouldn't happen often, since 't' messages usually fit in a packet. */ static int getParamDescriptions(PGconn *conn) { PGresult *result; int nparams; int i; result = PQmakeEmptyPGresult(conn, PGRES_COMMAND_OK); if (!result) goto failure; /* parseInput already read the 't' label and message length. */ /* the next two bytes are the number of parameters */ if (pqGetInt(&(result->numParameters), 2, conn)) goto failure; nparams = result->numParameters; /* allocate space for the parameter descriptors */ if (nparams > 0) { result->paramDescs = (PGresParamDesc *) pqResultAlloc(result, nparams * sizeof(PGresParamDesc), TRUE); if (!result->paramDescs) goto failure; MemSet(result->paramDescs, 0, nparams * sizeof(PGresParamDesc)); } /* get parameter info */ for (i = 0; i < nparams; i++) { int typid; if (pqGetInt(&typid, 4, conn)) goto failure; result->paramDescs[i].typid = typid; } /* Success! */ conn->result = result; return 0; failure: PQclear(result); return EOF; } /* * parseInput subroutine to read a 'D' (row data) message. * We add another tuple to the existing PGresult structure. * Returns: 0 if completed message, EOF if error or not enough data yet. * * Note that if we run out of data, we have to suspend and reprocess * the message after more data is received. We keep a partially constructed * tuple in conn->curTuple, and avoid reallocating already-allocated storage. */ static int getAnotherTuple(PGconn *conn, int msgLength) { PGresult *result = conn->result; int nfields = result->numAttributes; PGresAttValue *tup; int tupnfields; /* # fields from tuple */ int vlen; /* length of the current field value */ int i; /* Allocate tuple space if first time for this data message */ if (conn->curTuple == NULL) { conn->curTuple = (PGresAttValue *) pqResultAlloc(result, nfields * sizeof(PGresAttValue), TRUE); if (conn->curTuple == NULL) goto outOfMemory; MemSet(conn->curTuple, 0, nfields * sizeof(PGresAttValue)); } tup = conn->curTuple; /* Get the field count and make sure it's what we expect */ if (pqGetInt(&tupnfields, 2, conn)) return EOF; if (tupnfields != nfields) { /* Replace partially constructed result with an error result */ printfPQExpBuffer(&conn->errorMessage, libpq_gettext("unexpected field count in \"D\" message\n")); pqSaveErrorResult(conn); /* Discard the failed message by pretending we read it */ conn->inCursor = conn->inStart + 5 + msgLength; return 0; } /* Scan the fields */ for (i = 0; i < nfields; i++) { /* get the value length */ if (pqGetInt(&vlen, 4, conn)) return EOF; if (vlen == -1) { /* null field */ tup[i].value = result->null_field; tup[i].len = NULL_LEN; continue; } if (vlen < 0) vlen = 0; if (tup[i].value == NULL) { bool isbinary = (result->attDescs[i].format != 0); tup[i].value = (char *) pqResultAlloc(result, vlen + 1, isbinary); if (tup[i].value == NULL) goto outOfMemory; } tup[i].len = vlen; /* read in the value */ if (vlen > 0) if (pqGetnchar((char *) (tup[i].value), vlen, conn)) return EOF; /* we have to terminate this ourselves */ tup[i].value[vlen] = '\0'; } /* Success! Store the completed tuple in the result */ if (!pqAddTuple(result, tup)) goto outOfMemory; /* and reset for a new message */ conn->curTuple = NULL; return 0; outOfMemory: /* * Replace partially constructed result with an error result. First * discard the old result to try to win back some memory. */ pqClearAsyncResult(conn); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("out of memory for query result\n")); pqSaveErrorResult(conn); /* Discard the failed message by pretending we read it */ conn->inCursor = conn->inStart + 5 + msgLength; return 0; } /* * Attempt to read an Error or Notice response message. * This is possible in several places, so we break it out as a subroutine. * Entry: 'E' or 'N' message type and length have already been consumed. * Exit: returns 0 if successfully consumed message. * returns EOF if not enough data. */ int pqGetErrorNotice3(PGconn *conn, bool isError) { PGresult *res = NULL; PQExpBufferData workBuf; char id; const char *val; const char *querytext = NULL; int querypos = 0; /* * Since the fields might be pretty long, we create a temporary * PQExpBuffer rather than using conn->workBuffer. workBuffer is intended * for stuff that is expected to be short. We shouldn't use * conn->errorMessage either, since this might be only a notice. */ initPQExpBuffer(&workBuf); /* * Make a PGresult to hold the accumulated fields. We temporarily lie * about the result status, so that PQmakeEmptyPGresult doesn't uselessly * copy conn->errorMessage. */ res = PQmakeEmptyPGresult(conn, PGRES_EMPTY_QUERY); if (!res) goto fail; res->resultStatus = isError ? PGRES_FATAL_ERROR : PGRES_NONFATAL_ERROR; /* * Read the fields and save into res. */ for (;;) { if (pqGetc(&id, conn)) goto fail; if (id == '\0') break; /* terminator found */ if (pqGets(&workBuf, conn)) goto fail; pqSaveMessageField(res, id, workBuf.data); } /* * Now build the "overall" error message for PQresultErrorMessage. * * Also, save the SQLSTATE in conn->last_sqlstate. */ resetPQExpBuffer(&workBuf); val = PQresultErrorField(res, PG_DIAG_SEVERITY); if (val) appendPQExpBuffer(&workBuf, "%s: ", val); val = PQresultErrorField(res, PG_DIAG_SQLSTATE); if (val) { if (strlen(val) < sizeof(conn->last_sqlstate)) strcpy(conn->last_sqlstate, val); if (conn->verbosity == PQERRORS_VERBOSE) appendPQExpBuffer(&workBuf, "%s: ", val); } val = PQresultErrorField(res, PG_DIAG_MESSAGE_PRIMARY); if (val) appendPQExpBufferStr(&workBuf, val); val = PQresultErrorField(res, PG_DIAG_STATEMENT_POSITION); if (val) { if (conn->verbosity != PQERRORS_TERSE && conn->last_query != NULL) { /* emit position as a syntax cursor display */ querytext = conn->last_query; querypos = atoi(val); } else { /* emit position as text addition to primary message */ /* translator: %s represents a digit string */ appendPQExpBuffer(&workBuf, libpq_gettext(" at character %s"), val); } } else { val = PQresultErrorField(res, PG_DIAG_INTERNAL_POSITION); if (val) { querytext = PQresultErrorField(res, PG_DIAG_INTERNAL_QUERY); if (conn->verbosity != PQERRORS_TERSE && querytext != NULL) { /* emit position as a syntax cursor display */ querypos = atoi(val); } else { /* emit position as text addition to primary message */ /* translator: %s represents a digit string */ appendPQExpBuffer(&workBuf, libpq_gettext(" at character %s"), val); } } } appendPQExpBufferChar(&workBuf, '\n'); if (conn->verbosity != PQERRORS_TERSE) { if (querytext && querypos > 0) reportErrorPosition(&workBuf, querytext, querypos, conn->client_encoding); val = PQresultErrorField(res, PG_DIAG_MESSAGE_DETAIL); if (val) appendPQExpBuffer(&workBuf, libpq_gettext("DETAIL: %s\n"), val); val = PQresultErrorField(res, PG_DIAG_MESSAGE_HINT); if (val) appendPQExpBuffer(&workBuf, libpq_gettext("HINT: %s\n"), val); val = PQresultErrorField(res, PG_DIAG_INTERNAL_QUERY); if (val) appendPQExpBuffer(&workBuf, libpq_gettext("QUERY: %s\n"), val); val = PQresultErrorField(res, PG_DIAG_CONTEXT); if (val) appendPQExpBuffer(&workBuf, libpq_gettext("CONTEXT: %s\n"), val); } if (conn->verbosity == PQERRORS_VERBOSE) { const char *valf; const char *vall; valf = PQresultErrorField(res, PG_DIAG_SOURCE_FILE); vall = PQresultErrorField(res, PG_DIAG_SOURCE_LINE); val = PQresultErrorField(res, PG_DIAG_SOURCE_FUNCTION); if (val || valf || vall) { appendPQExpBufferStr(&workBuf, libpq_gettext("LOCATION: ")); if (val) appendPQExpBuffer(&workBuf, libpq_gettext("%s, "), val); if (valf && vall) /* unlikely we'd have just one */ appendPQExpBuffer(&workBuf, libpq_gettext("%s:%s"), valf, vall); appendPQExpBufferChar(&workBuf, '\n'); } } /* * Either save error as current async result, or just emit the notice. */ if (isError) { res->errMsg = pqResultStrdup(res, workBuf.data); if (!res->errMsg) goto fail; pqClearAsyncResult(conn); conn->result = res; appendPQExpBufferStr(&conn->errorMessage, workBuf.data); } else { /* We can cheat a little here and not copy the message. */ res->errMsg = workBuf.data; if (res->noticeHooks.noticeRec != NULL) (*res->noticeHooks.noticeRec) (res->noticeHooks.noticeRecArg, res); PQclear(res); } termPQExpBuffer(&workBuf); return 0; fail: PQclear(res); termPQExpBuffer(&workBuf); return EOF; } /* * Add an error-location display to the error message under construction. * * The cursor location is measured in logical characters; the query string * is presumed to be in the specified encoding. */ static void reportErrorPosition(PQExpBuffer msg, const char *query, int loc, int encoding) { #define DISPLAY_SIZE 60 /* screen width limit, in screen cols */ #define MIN_RIGHT_CUT 10 /* try to keep this far away from EOL */ char *wquery; int slen, cno, i, *qidx, *scridx, qoffset, scroffset, ibeg, iend, loc_line; bool mb_encoding, beg_trunc, end_trunc; /* Convert loc from 1-based to 0-based; no-op if out of range */ loc--; if (loc < 0) return; /* Need a writable copy of the query */ wquery = strdup(query); if (wquery == NULL) return; /* fail silently if out of memory */ /* * Each character might occupy multiple physical bytes in the string, and * in some Far Eastern character sets it might take more than one screen * column as well. We compute the starting byte offset and starting * screen column of each logical character, and store these in qidx[] and * scridx[] respectively. */ /* we need a safe allocation size... */ slen = strlen(wquery) + 1; qidx = (int *) malloc(slen * sizeof(int)); if (qidx == NULL) { free(wquery); return; } scridx = (int *) malloc(slen * sizeof(int)); if (scridx == NULL) { free(qidx); free(wquery); return; } /* We can optimize a bit if it's a single-byte encoding */ mb_encoding = (pg_encoding_max_length(encoding) != 1); /* * Within the scanning loop, cno is the current character's logical * number, qoffset is its offset in wquery, and scroffset is its starting * logical screen column (all indexed from 0). "loc" is the logical * character number of the error location. We scan to determine loc_line * (the 1-based line number containing loc) and ibeg/iend (first character * number and last+1 character number of the line containing loc). Note * that qidx[] and scridx[] are filled only as far as iend. */ qoffset = 0; scroffset = 0; loc_line = 1; ibeg = 0; iend = -1; /* -1 means not set yet */ for (cno = 0; wquery[qoffset] != '\0'; cno++) { char ch = wquery[qoffset]; qidx[cno] = qoffset; scridx[cno] = scroffset; /* * Replace tabs with spaces in the writable copy. (Later we might * want to think about coping with their variable screen width, but * not today.) */ if (ch == '\t') wquery[qoffset] = ' '; /* * If end-of-line, count lines and mark positions. Each \r or \n * counts as a line except when \r \n appear together. */ else if (ch == '\r' || ch == '\n') { if (cno < loc) { if (ch == '\r' || cno == 0 || wquery[qidx[cno - 1]] != '\r') loc_line++; /* extract beginning = last line start before loc. */ ibeg = cno + 1; } else { /* set extract end. */ iend = cno; /* done scanning. */ break; } } /* Advance */ if (mb_encoding) { int w; w = pg_encoding_dsplen(encoding, &wquery[qoffset]); /* treat any non-tab control chars as width 1 */ if (w <= 0) w = 1; scroffset += w; qoffset += pg_encoding_mblen(encoding, &wquery[qoffset]); } else { /* We assume wide chars only exist in multibyte encodings */ scroffset++; qoffset++; } } /* Fix up if we didn't find an end-of-line after loc */ if (iend < 0) { iend = cno; /* query length in chars, +1 */ qidx[iend] = qoffset; scridx[iend] = scroffset; } /* Print only if loc is within computed query length */ if (loc <= cno) { /* If the line extracted is too long, we truncate it. */ beg_trunc = false; end_trunc = false; if (scridx[iend] - scridx[ibeg] > DISPLAY_SIZE) { /* * We first truncate right if it is enough. This code might be * off a space or so on enforcing MIN_RIGHT_CUT if there's a wide * character right there, but that should be okay. */ if (scridx[ibeg] + DISPLAY_SIZE >= scridx[loc] + MIN_RIGHT_CUT) { while (scridx[iend] - scridx[ibeg] > DISPLAY_SIZE) iend--; end_trunc = true; } else { /* Truncate right if not too close to loc. */ while (scridx[loc] + MIN_RIGHT_CUT < scridx[iend]) { iend--; end_trunc = true; } /* Truncate left if still too long. */ while (scridx[iend] - scridx[ibeg] > DISPLAY_SIZE) { ibeg++; beg_trunc = true; } } } /* truncate working copy at desired endpoint */ wquery[qidx[iend]] = '\0'; /* Begin building the finished message. */ i = msg->len; appendPQExpBuffer(msg, libpq_gettext("LINE %d: "), loc_line); if (beg_trunc) appendPQExpBufferStr(msg, "..."); /* * While we have the prefix in the msg buffer, compute its screen * width. */ scroffset = 0; for (; i < msg->len; i += pg_encoding_mblen(encoding, &msg->data[i])) { int w = pg_encoding_dsplen(encoding, &msg->data[i]); if (w <= 0) w = 1; scroffset += w; } /* Finish up the LINE message line. */ appendPQExpBufferStr(msg, &wquery[qidx[ibeg]]); if (end_trunc) appendPQExpBufferStr(msg, "..."); appendPQExpBufferChar(msg, '\n'); /* Now emit the cursor marker line. */ scroffset += scridx[loc] - scridx[ibeg]; for (i = 0; i < scroffset; i++) appendPQExpBufferChar(msg, ' '); appendPQExpBufferChar(msg, '^'); appendPQExpBufferChar(msg, '\n'); } /* Clean up. */ free(scridx); free(qidx); free(wquery); } /* * Attempt to read a ParameterStatus message. * This is possible in several places, so we break it out as a subroutine. * Entry: 'S' message type and length have already been consumed. * Exit: returns 0 if successfully consumed message. * returns EOF if not enough data. */ static int getParameterStatus(PGconn *conn) { PQExpBufferData valueBuf; /* Get the parameter name */ if (pqGets(&conn->workBuffer, conn)) return EOF; /* Get the parameter value (could be large) */ initPQExpBuffer(&valueBuf); if (pqGets(&valueBuf, conn)) { termPQExpBuffer(&valueBuf); return EOF; } /* And save it */ pqSaveParameterStatus(conn, conn->workBuffer.data, valueBuf.data); termPQExpBuffer(&valueBuf); return 0; } /* * Attempt to read a Notify response message. * This is possible in several places, so we break it out as a subroutine. * Entry: 'A' message type and length have already been consumed. * Exit: returns 0 if successfully consumed Notify message. * returns EOF if not enough data. */ static int getNotify(PGconn *conn) { int be_pid; char *svname; int nmlen; int extralen; PGnotify *newNotify; if (pqGetInt(&be_pid, 4, conn)) return EOF; if (pqGets(&conn->workBuffer, conn)) return EOF; /* must save name while getting extra string */ svname = strdup(conn->workBuffer.data); if (!svname) return EOF; if (pqGets(&conn->workBuffer, conn)) { free(svname); return EOF; } /* * Store the strings right after the PQnotify structure so it can all be * freed at once. We don't use NAMEDATALEN because we don't want to tie * this interface to a specific server name length. */ nmlen = strlen(svname); extralen = strlen(conn->workBuffer.data); newNotify = (PGnotify *) malloc(sizeof(PGnotify) + nmlen + extralen + 2); if (newNotify) { newNotify->relname = (char *) newNotify + sizeof(PGnotify); strcpy(newNotify->relname, svname); newNotify->extra = newNotify->relname + nmlen + 1; strcpy(newNotify->extra, conn->workBuffer.data); newNotify->be_pid = be_pid; newNotify->next = NULL; if (conn->notifyTail) conn->notifyTail->next = newNotify; else conn->notifyHead = newNotify; conn->notifyTail = newNotify; } free(svname); return 0; } /* * getCopyStart - process CopyInResponse, CopyOutResponse or * CopyBothResponse message * * parseInput already read the message type and length. */ static int getCopyStart(PGconn *conn, ExecStatusType copytype) { PGresult *result; int nfields; int i; result = PQmakeEmptyPGresult(conn, copytype); if (!result) goto failure; if (pqGetc(&conn->copy_is_binary, conn)) goto failure; result->binary = conn->copy_is_binary; /* the next two bytes are the number of fields */ if (pqGetInt(&(result->numAttributes), 2, conn)) goto failure; nfields = result->numAttributes; /* allocate space for the attribute descriptors */ if (nfields > 0) { result->attDescs = (PGresAttDesc *) pqResultAlloc(result, nfields * sizeof(PGresAttDesc), TRUE); if (!result->attDescs) goto failure; MemSet(result->attDescs, 0, nfields * sizeof(PGresAttDesc)); } for (i = 0; i < nfields; i++) { int format; if (pqGetInt(&format, 2, conn)) goto failure; /* * Since pqGetInt treats 2-byte integers as unsigned, we need to * coerce these results to signed form. */ format = (int) ((int16) format); result->attDescs[i].format = format; } /* Success! */ conn->result = result; return 0; failure: PQclear(result); return EOF; } /* * getReadyForQuery - process ReadyForQuery message */ static int getReadyForQuery(PGconn *conn) { char xact_status; if (pqGetc(&xact_status, conn)) return EOF; switch (xact_status) { case 'I': conn->xactStatus = PQTRANS_IDLE; break; case 'T': conn->xactStatus = PQTRANS_INTRANS; break; case 'E': conn->xactStatus = PQTRANS_INERROR; break; default: conn->xactStatus = PQTRANS_UNKNOWN; break; } return 0; } /* * getCopyDataMessage - fetch next CopyData message, process async messages * * Returns length word of CopyData message (> 0), or 0 if no complete * message available, -1 if end of copy, -2 if error. */ static int getCopyDataMessage(PGconn *conn) { char id; int msgLength; int avail; for (;;) { /* * Do we have the next input message? To make life simpler for async * callers, we keep returning 0 until the next message is fully * available, even if it is not Copy Data. */ conn->inCursor = conn->inStart; if (pqGetc(&id, conn)) return 0; if (pqGetInt(&msgLength, 4, conn)) return 0; if (msgLength < 4) { handleSyncLoss(conn, id, msgLength); return -2; } avail = conn->inEnd - conn->inCursor; if (avail < msgLength - 4) { /* * Before returning, enlarge the input buffer if needed to hold * the whole message. See notes in parseInput. */ if (pqCheckInBufferSpace(conn->inCursor + (size_t) msgLength - 4, conn)) { /* * XXX add some better recovery code... plan is to skip over * the message using its length, then report an error. For the * moment, just treat this like loss of sync (which indeed it * might be!) */ handleSyncLoss(conn, id, msgLength); return -2; } return 0; } /* * If it's a legitimate async message type, process it. (NOTIFY * messages are not currently possible here, but we handle them for * completeness.) Otherwise, if it's anything except Copy Data, * report end-of-copy. */ switch (id) { case 'A': /* NOTIFY */ if (getNotify(conn)) return 0; break; case 'N': /* NOTICE */ if (pqGetErrorNotice3(conn, false)) return 0; break; case 'S': /* ParameterStatus */ if (getParameterStatus(conn)) return 0; break; case 'd': /* Copy Data, pass it back to caller */ return msgLength; default: /* treat as end of copy */ return -1; } /* Drop the processed message and loop around for another */ conn->inStart = conn->inCursor; } } /* * PQgetCopyData - read a row of data from the backend during COPY OUT * or COPY BOTH * * If successful, sets *buffer to point to a malloc'd row of data, and * returns row length (always > 0) as result. * Returns 0 if no row available yet (only possible if async is true), * -1 if end of copy (consult PQgetResult), or -2 if error (consult * PQerrorMessage). */ int pqGetCopyData3(PGconn *conn, char **buffer, int async) { int msgLength; for (;;) { /* * Collect the next input message. To make life simpler for async * callers, we keep returning 0 until the next message is fully * available, even if it is not Copy Data. */ msgLength = getCopyDataMessage(conn); if (msgLength < 0) { /* * On end-of-copy, exit COPY_OUT or COPY_BOTH mode and let caller * read status with PQgetResult(). The normal case is that it's * Copy Done, but we let parseInput read that. If error, we * expect the state was already changed. */ if (msgLength == -1) conn->asyncStatus = PGASYNC_BUSY; return msgLength; /* end-of-copy or error */ } if (msgLength == 0) { /* Don't block if async read requested */ if (async) return 0; /* Need to load more data */ if (pqWait(TRUE, FALSE, conn) || pqReadData(conn) < 0) return -2; continue; } /* * Drop zero-length messages (shouldn't happen anyway). Otherwise * pass the data back to the caller. */ msgLength -= 4; if (msgLength > 0) { *buffer = (char *) malloc(msgLength + 1); if (*buffer == NULL) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("out of memory\n")); return -2; } memcpy(*buffer, &conn->inBuffer[conn->inCursor], msgLength); (*buffer)[msgLength] = '\0'; /* Add terminating null */ /* Mark message consumed */ conn->inStart = conn->inCursor + msgLength; return msgLength; } /* Empty, so drop it and loop around for another */ conn->inStart = conn->inCursor; } } /* * PQgetline - gets a newline-terminated string from the backend. * * See fe-exec.c for documentation. */ int pqGetline3(PGconn *conn, char *s, int maxlen) { int status; if (conn->sock < 0 || conn->asyncStatus != PGASYNC_COPY_OUT || conn->copy_is_binary) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("PQgetline: not doing text COPY OUT\n")); *s = '\0'; return EOF; } while ((status = PQgetlineAsync(conn, s, maxlen - 1)) == 0) { /* need to load more data */ if (pqWait(TRUE, FALSE, conn) || pqReadData(conn) < 0) { *s = '\0'; return EOF; } } if (status < 0) { /* End of copy detected; gin up old-style terminator */ strcpy(s, "\\."); return 0; } /* Add null terminator, and strip trailing \n if present */ if (s[status - 1] == '\n') { s[status - 1] = '\0'; return 0; } else { s[status] = '\0'; return 1; } } /* * PQgetlineAsync - gets a COPY data row without blocking. * * See fe-exec.c for documentation. */ int pqGetlineAsync3(PGconn *conn, char *buffer, int bufsize) { int msgLength; int avail; if (conn->asyncStatus != PGASYNC_COPY_OUT) return -1; /* we are not doing a copy... */ /* * Recognize the next input message. To make life simpler for async * callers, we keep returning 0 until the next message is fully available * even if it is not Copy Data. This should keep PQendcopy from blocking. * (Note: unlike pqGetCopyData3, we do not change asyncStatus here.) */ msgLength = getCopyDataMessage(conn); if (msgLength < 0) return -1; /* end-of-copy or error */ if (msgLength == 0) return 0; /* no data yet */ /* * Move data from libpq's buffer to the caller's. In the case where a * prior call found the caller's buffer too small, we use * conn->copy_already_done to remember how much of the row was already * returned to the caller. */ conn->inCursor += conn->copy_already_done; avail = msgLength - 4 - conn->copy_already_done; if (avail <= bufsize) { /* Able to consume the whole message */ memcpy(buffer, &conn->inBuffer[conn->inCursor], avail); /* Mark message consumed */ conn->inStart = conn->inCursor + avail; /* Reset state for next time */ conn->copy_already_done = 0; return avail; } else { /* We must return a partial message */ memcpy(buffer, &conn->inBuffer[conn->inCursor], bufsize); /* The message is NOT consumed from libpq's buffer */ conn->copy_already_done += bufsize; return bufsize; } } /* * PQendcopy * * See fe-exec.c for documentation. */ int pqEndcopy3(PGconn *conn) { PGresult *result; if (conn->asyncStatus != PGASYNC_COPY_IN && conn->asyncStatus != PGASYNC_COPY_OUT) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("no COPY in progress\n")); return 1; } /* Send the CopyDone message if needed */ if (conn->asyncStatus == PGASYNC_COPY_IN) { if (pqPutMsgStart('c', false, conn) < 0 || pqPutMsgEnd(conn) < 0) return 1; /* * If we sent the COPY command in extended-query mode, we must issue a * Sync as well. */ if (conn->queryclass != PGQUERY_SIMPLE) { if (pqPutMsgStart('S', false, conn) < 0 || pqPutMsgEnd(conn) < 0) return 1; } } /* * make sure no data is waiting to be sent, abort if we are non-blocking * and the flush fails */ if (pqFlush(conn) && pqIsnonblocking(conn)) return 1; /* Return to active duty */ conn->asyncStatus = PGASYNC_BUSY; resetPQExpBuffer(&conn->errorMessage); /* * Non blocking connections may have to abort at this point. If everyone * played the game there should be no problem, but in error scenarios the * expected messages may not have arrived yet. (We are assuming that the * backend's packetizing will ensure that CommandComplete arrives along * with the CopyDone; are there corner cases where that doesn't happen?) */ if (pqIsnonblocking(conn) && PQisBusy(conn)) return 1; /* Wait for the completion response */ result = PQgetResult(conn); /* Expecting a successful result */ if (result && result->resultStatus == PGRES_COMMAND_OK) { PQclear(result); return 0; } /* * Trouble. For backwards-compatibility reasons, we issue the error * message as if it were a notice (would be nice to get rid of this * silliness, but too many apps probably don't handle errors from * PQendcopy reasonably). Note that the app can still obtain the error * status from the PGconn object. */ if (conn->errorMessage.len > 0) { /* We have to strip the trailing newline ... pain in neck... */ char svLast = conn->errorMessage.data[conn->errorMessage.len - 1]; if (svLast == '\n') conn->errorMessage.data[conn->errorMessage.len - 1] = '\0'; pqInternalNotice(&conn->noticeHooks, "%s", conn->errorMessage.data); conn->errorMessage.data[conn->errorMessage.len - 1] = svLast; } PQclear(result); return 1; } /* * PQfn - Send a function call to the POSTGRES backend. * * See fe-exec.c for documentation. */ PGresult * pqFunctionCall3(PGconn *conn, Oid fnid, int *result_buf, int *actual_result_len, int result_is_int, const PQArgBlock *args, int nargs) { bool needInput = false; ExecStatusType status = PGRES_FATAL_ERROR; char id; int msgLength; int avail; int i; /* PQfn already validated connection state */ if (pqPutMsgStart('F', false, conn) < 0 || /* function call msg */ pqPutInt(fnid, 4, conn) < 0 || /* function id */ pqPutInt(1, 2, conn) < 0 || /* # of format codes */ pqPutInt(1, 2, conn) < 0 || /* format code: BINARY */ pqPutInt(nargs, 2, conn) < 0) /* # of args */ { pqHandleSendFailure(conn); return NULL; } for (i = 0; i < nargs; ++i) { /* len.int4 + contents */ if (pqPutInt(args[i].len, 4, conn)) { pqHandleSendFailure(conn); return NULL; } if (args[i].len == -1) continue; /* it's NULL */ if (args[i].isint) { if (pqPutInt(args[i].u.integer, args[i].len, conn)) { pqHandleSendFailure(conn); return NULL; } } else { if (pqPutnchar((char *) args[i].u.ptr, args[i].len, conn)) { pqHandleSendFailure(conn); return NULL; } } } if (pqPutInt(1, 2, conn) < 0) /* result format code: BINARY */ { pqHandleSendFailure(conn); return NULL; } if (pqPutMsgEnd(conn) < 0 || pqFlush(conn)) { pqHandleSendFailure(conn); return NULL; } for (;;) { if (needInput) { /* Wait for some data to arrive (or for the channel to close) */ if (pqWait(TRUE, FALSE, conn) || pqReadData(conn) < 0) break; } /* * Scan the message. If we run out of data, loop around to try again. */ needInput = true; conn->inCursor = conn->inStart; if (pqGetc(&id, conn)) continue; if (pqGetInt(&msgLength, 4, conn)) continue; /* * Try to validate message type/length here. A length less than 4 is * definitely broken. Large lengths should only be believed for a few * message types. */ if (msgLength < 4) { handleSyncLoss(conn, id, msgLength); break; } if (msgLength > 30000 && !VALID_LONG_MESSAGE_TYPE(id)) { handleSyncLoss(conn, id, msgLength); break; } /* * Can't process if message body isn't all here yet. */ msgLength -= 4; avail = conn->inEnd - conn->inCursor; if (avail < msgLength) { /* * Before looping, enlarge the input buffer if needed to hold the * whole message. See notes in parseInput. */ if (pqCheckInBufferSpace(conn->inCursor + (size_t) msgLength, conn)) { /* * XXX add some better recovery code... plan is to skip over * the message using its length, then report an error. For the * moment, just treat this like loss of sync (which indeed it * might be!) */ handleSyncLoss(conn, id, msgLength); break; } continue; } /* * We should see V or E response to the command, but might get N * and/or A notices first. We also need to swallow the final Z before * returning. */ switch (id) { case 'V': /* function result */ if (pqGetInt(actual_result_len, 4, conn)) continue; if (*actual_result_len != -1) { if (result_is_int) { if (pqGetInt(result_buf, *actual_result_len, conn)) continue; } else { if (pqGetnchar((char *) result_buf, *actual_result_len, conn)) continue; } } /* correctly finished function result message */ status = PGRES_COMMAND_OK; break; case 'E': /* error return */ if (pqGetErrorNotice3(conn, true)) continue; status = PGRES_FATAL_ERROR; break; case 'A': /* notify message */ /* handle notify and go back to processing return values */ if (getNotify(conn)) continue; break; case 'N': /* notice */ /* handle notice and go back to processing return values */ if (pqGetErrorNotice3(conn, false)) continue; break; case 'Z': /* backend is ready for new query */ if (getReadyForQuery(conn)) continue; /* consume the message and exit */ conn->inStart += 5 + msgLength; /* if we saved a result object (probably an error), use it */ if (conn->result) return pqPrepareAsyncResult(conn); return PQmakeEmptyPGresult(conn, status); case 'S': /* parameter status */ if (getParameterStatus(conn)) continue; break; default: /* The backend violates the protocol. */ printfPQExpBuffer(&conn->errorMessage, libpq_gettext("protocol error: id=0x%x\n"), id); pqSaveErrorResult(conn); /* trust the specified message length as what to skip */ conn->inStart += 5 + msgLength; return pqPrepareAsyncResult(conn); } /* Completed this message, keep going */ /* trust the specified message length as what to skip */ conn->inStart += 5 + msgLength; needInput = false; } /* * We fall out of the loop only upon failing to read data. * conn->errorMessage has been set by pqWait or pqReadData. We want to * append it to any already-received error message. */ pqSaveErrorResult(conn); return pqPrepareAsyncResult(conn); } /* * Construct startup packet * * Returns a malloc'd packet buffer, or NULL if out of memory */ char * pqBuildStartupPacket3(PGconn *conn, int *packetlen, const PQEnvironmentOption *options) { char *startpacket; *packetlen = build_startup_packet(conn, NULL, options); startpacket = (char *) malloc(*packetlen); if (!startpacket) return NULL; *packetlen = build_startup_packet(conn, startpacket, options); return startpacket; } /* * Build a startup packet given a filled-in PGconn structure. * * We need to figure out how much space is needed, then fill it in. * To avoid duplicate logic, this routine is called twice: the first time * (with packet == NULL) just counts the space needed, the second time * (with packet == allocated space) fills it in. Return value is the number * of bytes used. */ static int build_startup_packet(const PGconn *conn, char *packet, const PQEnvironmentOption *options) { int packet_len = 0; const PQEnvironmentOption *next_eo; const char *val; /* Protocol version comes first. */ if (packet) { ProtocolVersion pv = htonl(conn->pversion); memcpy(packet + packet_len, &pv, sizeof(ProtocolVersion)); } packet_len += sizeof(ProtocolVersion); /* Add user name, database name, options */ #define ADD_STARTUP_OPTION(optname, optval) \ do { \ if (packet) \ strcpy(packet + packet_len, optname); \ packet_len += strlen(optname) + 1; \ if (packet) \ strcpy(packet + packet_len, optval); \ packet_len += strlen(optval) + 1; \ } while(0) if (conn->pguser && conn->pguser[0]) ADD_STARTUP_OPTION("user", conn->pguser); if (conn->dbName && conn->dbName[0]) ADD_STARTUP_OPTION("database", conn->dbName); if (conn->replication && conn->replication[0]) ADD_STARTUP_OPTION("replication", conn->replication); if (conn->pgoptions && conn->pgoptions[0]) ADD_STARTUP_OPTION("options", conn->pgoptions); if (conn->send_appname) { /* Use appname if present, otherwise use fallback */ val = conn->appname ? conn->appname : conn->fbappname; if (val && val[0]) ADD_STARTUP_OPTION("application_name", val); } if (conn->client_encoding_initial && conn->client_encoding_initial[0]) ADD_STARTUP_OPTION("client_encoding", conn->client_encoding_initial); /* Add any environment-driven GUC settings needed */ for (next_eo = options; next_eo->envName; next_eo++) { if ((val = getenv(next_eo->envName)) != NULL) { if (pg_strcasecmp(val, "default") != 0) ADD_STARTUP_OPTION(next_eo->pgName, val); } } /* Add trailing terminator */ if (packet) packet[packet_len] = '\0'; packet_len++; return packet_len; } RPostgreSQL/src/libpq/win32setlocale.c0000644000176000001440000000635512124517222017336 0ustar ripleyusers/*------------------------------------------------------------------------- * * win32setlocale.c * Wrapper to work around bugs in Windows setlocale() implementation * * Copyright (c) 2011, PostgreSQL Global Development Group * * IDENTIFICATION * src/port/win32setlocale.c * * * Windows has a problem with locale names that have a dot in the country * name. For example: * * "Chinese (Traditional)_Hong Kong S.A.R..950" * * For some reason, setlocale() doesn't accept that. Fortunately, Windows' * setlocale() accepts various alternative names for such countries, so we * provide a wrapper setlocale() function that maps the troublemaking locale * names to accepted aliases. *------------------------------------------------------------------------- */ #include "c.h" #undef setlocale struct locale_map { const char *locale_name_part; /* string in locale name to replace */ const char *replacement; /* string to replace it with */ }; static const struct locale_map locale_map_list[] = { /* * "HKG" is listed here: * http://msdn.microsoft.com/en-us/library/cdax410z%28v=vs.71%29.aspx * (Country/Region Strings). * * "ARE" is the ISO-3166 three-letter code for U.A.E. It is not on the * above list, but seems to work anyway. */ { "Hong Kong S.A.R.", "HKG" }, { "U.A.E.", "ARE" }, /* * The ISO-3166 country code for Macau S.A.R. is MAC, but Windows doesn't * seem to recognize that. And Macau isn't listed in the table of * accepted abbreviations linked above. Fortunately, "ZHM" seems to be * accepted as an alias for "Chinese (Traditional)_Macau S.A.R..950". I'm * not sure where "ZHM" comes from, must be some legacy naming scheme. But * hey, it works. * * Note that unlike HKG and ARE, ZHM is an alias for the *whole* locale * name, not just the country part. * * Some versions of Windows spell it "Macau", others "Macao". */ { "Chinese (Traditional)_Macau S.A.R..950", "ZHM" }, { "Chinese_Macau S.A.R..950", "ZHM" }, { "Chinese (Traditional)_Macao S.A.R..950", "ZHM" }, { "Chinese_Macao S.A.R..950", "ZHM" } }; char * pgwin32_setlocale(int category, const char *locale) { char *result; char *alias; int i; if (locale == NULL) return setlocale(category, locale); /* Check if the locale name matches any of the problematic ones. */ alias = NULL; for (i = 0; i < lengthof(locale_map_list); i++) { const char *needle = locale_map_list[i].locale_name_part; const char *replacement = locale_map_list[i].replacement; char *match; match = strstr(locale, needle); if (match != NULL) { /* Found a match. Replace the matched string. */ int matchpos = match - locale; int replacementlen = strlen(replacement); char *rest = match + strlen(needle); int restlen = strlen(rest); alias = malloc(matchpos + replacementlen + restlen + 1); if (!alias) return NULL; memcpy(&alias[0], &locale[0], matchpos); memcpy(&alias[matchpos], replacement, replacementlen); memcpy(&alias[matchpos + replacementlen], rest, restlen + 1); /* includes null terminator */ break; } } /* Call the real setlocale() function */ if (alias) { result = setlocale(category, alias); free(alias); } else result = setlocale(category, locale); return result; } RPostgreSQL/src/libpq/fe-lobj.c0000644000176000001440000004106612124517222016014 0ustar ripleyusers/*------------------------------------------------------------------------- * * fe-lobj.c * Front-end large object interface * * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * src/interfaces/libpq/fe-lobj.c * *------------------------------------------------------------------------- */ #ifdef WIN32 /* * As unlink/rename are #define'd in port.h (via postgres_fe.h), io.h * must be included first on MS C. Might as well do it for all WIN32's * here. */ #include #endif #include "postgres_fe.h" #ifdef WIN32 #include "win32.h" #else #include #endif #include #include #include "libpq-fe.h" #include "libpq-int.h" #include "libpq/libpq-fs.h" /* must come after sys/stat.h */ #define LO_BUFSIZE 8192 static int lo_initialize(PGconn *conn); static Oid lo_import_internal(PGconn *conn, const char *filename, const Oid oid); /* * lo_open * opens an existing large object * * returns the file descriptor for use in later lo_* calls * return -1 upon failure. */ int lo_open(PGconn *conn, Oid lobjId, int mode) { int fd; int result_len; PQArgBlock argv[2]; PGresult *res; if (conn->lobjfuncs == NULL) { if (lo_initialize(conn) < 0) return -1; } argv[0].isint = 1; argv[0].len = 4; argv[0].u.integer = lobjId; argv[1].isint = 1; argv[1].len = 4; argv[1].u.integer = mode; res = PQfn(conn, conn->lobjfuncs->fn_lo_open, &fd, &result_len, 1, argv, 2); if (PQresultStatus(res) == PGRES_COMMAND_OK) { PQclear(res); return fd; } else { PQclear(res); return -1; } } /* * lo_close * closes an existing large object * * returns 0 upon success * returns -1 upon failure. */ int lo_close(PGconn *conn, int fd) { PQArgBlock argv[1]; PGresult *res; int retval; int result_len; if (conn->lobjfuncs == NULL) { if (lo_initialize(conn) < 0) return -1; } argv[0].isint = 1; argv[0].len = 4; argv[0].u.integer = fd; res = PQfn(conn, conn->lobjfuncs->fn_lo_close, &retval, &result_len, 1, argv, 1); if (PQresultStatus(res) == PGRES_COMMAND_OK) { PQclear(res); return retval; } else { PQclear(res); return -1; } } /* * lo_truncate * truncates an existing large object to the given size * * returns 0 upon success * returns -1 upon failure */ int lo_truncate(PGconn *conn, int fd, size_t len) { PQArgBlock argv[2]; PGresult *res; int retval; int result_len; if (conn->lobjfuncs == NULL) { if (lo_initialize(conn) < 0) return -1; } /* Must check this on-the-fly because it's not there pre-8.3 */ if (conn->lobjfuncs->fn_lo_truncate == 0) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("cannot determine OID of function lo_truncate\n")); return -1; } argv[0].isint = 1; argv[0].len = 4; argv[0].u.integer = fd; argv[1].isint = 1; argv[1].len = 4; argv[1].u.integer = len; res = PQfn(conn, conn->lobjfuncs->fn_lo_truncate, &retval, &result_len, 1, argv, 2); if (PQresultStatus(res) == PGRES_COMMAND_OK) { PQclear(res); return retval; } else { PQclear(res); return -1; } } /* * lo_read * read len bytes of the large object into buf * * returns the number of bytes read, or -1 on failure. * the CALLER must have allocated enough space to hold the result returned */ int lo_read(PGconn *conn, int fd, char *buf, size_t len) { PQArgBlock argv[2]; PGresult *res; int result_len; if (conn->lobjfuncs == NULL) { if (lo_initialize(conn) < 0) return -1; } argv[0].isint = 1; argv[0].len = 4; argv[0].u.integer = fd; argv[1].isint = 1; argv[1].len = 4; argv[1].u.integer = len; res = PQfn(conn, conn->lobjfuncs->fn_lo_read, (int *) buf, &result_len, 0, argv, 2); if (PQresultStatus(res) == PGRES_COMMAND_OK) { PQclear(res); return result_len; } else { PQclear(res); return -1; } } /* * lo_write * write len bytes of buf into the large object fd * * returns the number of bytes written, or -1 on failure. */ int lo_write(PGconn *conn, int fd, const char *buf, size_t len) { PQArgBlock argv[2]; PGresult *res; int result_len; int retval; if (conn->lobjfuncs == NULL) { if (lo_initialize(conn) < 0) return -1; } if (len <= 0) return 0; argv[0].isint = 1; argv[0].len = 4; argv[0].u.integer = fd; argv[1].isint = 0; argv[1].len = len; argv[1].u.ptr = (int *) buf; res = PQfn(conn, conn->lobjfuncs->fn_lo_write, &retval, &result_len, 1, argv, 2); if (PQresultStatus(res) == PGRES_COMMAND_OK) { PQclear(res); return retval; } else { PQclear(res); return -1; } } /* * lo_lseek * change the current read or write location on a large object * currently, only L_SET is a legal value for whence * */ int lo_lseek(PGconn *conn, int fd, int offset, int whence) { PQArgBlock argv[3]; PGresult *res; int retval; int result_len; if (conn->lobjfuncs == NULL) { if (lo_initialize(conn) < 0) return -1; } argv[0].isint = 1; argv[0].len = 4; argv[0].u.integer = fd; argv[1].isint = 1; argv[1].len = 4; argv[1].u.integer = offset; argv[2].isint = 1; argv[2].len = 4; argv[2].u.integer = whence; res = PQfn(conn, conn->lobjfuncs->fn_lo_lseek, &retval, &result_len, 1, argv, 3); if (PQresultStatus(res) == PGRES_COMMAND_OK) { PQclear(res); return retval; } else { PQclear(res); return -1; } } /* * lo_creat * create a new large object * the mode is ignored (once upon a time it had a use) * * returns the oid of the large object created or * InvalidOid upon failure */ Oid lo_creat(PGconn *conn, int mode) { PQArgBlock argv[1]; PGresult *res; int retval; int result_len; if (conn->lobjfuncs == NULL) { if (lo_initialize(conn) < 0) return InvalidOid; } argv[0].isint = 1; argv[0].len = 4; argv[0].u.integer = mode; res = PQfn(conn, conn->lobjfuncs->fn_lo_creat, &retval, &result_len, 1, argv, 1); if (PQresultStatus(res) == PGRES_COMMAND_OK) { PQclear(res); return (Oid) retval; } else { PQclear(res); return InvalidOid; } } /* * lo_create * create a new large object * if lobjId isn't InvalidOid, it specifies the OID to (attempt to) create * * returns the oid of the large object created or * InvalidOid upon failure */ Oid lo_create(PGconn *conn, Oid lobjId) { PQArgBlock argv[1]; PGresult *res; int retval; int result_len; if (conn->lobjfuncs == NULL) { if (lo_initialize(conn) < 0) return InvalidOid; } /* Must check this on-the-fly because it's not there pre-8.1 */ if (conn->lobjfuncs->fn_lo_create == 0) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("cannot determine OID of function lo_create\n")); return InvalidOid; } argv[0].isint = 1; argv[0].len = 4; argv[0].u.integer = lobjId; res = PQfn(conn, conn->lobjfuncs->fn_lo_create, &retval, &result_len, 1, argv, 1); if (PQresultStatus(res) == PGRES_COMMAND_OK) { PQclear(res); return (Oid) retval; } else { PQclear(res); return InvalidOid; } } /* * lo_tell * returns the current seek location of the large object * */ int lo_tell(PGconn *conn, int fd) { int retval; PQArgBlock argv[1]; PGresult *res; int result_len; if (conn->lobjfuncs == NULL) { if (lo_initialize(conn) < 0) return -1; } argv[0].isint = 1; argv[0].len = 4; argv[0].u.integer = fd; res = PQfn(conn, conn->lobjfuncs->fn_lo_tell, &retval, &result_len, 1, argv, 1); if (PQresultStatus(res) == PGRES_COMMAND_OK) { PQclear(res); return retval; } else { PQclear(res); return -1; } } /* * lo_unlink * delete a file * */ int lo_unlink(PGconn *conn, Oid lobjId) { PQArgBlock argv[1]; PGresult *res; int result_len; int retval; if (conn->lobjfuncs == NULL) { if (lo_initialize(conn) < 0) return -1; } argv[0].isint = 1; argv[0].len = 4; argv[0].u.integer = lobjId; res = PQfn(conn, conn->lobjfuncs->fn_lo_unlink, &retval, &result_len, 1, argv, 1); if (PQresultStatus(res) == PGRES_COMMAND_OK) { PQclear(res); return retval; } else { PQclear(res); return -1; } } /* * lo_import - * imports a file as an (inversion) large object. * * returns the oid of that object upon success, * returns InvalidOid upon failure */ Oid lo_import(PGconn *conn, const char *filename) { return lo_import_internal(conn, filename, InvalidOid); } /* * lo_import_with_oid - * imports a file as an (inversion) large object. * large object id can be specified. * * returns the oid of that object upon success, * returns InvalidOid upon failure */ Oid lo_import_with_oid(PGconn *conn, const char *filename, Oid lobjId) { return lo_import_internal(conn, filename, lobjId); } static Oid lo_import_internal(PGconn *conn, const char *filename, const Oid oid) { int fd; int nbytes, tmp; char buf[LO_BUFSIZE]; Oid lobjOid; int lobj; char sebuf[256]; /* * open the file to be read in */ fd = open(filename, O_RDONLY | PG_BINARY, 0666); if (fd < 0) { /* error */ printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not open file \"%s\": %s\n"), filename, pqStrerror(errno, sebuf, sizeof(sebuf))); return InvalidOid; } /* * create an inversion object */ if (oid == InvalidOid) lobjOid = lo_creat(conn, INV_READ | INV_WRITE); else lobjOid = lo_create(conn, oid); if (lobjOid == InvalidOid) { /* we assume lo_create() already set a suitable error message */ (void) close(fd); return InvalidOid; } lobj = lo_open(conn, lobjOid, INV_WRITE); if (lobj == -1) { /* we assume lo_open() already set a suitable error message */ (void) close(fd); return InvalidOid; } /* * read in from the file and write to the large object */ while ((nbytes = read(fd, buf, LO_BUFSIZE)) > 0) { tmp = lo_write(conn, lobj, buf, nbytes); if (tmp != nbytes) { /* * If lo_write() failed, we are now in an aborted transaction so * there's no need for lo_close(); furthermore, if we tried it * we'd overwrite the useful error result with a useless one. So * just nail the doors shut and get out of town. */ (void) close(fd); return InvalidOid; } } if (nbytes < 0) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not read from file \"%s\": %s\n"), filename, pqStrerror(errno, sebuf, sizeof(sebuf))); lobjOid = InvalidOid; } (void) close(fd); if (lo_close(conn, lobj) != 0) { /* we assume lo_close() already set a suitable error message */ return InvalidOid; } return lobjOid; } /* * lo_export - * exports an (inversion) large object. * returns -1 upon failure, 1 if OK */ int lo_export(PGconn *conn, Oid lobjId, const char *filename) { int result = 1; int fd; int nbytes, tmp; char buf[LO_BUFSIZE]; int lobj; char sebuf[256]; /* * open the large object. */ lobj = lo_open(conn, lobjId, INV_READ); if (lobj == -1) { /* we assume lo_open() already set a suitable error message */ return -1; } /* * create the file to be written to */ fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC | PG_BINARY, 0666); if (fd < 0) { /* error */ printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not open file \"%s\": %s\n"), filename, pqStrerror(errno, sebuf, sizeof(sebuf))); (void) lo_close(conn, lobj); return -1; } /* * read in from the large object and write to the file */ while ((nbytes = lo_read(conn, lobj, buf, LO_BUFSIZE)) > 0) { tmp = write(fd, buf, nbytes); if (tmp != nbytes) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not write to file \"%s\": %s\n"), filename, pqStrerror(errno, sebuf, sizeof(sebuf))); (void) lo_close(conn, lobj); (void) close(fd); return -1; } } /* * If lo_read() failed, we are now in an aborted transaction so there's no * need for lo_close(); furthermore, if we tried it we'd overwrite the * useful error result with a useless one. So skip lo_close() if we got a * failure result. */ if (nbytes < 0 || lo_close(conn, lobj) != 0) { /* assume lo_read() or lo_close() left a suitable error message */ result = -1; } if (close(fd)) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not write to file \"%s\": %s\n"), filename, pqStrerror(errno, sebuf, sizeof(sebuf))); result = -1; } return result; } /* * lo_initialize * * Initialize the large object interface for an existing connection. * We ask the backend about the functions OID's in pg_proc for all * functions that are required for large object operations. */ static int lo_initialize(PGconn *conn) { PGresult *res; PGlobjfuncs *lobjfuncs; int n; const char *query; const char *fname; Oid foid; /* * Allocate the structure to hold the functions OID's */ lobjfuncs = (PGlobjfuncs *) malloc(sizeof(PGlobjfuncs)); if (lobjfuncs == NULL) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("out of memory\n")); return -1; } MemSet((char *) lobjfuncs, 0, sizeof(PGlobjfuncs)); /* * Execute the query to get all the functions at once. In 7.3 and later * we need to be schema-safe. lo_create only exists in 8.1 and up. * lo_truncate only exists in 8.3 and up. */ if (conn->sversion >= 70300) query = "select proname, oid from pg_catalog.pg_proc " "where proname in (" "'lo_open', " "'lo_close', " "'lo_creat', " "'lo_create', " "'lo_unlink', " "'lo_lseek', " "'lo_tell', " "'lo_truncate', " "'loread', " "'lowrite') " "and pronamespace = (select oid from pg_catalog.pg_namespace " "where nspname = 'pg_catalog')"; else query = "select proname, oid from pg_proc " "where proname = 'lo_open' " "or proname = 'lo_close' " "or proname = 'lo_creat' " "or proname = 'lo_unlink' " "or proname = 'lo_lseek' " "or proname = 'lo_tell' " "or proname = 'loread' " "or proname = 'lowrite'"; res = PQexec(conn, query); if (res == NULL) { free(lobjfuncs); return -1; } if (res->resultStatus != PGRES_TUPLES_OK) { free(lobjfuncs); PQclear(res); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("query to initialize large object functions did not return data\n")); return -1; } /* * Examine the result and put the OID's into the struct */ for (n = 0; n < PQntuples(res); n++) { fname = PQgetvalue(res, n, 0); foid = (Oid) atoi(PQgetvalue(res, n, 1)); if (!strcmp(fname, "lo_open")) lobjfuncs->fn_lo_open = foid; else if (!strcmp(fname, "lo_close")) lobjfuncs->fn_lo_close = foid; else if (!strcmp(fname, "lo_creat")) lobjfuncs->fn_lo_creat = foid; else if (!strcmp(fname, "lo_create")) lobjfuncs->fn_lo_create = foid; else if (!strcmp(fname, "lo_unlink")) lobjfuncs->fn_lo_unlink = foid; else if (!strcmp(fname, "lo_lseek")) lobjfuncs->fn_lo_lseek = foid; else if (!strcmp(fname, "lo_tell")) lobjfuncs->fn_lo_tell = foid; else if (!strcmp(fname, "lo_truncate")) lobjfuncs->fn_lo_truncate = foid; else if (!strcmp(fname, "loread")) lobjfuncs->fn_lo_read = foid; else if (!strcmp(fname, "lowrite")) lobjfuncs->fn_lo_write = foid; } PQclear(res); /* * Finally check that we really got all large object interface functions */ if (lobjfuncs->fn_lo_open == 0) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("cannot determine OID of function lo_open\n")); free(lobjfuncs); return -1; } if (lobjfuncs->fn_lo_close == 0) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("cannot determine OID of function lo_close\n")); free(lobjfuncs); return -1; } if (lobjfuncs->fn_lo_creat == 0) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("cannot determine OID of function lo_creat\n")); free(lobjfuncs); return -1; } if (lobjfuncs->fn_lo_unlink == 0) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("cannot determine OID of function lo_unlink\n")); free(lobjfuncs); return -1; } if (lobjfuncs->fn_lo_lseek == 0) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("cannot determine OID of function lo_lseek\n")); free(lobjfuncs); return -1; } if (lobjfuncs->fn_lo_tell == 0) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("cannot determine OID of function lo_tell\n")); free(lobjfuncs); return -1; } if (lobjfuncs->fn_lo_read == 0) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("cannot determine OID of function loread\n")); free(lobjfuncs); return -1; } if (lobjfuncs->fn_lo_write == 0) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("cannot determine OID of function lowrite\n")); free(lobjfuncs); return -1; } /* * Put the structure into the connection control */ conn->lobjfuncs = lobjfuncs; return 0; } RPostgreSQL/src/libpq/postgres_fe.h0000644000176000001440000000133212124517222017013 0ustar ripleyusers/*------------------------------------------------------------------------- * * postgres_fe.h * Primary include file for PostgreSQL client-side .c files * * This should be the first file included by PostgreSQL client libraries and * application programs --- but not by backend modules, which should include * postgres.h. * * * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * Portions Copyright (c) 1995, Regents of the University of California * * src/include/postgres_fe.h * *------------------------------------------------------------------------- */ #ifndef POSTGRES_FE_H #define POSTGRES_FE_H #ifndef FRONTEND #define FRONTEND 1 #endif #include "c.h" #endif /* POSTGRES_FE_H */ RPostgreSQL/src/libpq/pg_config_paths.h.win0000644000176000001440000000104011663173071020424 0ustar ripleyusers#define PGBINDIR "/usr/local/pgsql/bin" #define PGSHAREDIR "/usr/local/pgsql/share" #define SYSCONFDIR "/usr/local/pgsql/etc" #define INCLUDEDIR "/usr/local/pgsql/include" #define PKGINCLUDEDIR "/usr/local/pgsql/include" #define INCLUDEDIRSERVER "/usr/local/pgsql/include/server" #define LIBDIR "/usr/local/pgsql/lib" #define PKGLIBDIR "/usr/local/pgsql/lib" #define LOCALEDIR "/usr/local/pgsql/share/locale" #define DOCDIR "/usr/local/pgsql/share/doc/" #define HTMLDIR "/usr/local/pgsql/share/doc/" #define MANDIR "/usr/local/pgsql/share/man" RPostgreSQL/src/libpq/encnames.c0000644000176000001440000002666712124517222016301 0ustar ripleyusers/* * Encoding names and routines for work with it. All * in this file is shared bedween FE and BE. * * src/backend/utils/mb/encnames.c */ #ifdef FRONTEND #include "postgres_fe.h" #define Assert(condition) #else #include "postgres.h" #include "utils/builtins.h" #endif #include #include #include "mb/pg_wchar.h" /* ---------- * All encoding names, sorted: *** A L P H A B E T I C *** * * All names must be without irrelevant chars, search routines use * isalnum() chars only. It means ISO-8859-1, iso_8859-1 and Iso8859_1 * are always converted to 'iso88591'. All must be lower case. * * The table doesn't contain 'cs' aliases (like csISOLatin1). It's needed? * * Karel Zak, Aug 2001 * ---------- */ pg_encname pg_encname_tbl[] = { { "abc", PG_WIN1258 }, /* alias for WIN1258 */ { "alt", PG_WIN866 }, /* IBM866 */ { "big5", PG_BIG5 }, /* Big5; Chinese for Taiwan multibyte set */ { "euccn", PG_EUC_CN }, /* EUC-CN; Extended Unix Code for simplified * Chinese */ { "eucjis2004", PG_EUC_JIS_2004 }, /* EUC-JIS-2004; Extended UNIX Code fixed * Width for Japanese, standard JIS X 0213 */ { "eucjp", PG_EUC_JP }, /* EUC-JP; Extended UNIX Code fixed Width for * Japanese, standard OSF */ { "euckr", PG_EUC_KR }, /* EUC-KR; Extended Unix Code for Korean , KS * X 1001 standard */ { "euctw", PG_EUC_TW }, /* EUC-TW; Extended Unix Code for * * traditional Chinese */ { "gb18030", PG_GB18030 }, /* GB18030;GB18030 */ { "gbk", PG_GBK }, /* GBK; Chinese Windows CodePage 936 * simplified Chinese */ { "iso88591", PG_LATIN1 }, /* ISO-8859-1; RFC1345,KXS2 */ { "iso885910", PG_LATIN6 }, /* ISO-8859-10; RFC1345,KXS2 */ { "iso885913", PG_LATIN7 }, /* ISO-8859-13; RFC1345,KXS2 */ { "iso885914", PG_LATIN8 }, /* ISO-8859-14; RFC1345,KXS2 */ { "iso885915", PG_LATIN9 }, /* ISO-8859-15; RFC1345,KXS2 */ { "iso885916", PG_LATIN10 }, /* ISO-8859-16; RFC1345,KXS2 */ { "iso88592", PG_LATIN2 }, /* ISO-8859-2; RFC1345,KXS2 */ { "iso88593", PG_LATIN3 }, /* ISO-8859-3; RFC1345,KXS2 */ { "iso88594", PG_LATIN4 }, /* ISO-8859-4; RFC1345,KXS2 */ { "iso88595", PG_ISO_8859_5 }, /* ISO-8859-5; RFC1345,KXS2 */ { "iso88596", PG_ISO_8859_6 }, /* ISO-8859-6; RFC1345,KXS2 */ { "iso88597", PG_ISO_8859_7 }, /* ISO-8859-7; RFC1345,KXS2 */ { "iso88598", PG_ISO_8859_8 }, /* ISO-8859-8; RFC1345,KXS2 */ { "iso88599", PG_LATIN5 }, /* ISO-8859-9; RFC1345,KXS2 */ { "johab", PG_JOHAB }, /* JOHAB; Extended Unix Code for simplified * Chinese */ { "koi8", PG_KOI8R }, /* _dirty_ alias for KOI8-R (backward * compatibility) */ { "koi8r", PG_KOI8R }, /* KOI8-R; RFC1489 */ { "koi8u", PG_KOI8U }, /* KOI8-U; RFC2319 */ { "latin1", PG_LATIN1 }, /* alias for ISO-8859-1 */ { "latin10", PG_LATIN10 }, /* alias for ISO-8859-16 */ { "latin2", PG_LATIN2 }, /* alias for ISO-8859-2 */ { "latin3", PG_LATIN3 }, /* alias for ISO-8859-3 */ { "latin4", PG_LATIN4 }, /* alias for ISO-8859-4 */ { "latin5", PG_LATIN5 }, /* alias for ISO-8859-9 */ { "latin6", PG_LATIN6 }, /* alias for ISO-8859-10 */ { "latin7", PG_LATIN7 }, /* alias for ISO-8859-13 */ { "latin8", PG_LATIN8 }, /* alias for ISO-8859-14 */ { "latin9", PG_LATIN9 }, /* alias for ISO-8859-15 */ { "mskanji", PG_SJIS }, /* alias for Shift_JIS */ { "muleinternal", PG_MULE_INTERNAL }, { "shiftjis", PG_SJIS }, /* Shift_JIS; JIS X 0202-1991 */ { "shiftjis2004", PG_SHIFT_JIS_2004 }, /* SHIFT-JIS-2004; Shift JIS for Japanese, * standard JIS X 0213 */ { "sjis", PG_SJIS }, /* alias for Shift_JIS */ { "sqlascii", PG_SQL_ASCII }, { "tcvn", PG_WIN1258 }, /* alias for WIN1258 */ { "tcvn5712", PG_WIN1258 }, /* alias for WIN1258 */ { "uhc", PG_UHC }, /* UHC; Korean Windows CodePage 949 */ { "unicode", PG_UTF8 }, /* alias for UTF8 */ { "utf8", PG_UTF8 }, /* alias for UTF8 */ { "vscii", PG_WIN1258 }, /* alias for WIN1258 */ { "win", PG_WIN1251 }, /* _dirty_ alias for windows-1251 (backward * compatibility) */ { "win1250", PG_WIN1250 }, /* alias for Windows-1250 */ { "win1251", PG_WIN1251 }, /* alias for Windows-1251 */ { "win1252", PG_WIN1252 }, /* alias for Windows-1252 */ { "win1253", PG_WIN1253 }, /* alias for Windows-1253 */ { "win1254", PG_WIN1254 }, /* alias for Windows-1254 */ { "win1255", PG_WIN1255 }, /* alias for Windows-1255 */ { "win1256", PG_WIN1256 }, /* alias for Windows-1256 */ { "win1257", PG_WIN1257 }, /* alias for Windows-1257 */ { "win1258", PG_WIN1258 }, /* alias for Windows-1258 */ { "win866", PG_WIN866 }, /* IBM866 */ { "win874", PG_WIN874 }, /* alias for Windows-874 */ { "win932", PG_SJIS }, /* alias for Shift_JIS */ { "win936", PG_GBK }, /* alias for GBK */ { "win949", PG_UHC }, /* alias for UHC */ { "win950", PG_BIG5 }, /* alias for BIG5 */ { "windows1250", PG_WIN1250 }, /* Windows-1251; Microsoft */ { "windows1251", PG_WIN1251 }, /* Windows-1251; Microsoft */ { "windows1252", PG_WIN1252 }, /* Windows-1252; Microsoft */ { "windows1253", PG_WIN1253 }, /* Windows-1253; Microsoft */ { "windows1254", PG_WIN1254 }, /* Windows-1254; Microsoft */ { "windows1255", PG_WIN1255 }, /* Windows-1255; Microsoft */ { "windows1256", PG_WIN1256 }, /* Windows-1256; Microsoft */ { "windows1257", PG_WIN1257 }, /* Windows-1257; Microsoft */ { "windows1258", PG_WIN1258 }, /* Windows-1258; Microsoft */ { "windows866", PG_WIN866 }, /* IBM866 */ { "windows874", PG_WIN874 }, /* Windows-874; Microsoft */ { "windows932", PG_SJIS }, /* alias for Shift_JIS */ { "windows936", PG_GBK }, /* alias for GBK */ { "windows949", PG_UHC }, /* alias for UHC */ { "windows950", PG_BIG5 }, /* alias for BIG5 */ { NULL, 0 } /* last */ }; unsigned int pg_encname_tbl_sz = \ sizeof(pg_encname_tbl) / sizeof(pg_encname_tbl[0]) - 1; /* ---------- * These are "official" encoding names. * XXX must be sorted by the same order as enum pg_enc (in mb/pg_wchar.h) * ---------- */ #ifndef WIN32 #define DEF_ENC2NAME(name, codepage) { #name, PG_##name } #else #define DEF_ENC2NAME(name, codepage) { #name, PG_##name, codepage } #endif pg_enc2name pg_enc2name_tbl[] = { DEF_ENC2NAME(SQL_ASCII, 0), DEF_ENC2NAME(EUC_JP, 20932), DEF_ENC2NAME(EUC_CN, 20936), DEF_ENC2NAME(EUC_KR, 51949), DEF_ENC2NAME(EUC_TW, 0), DEF_ENC2NAME(EUC_JIS_2004, 20932), DEF_ENC2NAME(UTF8, 65001), DEF_ENC2NAME(MULE_INTERNAL, 0), DEF_ENC2NAME(LATIN1, 28591), DEF_ENC2NAME(LATIN2, 28592), DEF_ENC2NAME(LATIN3, 28593), DEF_ENC2NAME(LATIN4, 28594), DEF_ENC2NAME(LATIN5, 28599), DEF_ENC2NAME(LATIN6, 0), DEF_ENC2NAME(LATIN7, 0), DEF_ENC2NAME(LATIN8, 0), DEF_ENC2NAME(LATIN9, 28605), DEF_ENC2NAME(LATIN10, 0), DEF_ENC2NAME(WIN1256, 1256), DEF_ENC2NAME(WIN1258, 1258), DEF_ENC2NAME(WIN866, 866), DEF_ENC2NAME(WIN874, 874), DEF_ENC2NAME(KOI8R, 20866), DEF_ENC2NAME(WIN1251, 1251), DEF_ENC2NAME(WIN1252, 1252), DEF_ENC2NAME(ISO_8859_5, 28595), DEF_ENC2NAME(ISO_8859_6, 28596), DEF_ENC2NAME(ISO_8859_7, 28597), DEF_ENC2NAME(ISO_8859_8, 28598), DEF_ENC2NAME(WIN1250, 1250), DEF_ENC2NAME(WIN1253, 1253), DEF_ENC2NAME(WIN1254, 1254), DEF_ENC2NAME(WIN1255, 1255), DEF_ENC2NAME(WIN1257, 1257), DEF_ENC2NAME(KOI8U, 21866), DEF_ENC2NAME(SJIS, 932), DEF_ENC2NAME(BIG5, 950), DEF_ENC2NAME(GBK, 936), DEF_ENC2NAME(UHC, 0), DEF_ENC2NAME(GB18030, 54936), DEF_ENC2NAME(JOHAB, 0), DEF_ENC2NAME(SHIFT_JIS_2004, 932) }; /* ---------- * These are encoding names for gettext. * ---------- */ pg_enc2gettext pg_enc2gettext_tbl[] = { {PG_UTF8, "UTF-8"}, {PG_LATIN1, "LATIN1"}, {PG_LATIN2, "LATIN2"}, {PG_LATIN3, "LATIN3"}, {PG_LATIN4, "LATIN4"}, {PG_ISO_8859_5, "ISO-8859-5"}, {PG_ISO_8859_6, "ISO_8859-6"}, {PG_ISO_8859_7, "ISO-8859-7"}, {PG_ISO_8859_8, "ISO-8859-8"}, {PG_LATIN5, "LATIN5"}, {PG_LATIN6, "LATIN6"}, {PG_LATIN7, "LATIN7"}, {PG_LATIN8, "LATIN8"}, {PG_LATIN9, "LATIN-9"}, {PG_LATIN10, "LATIN10"}, {PG_KOI8R, "KOI8-R"}, {PG_KOI8U, "KOI8-U"}, {PG_WIN1250, "CP1250"}, {PG_WIN1251, "CP1251"}, {PG_WIN1252, "CP1252"}, {PG_WIN1253, "CP1253"}, {PG_WIN1254, "CP1254"}, {PG_WIN1255, "CP1255"}, {PG_WIN1256, "CP1256"}, {PG_WIN1257, "CP1257"}, {PG_WIN1258, "CP1258"}, {PG_WIN866, "CP866"}, {PG_WIN874, "CP874"}, {PG_EUC_CN, "EUC-CN"}, {PG_EUC_JP, "EUC-JP"}, {PG_EUC_KR, "EUC-KR"}, {PG_EUC_TW, "EUC-TW"}, {PG_EUC_JIS_2004, "EUC-JP"}, {0, NULL} }; /* ---------- * Encoding checks, for error returns -1 else encoding id * ---------- */ int pg_valid_client_encoding(const char *name) { int enc; if ((enc = pg_char_to_encoding(name)) < 0) return -1; if (!PG_VALID_FE_ENCODING(enc)) return -1; return enc; } int pg_valid_server_encoding(const char *name) { int enc; if ((enc = pg_char_to_encoding(name)) < 0) return -1; if (!PG_VALID_BE_ENCODING(enc)) return -1; return enc; } int pg_valid_server_encoding_id(int encoding) { return PG_VALID_BE_ENCODING(encoding); } /* ---------- * Remove irrelevant chars from encoding name * ---------- */ static char * clean_encoding_name(const char *key, char *newkey) { const char *p; char *np; for (p = key, np = newkey; *p != '\0'; p++) { if (isalnum((unsigned char) *p)) { if (*p >= 'A' && *p <= 'Z') *np++ = *p + 'a' - 'A'; else *np++ = *p; } } *np = '\0'; return newkey; } /* ---------- * Search encoding by encoding name * ---------- */ pg_encname * pg_char_to_encname_struct(const char *name) { unsigned int nel = pg_encname_tbl_sz; pg_encname *base = pg_encname_tbl, *last = base + nel - 1, *position; int result; char buff[NAMEDATALEN], *key; if (name == NULL || *name == '\0') return NULL; if (strlen(name) >= NAMEDATALEN) { #ifdef FRONTEND fprintf(stderr, "encoding name too long\n"); return NULL; #else ereport(ERROR, (errcode(ERRCODE_NAME_TOO_LONG), errmsg("encoding name too long"))); #endif } key = clean_encoding_name(name, buff); while (last >= base) { position = base + ((last - base) >> 1); result = key[0] - position->name[0]; if (result == 0) { result = strcmp(key, position->name); if (result == 0) return position; } if (result < 0) last = position - 1; else base = position + 1; } return NULL; } /* * Returns encoding or -1 for error */ int pg_char_to_encoding(const char *name) { pg_encname *p; if (!name) return -1; p = pg_char_to_encname_struct(name); return p ? p->encoding : -1; } #ifndef FRONTEND Datum PG_char_to_encoding(PG_FUNCTION_ARGS) { Name s = PG_GETARG_NAME(0); PG_RETURN_INT32(pg_char_to_encoding(NameStr(*s))); } #endif const char * pg_encoding_to_char(int encoding) { if (PG_VALID_ENCODING(encoding)) { pg_enc2name *p = &pg_enc2name_tbl[encoding]; Assert(encoding == p->encoding); return p->name; } return ""; } #ifndef FRONTEND Datum PG_encoding_to_char(PG_FUNCTION_ARGS) { int32 encoding = PG_GETARG_INT32(0); const char *encoding_name = pg_encoding_to_char(encoding); return DirectFunctionCall1(namein, CStringGetDatum(encoding_name)); } #endif RPostgreSQL/src/libpq/libpq-fe.h0000644000176000001440000005002512124517222016175 0ustar ripleyusers/*------------------------------------------------------------------------- * * libpq-fe.h * This file contains definitions for structures and * externs for functions used by frontend postgres applications. * * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/interfaces/libpq/libpq-fe.h * *------------------------------------------------------------------------- */ #ifndef LIBPQ_FE_H #define LIBPQ_FE_H #ifdef __cplusplus extern "C" { #endif #include /* * postgres_ext.h defines the backend's externally visible types, * such as Oid. */ #include "postgres_ext.h" /* * Option flags for PQcopyResult */ #define PG_COPYRES_ATTRS 0x01 #define PG_COPYRES_TUPLES 0x02 /* Implies PG_COPYRES_ATTRS */ #define PG_COPYRES_EVENTS 0x04 #define PG_COPYRES_NOTICEHOOKS 0x08 /* Application-visible enum types */ typedef enum { /* * Although it is okay to add to this list, values which become unused * should never be removed, nor should constants be redefined - that would * break compatibility with existing code. */ CONNECTION_OK, CONNECTION_BAD, /* Non-blocking mode only below here */ /* * The existence of these should never be relied upon - they should only * be used for user feedback or similar purposes. */ CONNECTION_STARTED, /* Waiting for connection to be made. */ CONNECTION_MADE, /* Connection OK; waiting to send. */ CONNECTION_AWAITING_RESPONSE, /* Waiting for a response from the * postmaster. */ CONNECTION_AUTH_OK, /* Received authentication; waiting for * backend startup. */ CONNECTION_SETENV, /* Negotiating environment. */ CONNECTION_SSL_STARTUP, /* Negotiating SSL. */ CONNECTION_NEEDED /* Internal state: connect() needed */ } ConnStatusType; typedef enum { PGRES_POLLING_FAILED = 0, PGRES_POLLING_READING, /* These two indicate that one may */ PGRES_POLLING_WRITING, /* use select before polling again. */ PGRES_POLLING_OK, PGRES_POLLING_ACTIVE /* unused; keep for awhile for backwards * compatibility */ } PostgresPollingStatusType; typedef enum { PGRES_EMPTY_QUERY = 0, /* empty query string was executed */ PGRES_COMMAND_OK, /* a query command that doesn't return * anything was executed properly by the * backend */ PGRES_TUPLES_OK, /* a query command that returns tuples was * executed properly by the backend, PGresult * contains the result tuples */ PGRES_COPY_OUT, /* Copy Out data transfer in progress */ PGRES_COPY_IN, /* Copy In data transfer in progress */ PGRES_BAD_RESPONSE, /* an unexpected response was recv'd from the * backend */ PGRES_NONFATAL_ERROR, /* notice or warning message */ PGRES_FATAL_ERROR, /* query failed */ PGRES_COPY_BOTH /* Copy In/Out data transfer in progress */ } ExecStatusType; typedef enum { PQTRANS_IDLE, /* connection idle */ PQTRANS_ACTIVE, /* command in progress */ PQTRANS_INTRANS, /* idle, within transaction block */ PQTRANS_INERROR, /* idle, within failed transaction */ PQTRANS_UNKNOWN /* cannot determine status */ } PGTransactionStatusType; typedef enum { PQERRORS_TERSE, /* single-line error messages */ PQERRORS_DEFAULT, /* recommended style */ PQERRORS_VERBOSE /* all the facts, ma'am */ } PGVerbosity; typedef enum { PQPING_OK, /* server is accepting connections */ PQPING_REJECT, /* server is alive but rejecting connections */ PQPING_NO_RESPONSE, /* could not establish connection */ PQPING_NO_ATTEMPT /* connection not attempted (bad params) */ } PGPing; /* PGconn encapsulates a connection to the backend. * The contents of this struct are not supposed to be known to applications. */ typedef struct pg_conn PGconn; /* PGresult encapsulates the result of a query (or more precisely, of a single * SQL command --- a query string given to PQsendQuery can contain multiple * commands and thus return multiple PGresult objects). * The contents of this struct are not supposed to be known to applications. */ typedef struct pg_result PGresult; /* PGcancel encapsulates the information needed to cancel a running * query on an existing connection. * The contents of this struct are not supposed to be known to applications. */ typedef struct pg_cancel PGcancel; /* PGnotify represents the occurrence of a NOTIFY message. * Ideally this would be an opaque typedef, but it's so simple that it's * unlikely to change. * NOTE: in Postgres 6.4 and later, the be_pid is the notifying backend's, * whereas in earlier versions it was always your own backend's PID. */ typedef struct pgNotify { char *relname; /* notification condition name */ int be_pid; /* process ID of notifying server process */ char *extra; /* notification parameter */ /* Fields below here are private to libpq; apps should not use 'em */ struct pgNotify *next; /* list link */ } PGnotify; /* Function types for notice-handling callbacks */ typedef void (*PQnoticeReceiver) (void *arg, const PGresult *res); typedef void (*PQnoticeProcessor) (void *arg, const char *message); /* Print options for PQprint() */ typedef char pqbool; typedef struct _PQprintOpt { pqbool header; /* print output field headings and row count */ pqbool align; /* fill align the fields */ pqbool standard; /* old brain dead format */ pqbool html3; /* output html tables */ pqbool expanded; /* expand tables */ pqbool pager; /* use pager for output if needed */ char *fieldSep; /* field separator */ char *tableOpt; /* insert to HTML */ char *caption; /* HTML " "\n", fieldNames[j], fieldNotNum[j] ? "left" : "right", pval); else { if (po->align) fprintf(fout, "%-*s%s %s\n", fieldMaxLen - fs_len, fieldNames[j], po->fieldSep, pval); else fprintf(fout, "%s%s%s\n", fieldNames[j], po->fieldSep, pval); } } else { if (!po->html3) { fputs(pval, fout); efield: if ((j + 1) < nFields) fputs(po->fieldSep, fout); else fputc('\n', fout); } } } } } static char * do_header(FILE *fout, const PQprintOpt *po, const int nFields, int *fieldMax, const char **fieldNames, unsigned char *fieldNotNum, const int fs_len, const PGresult *res) { int j; /* for loop index */ char *border = NULL; if (po->html3) fputs("", fout); else { int tot = 0; int n = 0; char *p = NULL; for (; n < nFields; n++) tot += fieldMax[n] + fs_len + (po->standard ? 2 : 0); if (po->standard) tot += fs_len * 2 + 2; border = malloc(tot + 1); if (!border) { fprintf(stderr, libpq_gettext("out of memory\n")); exit(1); } p = border; if (po->standard) { char *fs = po->fieldSep; while (*fs++) *p++ = '+'; } for (j = 0; j < nFields; j++) { int len; for (len = fieldMax[j] + (po->standard ? 2 : 0); len--; *p++ = '-'); if (po->standard || (j + 1) < nFields) { char *fs = po->fieldSep; while (*fs++) *p++ = '+'; } } *p = '\0'; if (po->standard) fprintf(fout, "%s\n", border); } if (po->standard) fputs(po->fieldSep, fout); for (j = 0; j < nFields; j++) { const char *s = PQfname(res, j); if (po->html3) { fprintf(fout, "", fieldNotNum[j] ? "left" : "right", fieldNames[j]); } else { int n = strlen(s); if (n > fieldMax[j]) fieldMax[j] = n; if (po->standard) fprintf(fout, fieldNotNum[j] ? " %-*s " : " %*s ", fieldMax[j], s); else fprintf(fout, fieldNotNum[j] ? "%-*s" : "%*s", fieldMax[j], s); if (po->standard || (j + 1) < nFields) fputs(po->fieldSep, fout); } } if (po->html3) fputs("\n", fout); else fprintf(fout, "\n%s\n", border); return border; } static void output_row(FILE *fout, const PQprintOpt *po, const int nFields, char **fields, unsigned char *fieldNotNum, int *fieldMax, char *border, const int row_index) { int field_index; /* for loop index */ if (po->html3) fputs("", fout); else if (po->standard) fputs(po->fieldSep, fout); for (field_index = 0; field_index < nFields; field_index++) { char *p = fields[row_index * nFields + field_index]; if (po->html3) fprintf(fout, "", fieldNotNum[field_index] ? "left" : "right", p ? p : ""); else { fprintf(fout, fieldNotNum[field_index] ? (po->standard ? " %-*s " : "%-*s") : (po->standard ? " %*s " : "%*s"), fieldMax[field_index], p ? p : ""); if (po->standard || field_index + 1 < nFields) fputs(po->fieldSep, fout); } if (p) free(p); } if (po->html3) fputs("", fout); else if (po->standard) fprintf(fout, "\n%s", border); fputc('\n', fout); } /* * really old printing routines */ void PQdisplayTuples(const PGresult *res, FILE *fp, /* where to send the output */ int fillAlign, /* pad the fields with spaces */ const char *fieldSep, /* field separator */ int printHeader, /* display headers? */ int quiet ) { #define DEFAULT_FIELD_SEP " " int i, j; int nFields; int nTuples; int *fLength = NULL; if (fieldSep == NULL) fieldSep = DEFAULT_FIELD_SEP; /* Get some useful info about the results */ nFields = PQnfields(res); nTuples = PQntuples(res); if (fp == NULL) fp = stdout; /* Figure the field lengths to align to */ /* will be somewhat time consuming for very large results */ if (fillAlign) { fLength = (int *) malloc(nFields * sizeof(int)); if (!fLength) { fprintf(stderr, libpq_gettext("out of memory\n")); exit(1); } for (j = 0; j < nFields; j++) { fLength[j] = strlen(PQfname(res, j)); for (i = 0; i < nTuples; i++) { int flen = PQgetlength(res, i, j); if (flen > fLength[j]) fLength[j] = flen; } } } if (printHeader) { /* first, print out the attribute names */ for (i = 0; i < nFields; i++) { fputs(PQfname(res, i), fp); if (fillAlign) fill(strlen(PQfname(res, i)), fLength[i], ' ', fp); fputs(fieldSep, fp); } fprintf(fp, "\n"); /* Underline the attribute names */ for (i = 0; i < nFields; i++) { if (fillAlign) fill(0, fLength[i], '-', fp); fputs(fieldSep, fp); } fprintf(fp, "\n"); } /* next, print out the instances */ for (i = 0; i < nTuples; i++) { for (j = 0; j < nFields; j++) { fprintf(fp, "%s", PQgetvalue(res, i, j)); if (fillAlign) fill(strlen(PQgetvalue(res, i, j)), fLength[j], ' ', fp); fputs(fieldSep, fp); } fprintf(fp, "\n"); } if (!quiet) fprintf(fp, "\nQuery returned %d row%s.\n", PQntuples(res), (PQntuples(res) == 1) ? "" : "s"); fflush(fp); if (fLength) free(fLength); } void PQprintTuples(const PGresult *res, FILE *fout, /* output stream */ int PrintAttNames, /* print attribute names or not */ int TerseOutput, /* delimiter bars or not? */ int colWidth /* width of column, if 0, use variable width */ ) { int nFields; int nTups; int i, j; char formatString[80]; char *tborder = NULL; nFields = PQnfields(res); nTups = PQntuples(res); if (colWidth > 0) sprintf(formatString, "%%s %%-%ds", colWidth); else sprintf(formatString, "%%s %%s"); if (nFields > 0) { /* only print rows with at least 1 field. */ if (!TerseOutput) { int width; width = nFields * 14; tborder = malloc(width + 1); if (!tborder) { fprintf(stderr, libpq_gettext("out of memory\n")); exit(1); } for (i = 0; i <= width; i++) tborder[i] = '-'; tborder[i] = '\0'; fprintf(fout, "%s\n", tborder); } for (i = 0; i < nFields; i++) { if (PrintAttNames) { fprintf(fout, formatString, TerseOutput ? "" : "|", PQfname(res, i)); } } if (PrintAttNames) { if (TerseOutput) fprintf(fout, "\n"); else fprintf(fout, "|\n%s\n", tborder); } for (i = 0; i < nTups; i++) { for (j = 0; j < nFields; j++) { const char *pval = PQgetvalue(res, i, j); fprintf(fout, formatString, TerseOutput ? "" : "|", pval ? pval : ""); } if (TerseOutput) fprintf(fout, "\n"); else fprintf(fout, "|\n%s\n", tborder); } } if (tborder) free(tborder); } /* simply send out max-length number of filler characters to fp */ static void fill(int length, int max, char filler, FILE *fp) { int count; count = max - length; while (count-- >= 0) putc(filler, fp); } RPostgreSQL/src/libpq/wininclude/0000755000176000001440000000000012124517222016464 5ustar ripleyusersRPostgreSQL/src/libpq/wininclude/arpa/0000755000176000001440000000000012124517222017407 5ustar ripleyusersRPostgreSQL/src/libpq/wininclude/arpa/inet.h0000644000176000001440000000010212124517222020510 0ustar ripleyusers/* src/include/port/win32/arpa/inet.h */ #include RPostgreSQL/src/libpq/wininclude/pwd.h0000644000176000001440000000004712124517222017430 0ustar ripleyusers/* * src/include/port/win32/pwd.h */ RPostgreSQL/src/libpq/wininclude/netinet/0000755000176000001440000000000012124517222020132 5ustar ripleyusersRPostgreSQL/src/libpq/wininclude/netinet/in.h0000644000176000001440000000010312124517222020703 0ustar ripleyusers/* src/include/port/win32/netinet/in.h */ #include RPostgreSQL/src/libpq/wininclude/sys/0000755000176000001440000000000012124517222017302 5ustar ripleyusersRPostgreSQL/src/libpq/wininclude/sys/wait.h0000644000176000001440000000005412124517222020416 0ustar ripleyusers/* * src/include/port/win32/sys/wait.h */ RPostgreSQL/src/libpq/wininclude/sys/socket.h0000644000176000001440000000127012124517222020743 0ustar ripleyusers/* * src/include/port/win32/sys/socket.h */ #ifndef WIN32_SYS_SOCKET_H #define WIN32_SYS_SOCKET_H /* * Unfortunately, of VC++ also defines ERROR. * To avoid the conflict, we include here and undefine ERROR * immediately. * * Note: Don't include directly. It causes compile errors. */ #include #include #include #undef ERROR #undef small /* Restore old ERROR value */ #ifdef PGERROR #define ERROR PGERROR #endif /* * we can't use the windows gai_strerror{AW} functions because * they are defined inline in the MS header files. So we'll use our * own */ #undef gai_strerror #endif /* WIN32_SYS_SOCKET_H */ RPostgreSQL/src/libpq/wininclude/netdb.h0000644000176000001440000000004512124517222017730 0ustar ripleyusers/* src/include/port/win32/netdb.h */ RPostgreSQL/src/libpq/pqsignal.c0000644000176000001440000000214112124517222016303 0ustar ripleyusers/*------------------------------------------------------------------------- * * pqsignal.c * reliable BSD-style signal(2) routine stolen from RWW who stole it * from Stevens... * * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * src/interfaces/libpq/pqsignal.c * * NOTES * This shouldn't be in libpq, but the monitor and some other * things need it... * *------------------------------------------------------------------------- */ #include "postgres_fe.h" #include #include "pqsignal.h" pqsigfunc pqsignal(int signo, pqsigfunc func) { #if !defined(HAVE_POSIX_SIGNALS) return signal(signo, func); #else struct sigaction act, oact; act.sa_handler = func; sigemptyset(&act.sa_mask); act.sa_flags = 0; if (signo != SIGALRM) act.sa_flags |= SA_RESTART; #ifdef SA_NOCLDSTOP if (signo == SIGCHLD) act.sa_flags |= SA_NOCLDSTOP; #endif if (sigaction(signo, &act, &oact) < 0) return SIG_ERR; return oact.sa_handler; #endif /* !HAVE_POSIX_SIGNALS */ } RPostgreSQL/src/libpq/blibpqdll.def0000644000176000001440000003214611660061757016771 0ustar ripleyusers; DEF file for Borland C++ Builder LIBRARY BLIBPQ EXPORTS _PQconnectdb @ 1 _PQsetdbLogin @ 2 _PQconndefaults @ 3 _PQfinish @ 4 _PQreset @ 5 _PQrequestCancel @ 6 _PQdb @ 7 _PQuser @ 8 _PQpass @ 9 _PQhost @ 10 _PQport @ 11 _PQtty @ 12 _PQoptions @ 13 _PQstatus @ 14 _PQerrorMessage @ 15 _PQsocket @ 16 _PQbackendPID @ 17 _PQtrace @ 18 _PQuntrace @ 19 _PQsetNoticeProcessor @ 20 _PQexec @ 21 _PQnotifies @ 22 _PQsendQuery @ 23 _PQgetResult @ 24 _PQisBusy @ 25 _PQconsumeInput @ 26 _PQgetline @ 27 _PQputline @ 28 _PQgetlineAsync @ 29 _PQputnbytes @ 30 _PQendcopy @ 31 _PQfn @ 32 _PQresultStatus @ 33 _PQntuples @ 34 _PQnfields @ 35 _PQbinaryTuples @ 36 _PQfname @ 37 _PQfnumber @ 38 _PQftype @ 39 _PQfsize @ 40 _PQfmod @ 41 _PQcmdStatus @ 42 _PQoidStatus @ 43 _PQcmdTuples @ 44 _PQgetvalue @ 45 _PQgetlength @ 46 _PQgetisnull @ 47 _PQclear @ 48 _PQmakeEmptyPGresult @ 49 _PQprint @ 50 _PQdisplayTuples @ 51 _PQprintTuples @ 52 _lo_open @ 53 _lo_close @ 54 _lo_read @ 55 _lo_write @ 56 _lo_lseek @ 57 _lo_creat @ 58 _lo_tell @ 59 _lo_unlink @ 60 _lo_import @ 61 _lo_export @ 62 _pgresStatus @ 63 _PQmblen @ 64 _PQresultErrorMessage @ 65 _PQresStatus @ 66 _termPQExpBuffer @ 67 _appendPQExpBufferChar @ 68 _initPQExpBuffer @ 69 _resetPQExpBuffer @ 70 _PQoidValue @ 71 _PQclientEncoding @ 72 _PQenv2encoding @ 73 _appendBinaryPQExpBuffer @ 74 _appendPQExpBufferStr @ 75 _destroyPQExpBuffer @ 76 _createPQExpBuffer @ 77 _PQconninfoFree @ 78 _PQconnectPoll @ 79 _PQconnectStart @ 80 _PQflush @ 81 _PQisnonblocking @ 82 _PQresetPoll @ 83 _PQresetStart @ 84 _PQsetClientEncoding @ 85 _PQsetnonblocking @ 86 _PQfreeNotify @ 87 _PQescapeString @ 88 _PQescapeBytea @ 89 _printfPQExpBuffer @ 90 _appendPQExpBuffer @ 91 _pg_encoding_to_char @ 92 _pg_utf_mblen @ 93 _PQunescapeBytea @ 94 _PQfreemem @ 95 _PQtransactionStatus @ 96 _PQparameterStatus @ 97 _PQprotocolVersion @ 98 _PQsetErrorVerbosity @ 99 _PQsetNoticeReceiver @ 100 _PQexecParams @ 101 _PQsendQueryParams @ 102 _PQputCopyData @ 103 _PQputCopyEnd @ 104 _PQgetCopyData @ 105 _PQresultErrorField @ 106 _PQftable @ 107 _PQftablecol @ 108 _PQfformat @ 109 _PQexecPrepared @ 110 _PQsendQueryPrepared @ 111 _PQdsplen @ 112 _PQserverVersion @ 113 _PQgetssl @ 114 _pg_char_to_encoding @ 115 _pg_valid_server_encoding @ 116 _pqsignal @ 117 _PQprepare @ 118 _PQsendPrepare @ 119 _PQgetCancel @ 120 _PQfreeCancel @ 121 _PQcancel @ 122 _lo_create @ 123 _PQinitSSL @ 124 _PQregisterThreadLock @ 125 _PQescapeStringConn @ 126 _PQescapeByteaConn @ 127 _PQencryptPassword @ 128 _PQisthreadsafe @ 129 _enlargePQExpBuffer @ 130 _PQnparams @ 131 _PQparamtype @ 132 _PQdescribePrepared @ 133 _PQdescribePortal @ 134 _PQsendDescribePrepared @ 135 _PQsendDescribePortal @ 136 _lo_truncate @ 137 _PQconnectionUsedPassword @ 138 _pg_valid_server_encoding_id @ 139 _PQconnectionNeedsPassword @ 140 _lo_import_with_oid @ 141 _PQcopyResult @ 142 _PQsetResultAttrs @ 143 _PQsetvalue @ 144 _PQresultAlloc @ 145 _PQregisterEventProc @ 146 _PQinstanceData @ 147 _PQsetInstanceData @ 148 _PQresultInstanceData @ 149 _PQresultSetInstanceData @ 150 _PQfireResultCreateEvents @ 151 _PQconninfoParse @ 152 _PQinitOpenSSL @ 153 _PQescapeLiteral @ 154 _PQescapeIdentifier @ 155 _PQconnectdbParams @ 156 _PQconnectStartParams @ 157 _PQping @ 158 _PQpingParams @ 159 _PQlibVersion @ 160 ; Aliases for MS compatible names PQconnectdb = _PQconnectdb PQsetdbLogin = _PQsetdbLogin PQconndefaults = _PQconndefaults PQfinish = _PQfinish PQreset = _PQreset PQrequestCancel = _PQrequestCancel PQdb = _PQdb PQuser = _PQuser PQpass = _PQpass PQhost = _PQhost PQport = _PQport PQtty = _PQtty PQoptions = _PQoptions PQstatus = _PQstatus PQerrorMessage = _PQerrorMessage PQsocket = _PQsocket PQbackendPID = _PQbackendPID PQtrace = _PQtrace PQuntrace = _PQuntrace PQsetNoticeProcessor = _PQsetNoticeProcessor PQexec = _PQexec PQnotifies = _PQnotifies PQsendQuery = _PQsendQuery PQgetResult = _PQgetResult PQisBusy = _PQisBusy PQconsumeInput = _PQconsumeInput PQgetline = _PQgetline PQputline = _PQputline PQgetlineAsync = _PQgetlineAsync PQputnbytes = _PQputnbytes PQendcopy = _PQendcopy PQfn = _PQfn PQresultStatus = _PQresultStatus PQntuples = _PQntuples PQnfields = _PQnfields PQbinaryTuples = _PQbinaryTuples PQfname = _PQfname PQfnumber = _PQfnumber PQftype = _PQftype PQfsize = _PQfsize PQfmod = _PQfmod PQcmdStatus = _PQcmdStatus PQoidStatus = _PQoidStatus PQcmdTuples = _PQcmdTuples PQgetvalue = _PQgetvalue PQgetlength = _PQgetlength PQgetisnull = _PQgetisnull PQclear = _PQclear PQmakeEmptyPGresult = _PQmakeEmptyPGresult PQprint = _PQprint PQdisplayTuples = _PQdisplayTuples PQprintTuples = _PQprintTuples lo_open = _lo_open lo_close = _lo_close lo_read = _lo_read lo_write = _lo_write lo_lseek = _lo_lseek lo_creat = _lo_creat lo_tell = _lo_tell lo_unlink = _lo_unlink lo_import = _lo_import lo_export = _lo_export pgresStatus = _pgresStatus PQmblen = _PQmblen PQresultErrorMessage = _PQresultErrorMessage PQresStatus = _PQresStatus termPQExpBuffer = _termPQExpBuffer appendPQExpBufferChar = _appendPQExpBufferChar initPQExpBuffer = _initPQExpBuffer resetPQExpBuffer = _resetPQExpBuffer PQoidValue = _PQoidValue PQclientEncoding = _PQclientEncoding PQenv2encoding = _PQenv2encoding appendBinaryPQExpBuffer = _appendBinaryPQExpBuffer appendPQExpBufferStr = _appendPQExpBufferStr destroyPQExpBuffer = _destroyPQExpBuffer createPQExpBuffer = _createPQExpBuffer PQconninfoFree = _PQconninfoFree PQconnectPoll = _PQconnectPoll PQconnectStart = _PQconnectStart PQflush = _PQflush PQisnonblocking = _PQisnonblocking PQresetPoll = _PQresetPoll PQresetStart = _PQresetStart PQsetClientEncoding = _PQsetClientEncoding PQsetnonblocking = _PQsetnonblocking PQfreeNotify = _PQfreeNotify PQescapeString = _PQescapeString PQescapeBytea = _PQescapeBytea printfPQExpBuffer = _printfPQExpBuffer appendPQExpBuffer = _appendPQExpBuffer pg_encoding_to_char = _pg_encoding_to_char pg_utf_mblen = _pg_utf_mblen PQunescapeBytea = _PQunescapeBytea PQfreemem = _PQfreemem PQtransactionStatus = _PQtransactionStatus PQparameterStatus = _PQparameterStatus PQprotocolVersion = _PQprotocolVersion PQsetErrorVerbosity = _PQsetErrorVerbosity PQsetNoticeReceiver = _PQsetNoticeReceiver PQexecParams = _PQexecParams PQsendQueryParams = _PQsendQueryParams PQputCopyData = _PQputCopyData PQputCopyEnd = _PQputCopyEnd PQgetCopyData = _PQgetCopyData PQresultErrorField = _PQresultErrorField PQftable = _PQftable PQftablecol = _PQftablecol PQfformat = _PQfformat PQexecPrepared = _PQexecPrepared PQsendQueryPrepared = _PQsendQueryPrepared PQdsplen = _PQdsplen PQserverVersion = _PQserverVersion PQgetssl = _PQgetssl pg_char_to_encoding = _pg_char_to_encoding pg_valid_server_encoding = _pg_valid_server_encoding pqsignal = _pqsignal PQprepare = _PQprepare PQsendPrepare = _PQsendPrepare PQgetCancel = _PQgetCancel PQfreeCancel = _PQfreeCancel PQcancel = _PQcancel lo_create = _lo_create PQinitSSL = _PQinitSSL PQregisterThreadLock = _PQregisterThreadLock PQescapeStringConn = _PQescapeStringConn PQescapeByteaConn = _PQescapeByteaConn PQencryptPassword = _PQencryptPassword PQisthreadsafe = _PQisthreadsafe enlargePQExpBuffer = _enlargePQExpBuffer PQnparams = _PQnparams PQparamtype = _PQparamtype PQdescribePrepared = _PQdescribePrepared PQdescribePortal = _PQdescribePortal PQsendDescribePrepared = _PQsendDescribePrepared PQsendDescribePortal = _PQsendDescribePortal lo_truncate = _lo_truncate PQconnectionUsedPassword = _PQconnectionUsedPassword pg_valid_server_encoding_id = _pg_valid_server_encoding_id PQconnectionNeedsPassword = _PQconnectionNeedsPassword lo_import_with_oid = _lo_import_with_oid PQcopyResult = _PQcopyResult PQsetResultAttrs = _PQsetResultAttrs PQsetvalue = _PQsetvalue PQresultAlloc = _PQresultAlloc PQregisterEventProc = _PQregisterEventProc PQinstanceData = _PQinstanceData PQsetInstanceData = _PQsetInstanceData PQresultInstanceData = _PQresultInstanceData PQresultSetInstanceData = _PQresultSetInstanceData PQfireResultCreateEvents = _PQfireResultCreateEvents PQconninfoParse = _PQconninfoParse PQinitOpenSSL = _PQinitOpenSSL PQescapeLiteral = _PQescapeLiteral PQescapeIdentifier = _PQescapeIdentifier PQconnectdbParams = _PQconnectdbParams PQconnectStartParams = _PQconnectStartParams PQping = _PQping PQpingParams = _PQpingParams PQlibVersion = _PQlibVersion RPostgreSQL/src/libpq/libpq-int.h0000644000176000001440000005310512124517222016377 0ustar ripleyusers/*------------------------------------------------------------------------- * * libpq-int.h * This file contains internal definitions meant to be used only by * the frontend libpq library, not by applications that call it. * * An application can include this file if it wants to bypass the * official API defined by libpq-fe.h, but code that does so is much * more likely to break across PostgreSQL releases than code that uses * only the official API. * * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/interfaces/libpq/libpq-int.h * *------------------------------------------------------------------------- */ #ifndef LIBPQ_INT_H #define LIBPQ_INT_H /* We assume libpq-fe.h has already been included. */ #include "postgres_fe.h" #include "libpq-events.h" #include #include #ifndef WIN32 #include #endif #ifdef ENABLE_THREAD_SAFETY #ifdef WIN32 #include "pthread-win32.h" #else #include #endif #include #endif /* include stuff common to fe and be */ #include "getaddrinfo.h" #include "libpq/pqcomm.h" /* include stuff found in fe only */ #include "pqexpbuffer.h" #ifdef ENABLE_GSS #if defined(HAVE_GSSAPI_H) #include #else #include #endif #endif #ifdef ENABLE_SSPI #define SECURITY_WIN32 #if defined(WIN32) && !defined(WIN32_ONLY_COMPILER) #include #endif #include #undef SECURITY_WIN32 #ifndef ENABLE_GSS /* * Define a fake structure compatible with GSSAPI on Unix. */ typedef struct { void *value; int length; } gss_buffer_desc; #endif #endif /* ENABLE_SSPI */ #ifdef USE_SSL #include #include #if (SSLEAY_VERSION_NUMBER >= 0x00907000L) && !defined(OPENSSL_NO_ENGINE) #define USE_SSL_ENGINE #endif #endif /* USE_SSL */ /* * POSTGRES backend dependent Constants. */ #define CMDSTATUS_LEN 64 /* should match COMPLETION_TAG_BUFSIZE */ /* * PGresult and the subsidiary types PGresAttDesc, PGresAttValue * represent the result of a query (or more precisely, of a single SQL * command --- a query string given to PQexec can contain multiple commands). * Note we assume that a single command can return at most one tuple group, * hence there is no need for multiple descriptor sets. */ /* Subsidiary-storage management structure for PGresult. * See space management routines in fe-exec.c for details. * Note that space[k] refers to the k'th byte starting from the physical * head of the block --- it's a union, not a struct! */ typedef union pgresult_data PGresult_data; union pgresult_data { PGresult_data *next; /* link to next block, or NULL */ char space[1]; /* dummy for accessing block as bytes */ }; /* Data about a single parameter of a prepared statement */ typedef struct pgresParamDesc { Oid typid; /* type id */ } PGresParamDesc; /* * Data for a single attribute of a single tuple * * We use char* for Attribute values. * * The value pointer always points to a null-terminated area; we add a * null (zero) byte after whatever the backend sends us. This is only * particularly useful for text values ... with a binary value, the * value might have embedded nulls, so the application can't use C string * operators on it. But we add a null anyway for consistency. * Note that the value itself does not contain a length word. * * A NULL attribute is a special case in two ways: its len field is NULL_LEN * and its value field points to null_field in the owning PGresult. All the * NULL attributes in a query result point to the same place (there's no need * to store a null string separately for each one). */ #define NULL_LEN (-1) /* pg_result len for NULL value */ typedef struct pgresAttValue { int len; /* length in bytes of the value */ char *value; /* actual value, plus terminating zero byte */ } PGresAttValue; /* Typedef for message-field list entries */ typedef struct pgMessageField { struct pgMessageField *next; /* list link */ char code; /* field code */ char contents[1]; /* field value (VARIABLE LENGTH) */ } PGMessageField; /* Fields needed for notice handling */ typedef struct { PQnoticeReceiver noticeRec; /* notice message receiver */ void *noticeRecArg; PQnoticeProcessor noticeProc; /* notice message processor */ void *noticeProcArg; } PGNoticeHooks; typedef struct PGEvent { PGEventProc proc; /* the function to call on events */ char *name; /* used only for error messages */ void *passThrough; /* pointer supplied at registration time */ void *data; /* optional state (instance) data */ bool resultInitialized; /* T if RESULTCREATE/COPY succeeded */ } PGEvent; struct pg_result { int ntups; int numAttributes; PGresAttDesc *attDescs; PGresAttValue **tuples; /* each PGresTuple is an array of * PGresAttValue's */ int tupArrSize; /* allocated size of tuples array */ int numParameters; PGresParamDesc *paramDescs; ExecStatusType resultStatus; char cmdStatus[CMDSTATUS_LEN]; /* cmd status from the query */ int binary; /* binary tuple values if binary == 1, * otherwise text */ /* * These fields are copied from the originating PGconn, so that operations * on the PGresult don't have to reference the PGconn. */ PGNoticeHooks noticeHooks; PGEvent *events; int nEvents; int client_encoding; /* encoding id */ /* * Error information (all NULL if not an error result). errMsg is the * "overall" error message returned by PQresultErrorMessage. If we have * per-field info then it is stored in a linked list. */ char *errMsg; /* error message, or NULL if no error */ PGMessageField *errFields; /* message broken into fields */ /* All NULL attributes in the query result point to this null string */ char null_field[1]; /* * Space management information. Note that attDescs and error stuff, if * not null, point into allocated blocks. But tuples points to a * separately malloc'd block, so that we can realloc it. */ PGresult_data *curBlock; /* most recently allocated block */ int curOffset; /* start offset of free space in block */ int spaceLeft; /* number of free bytes remaining in block */ }; /* PGAsyncStatusType defines the state of the query-execution state machine */ typedef enum { PGASYNC_IDLE, /* nothing's happening, dude */ PGASYNC_BUSY, /* query in progress */ PGASYNC_READY, /* result ready for PQgetResult */ PGASYNC_COPY_IN, /* Copy In data transfer in progress */ PGASYNC_COPY_OUT, /* Copy Out data transfer in progress */ PGASYNC_COPY_BOTH /* Copy In/Out data transfer in progress */ } PGAsyncStatusType; /* PGQueryClass tracks which query protocol we are now executing */ typedef enum { PGQUERY_SIMPLE, /* simple Query protocol (PQexec) */ PGQUERY_EXTENDED, /* full Extended protocol (PQexecParams) */ PGQUERY_PREPARE, /* Parse only (PQprepare) */ PGQUERY_DESCRIBE /* Describe Statement or Portal */ } PGQueryClass; /* PGSetenvStatusType defines the state of the PQSetenv state machine */ /* (this is used only for 2.0-protocol connections) */ typedef enum { SETENV_STATE_CLIENT_ENCODING_SEND, /* About to send an Environment Option */ SETENV_STATE_CLIENT_ENCODING_WAIT, /* Waiting for above send to complete */ SETENV_STATE_OPTION_SEND, /* About to send an Environment Option */ SETENV_STATE_OPTION_WAIT, /* Waiting for above send to complete */ SETENV_STATE_QUERY1_SEND, /* About to send a status query */ SETENV_STATE_QUERY1_WAIT, /* Waiting for query to complete */ SETENV_STATE_QUERY2_SEND, /* About to send a status query */ SETENV_STATE_QUERY2_WAIT, /* Waiting for query to complete */ SETENV_STATE_IDLE } PGSetenvStatusType; /* Typedef for the EnvironmentOptions[] array */ typedef struct PQEnvironmentOption { const char *envName, /* name of an environment variable */ *pgName; /* name of corresponding SET variable */ } PQEnvironmentOption; /* Typedef for parameter-status list entries */ typedef struct pgParameterStatus { struct pgParameterStatus *next; /* list link */ char *name; /* parameter name */ char *value; /* parameter value */ /* Note: name and value are stored in same malloc block as struct is */ } pgParameterStatus; /* large-object-access data ... allocated only if large-object code is used. */ typedef struct pgLobjfuncs { Oid fn_lo_open; /* OID of backend function lo_open */ Oid fn_lo_close; /* OID of backend function lo_close */ Oid fn_lo_creat; /* OID of backend function lo_creat */ Oid fn_lo_create; /* OID of backend function lo_create */ Oid fn_lo_unlink; /* OID of backend function lo_unlink */ Oid fn_lo_lseek; /* OID of backend function lo_lseek */ Oid fn_lo_tell; /* OID of backend function lo_tell */ Oid fn_lo_truncate; /* OID of backend function lo_truncate */ Oid fn_lo_read; /* OID of backend function LOread */ Oid fn_lo_write; /* OID of backend function LOwrite */ } PGlobjfuncs; /* * PGconn stores all the state data associated with a single connection * to a backend. */ struct pg_conn { /* Saved values of connection options */ char *pghost; /* the machine on which the server is running */ char *pghostaddr; /* the numeric IP address of the machine on * which the server is running. Takes * precedence over above. */ char *pgport; /* the server's communication port */ char *pgunixsocket; /* the Unix-domain socket that the server is * listening on; if NULL, uses a default * constructed from pgport */ char *pgtty; /* tty on which the backend messages is * displayed (OBSOLETE, NOT USED) */ char *connect_timeout; /* connection timeout (numeric string) */ char *client_encoding_initial; /* encoding to use */ char *pgoptions; /* options to start the backend with */ char *appname; /* application name */ char *fbappname; /* fallback application name */ char *dbName; /* database name */ char *replication; /* connect as the replication standby? */ char *pguser; /* Postgres username and password, if any */ char *pgpass; char *keepalives; /* use TCP keepalives? */ char *keepalives_idle; /* time between TCP keepalives */ char *keepalives_interval; /* time between TCP keepalive * retransmits */ char *keepalives_count; /* maximum number of TCP keepalive * retransmits */ char *sslmode; /* SSL mode (require,prefer,allow,disable) */ char *sslkey; /* client key filename */ char *sslcert; /* client certificate filename */ char *sslrootcert; /* root certificate filename */ char *sslcrl; /* certificate revocation list filename */ char *requirepeer; /* required peer credentials for local sockets */ #if defined(KRB5) || defined(ENABLE_GSS) || defined(ENABLE_SSPI) char *krbsrvname; /* Kerberos service name */ #endif /* Optional file to write trace info to */ FILE *Pfdebug; /* Callback procedures for notice message processing */ PGNoticeHooks noticeHooks; /* Event procs registered via PQregisterEventProc */ PGEvent *events; /* expandable array of event data */ int nEvents; /* number of active events */ int eventArraySize; /* allocated array size */ /* Status indicators */ ConnStatusType status; PGAsyncStatusType asyncStatus; PGTransactionStatusType xactStatus; /* never changes to ACTIVE */ PGQueryClass queryclass; char *last_query; /* last SQL command, or NULL if unknown */ char last_sqlstate[6]; /* last reported SQLSTATE */ bool options_valid; /* true if OK to attempt connection */ bool nonblocking; /* whether this connection is using nonblock * sending semantics */ char copy_is_binary; /* 1 = copy binary, 0 = copy text */ int copy_already_done; /* # bytes already returned in COPY * OUT */ PGnotify *notifyHead; /* oldest unreported Notify msg */ PGnotify *notifyTail; /* newest unreported Notify msg */ /* Connection data */ int sock; /* Unix FD for socket, -1 if not connected */ SockAddr laddr; /* Local address */ SockAddr raddr; /* Remote address */ ProtocolVersion pversion; /* FE/BE protocol version in use */ int sversion; /* server version, e.g. 70401 for 7.4.1 */ bool auth_req_received; /* true if any type of auth req * received */ bool password_needed; /* true if server demanded a password */ bool dot_pgpass_used; /* true if used .pgpass */ bool sigpipe_so; /* have we masked SIGPIPE via SO_NOSIGPIPE? */ bool sigpipe_flag; /* can we mask SIGPIPE via MSG_NOSIGNAL? */ /* Transient state needed while establishing connection */ struct addrinfo *addrlist; /* list of possible backend addresses */ struct addrinfo *addr_cur; /* the one currently being tried */ int addrlist_family; /* needed to know how to free addrlist */ PGSetenvStatusType setenv_state; /* for 2.0 protocol only */ const PQEnvironmentOption *next_eo; bool send_appname; /* okay to send application_name? */ /* Miscellaneous stuff */ int be_pid; /* PID of backend --- needed for cancels */ int be_key; /* key of backend --- needed for cancels */ char md5Salt[4]; /* password salt received from backend */ pgParameterStatus *pstatus; /* ParameterStatus data */ int client_encoding; /* encoding id */ bool std_strings; /* standard_conforming_strings */ PGVerbosity verbosity; /* error/notice message verbosity */ PGlobjfuncs *lobjfuncs; /* private state for large-object access fns */ /* Buffer for data received from backend and not yet processed */ char *inBuffer; /* currently allocated buffer */ int inBufSize; /* allocated size of buffer */ int inStart; /* offset to first unconsumed data in buffer */ int inCursor; /* next byte to tentatively consume */ int inEnd; /* offset to first position after avail data */ /* Buffer for data not yet sent to backend */ char *outBuffer; /* currently allocated buffer */ int outBufSize; /* allocated size of buffer */ int outCount; /* number of chars waiting in buffer */ /* State for constructing messages in outBuffer */ int outMsgStart; /* offset to msg start (length word); if -1, * msg has no length word */ int outMsgEnd; /* offset to msg end (so far) */ /* Status for asynchronous result construction */ PGresult *result; /* result being constructed */ PGresAttValue *curTuple; /* tuple currently being read */ #ifdef USE_SSL bool allow_ssl_try; /* Allowed to try SSL negotiation */ bool wait_ssl_try; /* Delay SSL negotiation until after * attempting normal connection */ SSL *ssl; /* SSL status, if have SSL connection */ X509 *peer; /* X509 cert of server */ char peer_dn[256 + 1]; /* peer distinguished name */ char peer_cn[SM_USER + 1]; /* peer common name */ #ifdef USE_SSL_ENGINE ENGINE *engine; /* SSL engine, if any */ #else void *engine; /* dummy field to keep struct the same if * OpenSSL version changes */ #endif #endif /* USE_SSL */ #ifdef ENABLE_GSS gss_ctx_id_t gctx; /* GSS context */ gss_name_t gtarg_nam; /* GSS target name */ gss_buffer_desc ginbuf; /* GSS input token */ gss_buffer_desc goutbuf; /* GSS output token */ #endif #ifdef ENABLE_SSPI #ifndef ENABLE_GSS gss_buffer_desc ginbuf; /* GSS input token */ #else char *gsslib; /* What GSS librart to use ("gssapi" or * "sspi") */ #endif CredHandle *sspicred; /* SSPI credentials handle */ CtxtHandle *sspictx; /* SSPI context */ char *sspitarget; /* SSPI target name */ int usesspi; /* Indicate if SSPI is in use on the * connection */ #endif /* Buffer for current error message */ PQExpBufferData errorMessage; /* expansible string */ /* Buffer for receiving various parts of messages */ PQExpBufferData workBuffer; /* expansible string */ }; /* PGcancel stores all data necessary to cancel a connection. A copy of this * data is required to safely cancel a connection running on a different * thread. */ struct pg_cancel { SockAddr raddr; /* Remote address */ int be_pid; /* PID of backend --- needed for cancels */ int be_key; /* key of backend --- needed for cancels */ }; /* String descriptions of the ExecStatusTypes. * direct use of this array is deprecated; call PQresStatus() instead. */ extern char *const pgresStatus[]; /* ---------------- * Internal functions of libpq * Functions declared here need to be visible across files of libpq, * but are not intended to be called by applications. We use the * convention "pqXXX" for internal functions, vs. the "PQxxx" names * used for application-visible routines. * ---------------- */ /* === in fe-connect.c === */ extern int pqPacketSend(PGconn *conn, char pack_type, const void *buf, size_t buf_len); extern bool pqGetHomeDirectory(char *buf, int bufsize); #ifdef ENABLE_THREAD_SAFETY extern pgthreadlock_t pg_g_threadlock; #define PGTHREAD_ERROR(msg) \ do { \ fprintf(stderr, "%s\n", msg); \ exit(1); \ } while (0) #define pglock_thread() pg_g_threadlock(true) #define pgunlock_thread() pg_g_threadlock(false) #else #define pglock_thread() ((void) 0) #define pgunlock_thread() ((void) 0) #endif /* === in fe-exec.c === */ extern void pqSetResultError(PGresult *res, const char *msg); extern void pqCatenateResultError(PGresult *res, const char *msg); extern void *pqResultAlloc(PGresult *res, size_t nBytes, bool isBinary); extern char *pqResultStrdup(PGresult *res, const char *str); extern void pqClearAsyncResult(PGconn *conn); extern void pqSaveErrorResult(PGconn *conn); extern PGresult *pqPrepareAsyncResult(PGconn *conn); extern void pqInternalNotice(const PGNoticeHooks *hooks, const char *fmt,...) /* This lets gcc check the format string for consistency. */ __attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 3))); extern int pqAddTuple(PGresult *res, PGresAttValue *tup); extern void pqSaveMessageField(PGresult *res, char code, const char *value); extern void pqSaveParameterStatus(PGconn *conn, const char *name, const char *value); extern void pqHandleSendFailure(PGconn *conn); /* === in fe-protocol2.c === */ extern PostgresPollingStatusType pqSetenvPoll(PGconn *conn); extern char *pqBuildStartupPacket2(PGconn *conn, int *packetlen, const PQEnvironmentOption *options); extern void pqParseInput2(PGconn *conn); extern int pqGetCopyData2(PGconn *conn, char **buffer, int async); extern int pqGetline2(PGconn *conn, char *s, int maxlen); extern int pqGetlineAsync2(PGconn *conn, char *buffer, int bufsize); extern int pqEndcopy2(PGconn *conn); extern PGresult *pqFunctionCall2(PGconn *conn, Oid fnid, int *result_buf, int *actual_result_len, int result_is_int, const PQArgBlock *args, int nargs); /* === in fe-protocol3.c === */ extern char *pqBuildStartupPacket3(PGconn *conn, int *packetlen, const PQEnvironmentOption *options); extern void pqParseInput3(PGconn *conn); extern int pqGetErrorNotice3(PGconn *conn, bool isError); extern int pqGetCopyData3(PGconn *conn, char **buffer, int async); extern int pqGetline3(PGconn *conn, char *s, int maxlen); extern int pqGetlineAsync3(PGconn *conn, char *buffer, int bufsize); extern int pqEndcopy3(PGconn *conn); extern PGresult *pqFunctionCall3(PGconn *conn, Oid fnid, int *result_buf, int *actual_result_len, int result_is_int, const PQArgBlock *args, int nargs); /* === in fe-misc.c === */ /* * "Get" and "Put" routines return 0 if successful, EOF if not. Note that for * Get, EOF merely means the buffer is exhausted, not that there is * necessarily any error. */ extern int pqCheckOutBufferSpace(size_t bytes_needed, PGconn *conn); extern int pqCheckInBufferSpace(size_t bytes_needed, PGconn *conn); extern int pqGetc(char *result, PGconn *conn); extern int pqPutc(char c, PGconn *conn); extern int pqGets(PQExpBuffer buf, PGconn *conn); extern int pqGets_append(PQExpBuffer buf, PGconn *conn); extern int pqPuts(const char *s, PGconn *conn); extern int pqGetnchar(char *s, size_t len, PGconn *conn); extern int pqPutnchar(const char *s, size_t len, PGconn *conn); extern int pqGetInt(int *result, size_t bytes, PGconn *conn); extern int pqPutInt(int value, size_t bytes, PGconn *conn); extern int pqPutMsgStart(char msg_type, bool force_len, PGconn *conn); extern int pqPutMsgEnd(PGconn *conn); extern int pqReadData(PGconn *conn); extern int pqFlush(PGconn *conn); extern int pqWait(int forRead, int forWrite, PGconn *conn); extern int pqWaitTimed(int forRead, int forWrite, PGconn *conn, time_t finish_time); extern int pqReadReady(PGconn *conn); extern int pqWriteReady(PGconn *conn); /* === in fe-secure.c === */ extern int pqsecure_initialize(PGconn *); extern void pqsecure_destroy(void); extern PostgresPollingStatusType pqsecure_open_client(PGconn *); extern void pqsecure_close(PGconn *); extern ssize_t pqsecure_read(PGconn *, void *ptr, size_t len); extern ssize_t pqsecure_write(PGconn *, const void *ptr, size_t len); #if defined(ENABLE_THREAD_SAFETY) && !defined(WIN32) extern int pq_block_sigpipe(sigset_t *osigset, bool *sigpipe_pending); extern void pq_reset_sigpipe(sigset_t *osigset, bool sigpipe_pending, bool got_epipe); #endif /* * this is so that we can check if a connection is non-blocking internally * without the overhead of a function call */ #define pqIsnonblocking(conn) ((conn)->nonblocking) #ifdef ENABLE_NLS extern char * libpq_gettext(const char *msgid) __attribute__((format_arg(1))); #else #define libpq_gettext(x) (x) #endif /* * These macros are needed to let error-handling code be portable between * Unix and Windows. (ugh) */ #ifdef WIN32 #define SOCK_ERRNO (WSAGetLastError()) #define SOCK_STRERROR winsock_strerror #define SOCK_ERRNO_SET(e) WSASetLastError(e) #else #define SOCK_ERRNO errno #define SOCK_STRERROR pqStrerror #define SOCK_ERRNO_SET(e) (errno = (e)) #endif #endif /* LIBPQ_INT_H */ RPostgreSQL/src/libpq/win32.mak0000644000176000001440000002117411660061757015777 0ustar ripleyusers# Makefile for Microsoft Visual C++ 7.1-8.0 # Will build a static library libpq(d).lib # and a dynamic library libpq(d).dll with import library libpq(d)dll.lib # USE_SSL=1 will compile with OpenSSL # USE_KFW=1 will compile with kfw(kerberos for Windows) # DEBUG=1 compiles with debugging symbols # ENABLE_THREAD_SAFETY=1 compiles with threading enabled ENABLE_THREAD_SAFETY=1 # CPU="i386" or CPU environment of nmake.exe (AMD64 or IA64) !IF ("$(CPU)" == "")||("$(CPU)" == "i386") CPU=i386 !MESSAGE Building the Win32 static library... !MESSAGE !ELSEIF ("$(CPU)" == "IA64")||("$(CPU)" == "AMD64") ADD_DEFINES=/D "WIN64" /Wp64 /GS ADD_SECLIB=bufferoverflowU.lib !MESSAGE Building the Win64 static library... !MESSAGE !ELSE !MESSAGE Please check a CPU=$(CPU) ? !MESSAGE CPU=i386 or AMD64 or IA64 !ERROR Make aborted. !ENDIF !IFDEF DEBUG OPT=/Od /Zi /MDd LOPT=/DEBUG DEBUGDEF=/D _DEBUG OUTFILENAME=libpqd !ELSE OPT=/O2 /MD LOPT= DEBUGDEF=/D NDEBUG OUTFILENAME=libpq !ENDIF !IF "$(SSL_INC)" == "" SSL_INC=C:\OpenSSL\include !MESSAGE Using default OpenSSL Include directory: $(SSL_INC) !ENDIF !IF "$(SSL_LIB_PATH)" == "" SSL_LIB_PATH=C:\OpenSSL\lib\VC !MESSAGE Using default OpenSSL Library directory: $(SSL_LIB_PATH) !ENDIF !IF "$(KFW_INC)" == "" KFW_INC=C:\kfw-2.6.5\inc !MESSAGE Using default Kerberos Include directory: $(KFW_INC) !ENDIF !IF "$(KFW_LIB_PATH)" == "" KFW_LIB_PATH=C:\kfw-2.6.5\lib\$(CPU) !MESSAGE Using default Kerberos Library directory: $(KFW_LIB_PATH) !ENDIF !IF "$(OS)" == "Windows_NT" NULL= !ELSE NULL=nul !ENDIF CPP=cl.exe RSC=rc.exe !IFDEF DEBUG OUTDIR=.\Debug INTDIR=.\Debug CPP_OBJS=.\Debug/ !ELSE OUTDIR=.\Release INTDIR=.\Release CPP_OBJS=.\Release/ !ENDIF ALL : config "$(OUTDIR)\$(OUTFILENAME).lib" "$(OUTDIR)\$(OUTFILENAME).dll" CLEAN : -@erase "$(INTDIR)\getaddrinfo.obj" -@erase "$(INTDIR)\pgstrcasecmp.obj" -@erase "$(INTDIR)\thread.obj" -@erase "$(INTDIR)\inet_aton.obj" -@erase "$(INTDIR)\crypt.obj" -@erase "$(INTDIR)\noblock.obj" -@erase "$(INTDIR)\chklocale.obj" -@erase "$(INTDIR)\inet_net_ntop.obj" -@erase "$(INTDIR)\md5.obj" -@erase "$(INTDIR)\ip.obj" -@erase "$(INTDIR)\fe-auth.obj" -@erase "$(INTDIR)\fe-protocol2.obj" -@erase "$(INTDIR)\fe-protocol3.obj" -@erase "$(INTDIR)\fe-connect.obj" -@erase "$(INTDIR)\fe-exec.obj" -@erase "$(INTDIR)\fe-lobj.obj" -@erase "$(INTDIR)\fe-misc.obj" -@erase "$(INTDIR)\fe-print.obj" -@erase "$(INTDIR)\fe-secure.obj" -@erase "$(INTDIR)\libpq-events.obj" -@erase "$(INTDIR)\pqexpbuffer.obj" -@erase "$(INTDIR)\pqsignal.obj" -@erase "$(INTDIR)\win32.obj" -@erase "$(INTDIR)\wchar.obj" -@erase "$(INTDIR)\encnames.obj" -@erase "$(INTDIR)\pthread-win32.obj" -@erase "$(INTDIR)\snprintf.obj" -@erase "$(INTDIR)\strlcpy.obj" -@erase "$(INTDIR)\dirent.obj" -@erase "$(INTDIR)\dirmod.obj" -@erase "$(INTDIR)\pgsleep.obj" -@erase "$(INTDIR)\open.obj" -@erase "$(INTDIR)\win32error.obj" -@erase "$(INTDIR)\win32setlocale.obj" -@erase "$(OUTDIR)\$(OUTFILENAME).lib" -@erase "$(OUTDIR)\$(OUTFILENAME)dll.lib" -@erase "$(OUTDIR)\libpq.res" -@erase "$(OUTDIR)\$(OUTFILENAME).dll" -@erase "$(OUTDIR)\$(OUTFILENAME)dll.exp" -@erase "$(OUTDIR)\$(OUTFILENAME).dll.manifest" -@erase "$(OUTDIR)\*.idb" -@erase pg_config_paths.h" LIB32=link.exe -lib LIB32_FLAGS=$(LOPT) /nologo /out:"$(OUTDIR)\$(OUTFILENAME).lib" LIB32_OBJS= \ "$(INTDIR)\win32.obj" \ "$(INTDIR)\getaddrinfo.obj" \ "$(INTDIR)\pgstrcasecmp.obj" \ "$(INTDIR)\thread.obj" \ "$(INTDIR)\inet_aton.obj" \ "$(INTDIR)\crypt.obj" \ "$(INTDIR)\noblock.obj" \ "$(INTDIR)\chklocale.obj" \ "$(INTDIR)\inet_net_ntop.obj" \ "$(INTDIR)\md5.obj" \ "$(INTDIR)\ip.obj" \ "$(INTDIR)\fe-auth.obj" \ "$(INTDIR)\fe-protocol2.obj" \ "$(INTDIR)\fe-protocol3.obj" \ "$(INTDIR)\fe-connect.obj" \ "$(INTDIR)\fe-exec.obj" \ "$(INTDIR)\fe-lobj.obj" \ "$(INTDIR)\fe-misc.obj" \ "$(INTDIR)\fe-print.obj" \ "$(INTDIR)\fe-secure.obj" \ "$(INTDIR)\libpq-events.obj" \ "$(INTDIR)\pqexpbuffer.obj" \ "$(INTDIR)\pqsignal.obj" \ "$(INTDIR)\wchar.obj" \ "$(INTDIR)\encnames.obj" \ "$(INTDIR)\snprintf.obj" \ "$(INTDIR)\strlcpy.obj" \ "$(INTDIR)\dirent.obj" \ "$(INTDIR)\dirmod.obj" \ "$(INTDIR)\pgsleep.obj" \ "$(INTDIR)\open.obj" \ "$(INTDIR)\win32error.obj" \ "$(INTDIR)\win32setlocale.obj" \ "$(INTDIR)\pthread-win32.obj" config: ..\..\include\pg_config.h pg_config_paths.h ..\..\include\pg_config_os.h ..\..\include\pg_config.h: ..\..\include\pg_config.h.win32 copy ..\..\include\pg_config.h.win32 ..\..\include\pg_config.h ..\..\include\pg_config_os.h: copy ..\..\include\port\win32.h ..\..\include\pg_config_os.h pg_config_paths.h: win32.mak echo #define SYSCONFDIR "" > pg_config_paths.h "$(OUTDIR)" : if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" CPP_PROJ=/nologo /W3 /EHsc $(OPT) /I "..\..\include" /I "..\..\include\port\win32" /I "..\..\include\port\win32_msvc" /I "..\..\port" /I. /I "$(SSL_INC)" \ /D "FRONTEND" $(DEBUGDEF) \ /D "WIN32" /D "_WINDOWS" /Fp"$(INTDIR)\libpq.pch" \ /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c \ /D "_CRT_SECURE_NO_DEPRECATE" $(ADD_DEFINES) !IFDEF USE_SSL CPP_PROJ=$(CPP_PROJ) /D USE_SSL SSL_LIBS=ssleay32.lib libeay32.lib gdi32.lib !ENDIF !IFDEF USE_KFW CPP_PROJ=$(CPP_PROJ) /D KRB5 KFW_LIBS=krb5_32.lib comerr32.lib gssapi32.lib !ENDIF !IFDEF ENABLE_THREAD_SAFETY CPP_PROJ=$(CPP_PROJ) /D ENABLE_THREAD_SAFETY !ENDIF CPP_SBRS=. RSC_PROJ=/l 0x409 /fo"$(INTDIR)\libpq.res" LINK32=link.exe LINK32_FLAGS=kernel32.lib user32.lib advapi32.lib shfolder.lib wsock32.lib ws2_32.lib secur32.lib $(SSL_LIBS) $(KFW_LIB) $(ADD_SECLIB) \ /nologo /subsystem:windows /dll $(LOPT) /incremental:no \ /pdb:"$(OUTDIR)\libpqdll.pdb" /machine:$(CPU) \ /out:"$(OUTDIR)\$(OUTFILENAME).dll"\ /implib:"$(OUTDIR)\$(OUTFILENAME)dll.lib" \ /libpath:"$(SSL_LIB_PATH)" /libpath:"$(KFW_LIB_PATH)" \ /def:$(OUTFILENAME)dll.def LINK32_OBJS= \ "$(OUTDIR)\$(OUTFILENAME).lib" \ "$(OUTDIR)\libpq.res" # @<< is a Response file, http://www.opussoftware.com/tutorial/TutMakefile.htm "$(OUTDIR)\$(OUTFILENAME).lib" : "$(OUTDIR)" $(DEF_FILE) $(LIB32_OBJS) $(LIB32) @<< $(LIB32_FLAGS) $(DEF_FLAGS) $(LIB32_OBJS) << "$(INTDIR)\libpq.res" : "$(INTDIR)" libpq-dist.rc $(RSC) $(RSC_PROJ) libpq-dist.rc "$(OUTDIR)\$(OUTFILENAME).dll" : "$(OUTDIR)" "$(INTDIR)\libpq.res" $(LINK32) @<< $(LINK32_FLAGS) $(LINK32_OBJS) << # Inclusion of manifest !IF "$(_NMAKE_VER)" != "6.00.8168.0" && "$(_NMAKE_VER)" != "7.00.9466" !IF "$(_NMAKE_VER)" != "6.00.9782.0" && "$(_NMAKE_VER)" != "7.10.3077" mt -manifest $(OUTDIR)\$(OUTFILENAME).dll.manifest -outputresource:$(OUTDIR)\$(OUTFILENAME).dll;2 !ENDIF !ENDIF "$(INTDIR)\getaddrinfo.obj" : ..\..\port\getaddrinfo.c $(CPP) @<< $(CPP_PROJ) ..\..\port\getaddrinfo.c << "$(INTDIR)\pgstrcasecmp.obj" : ..\..\port\pgstrcasecmp.c $(CPP) @<< $(CPP_PROJ) ..\..\port\pgstrcasecmp.c << "$(INTDIR)\thread.obj" : ..\..\port\thread.c $(CPP) @<< $(CPP_PROJ) ..\..\port\thread.c << "$(INTDIR)\inet_aton.obj" : ..\..\port\inet_aton.c $(CPP) @<< $(CPP_PROJ) ..\..\port\inet_aton.c << "$(INTDIR)\crypt.obj" : ..\..\port\crypt.c $(CPP) @<< $(CPP_PROJ) ..\..\port\crypt.c << "$(INTDIR)\noblock.obj" : ..\..\port\noblock.c $(CPP) @<< $(CPP_PROJ) ..\..\port\noblock.c << "$(INTDIR)\chklocale.obj" : ..\..\port\chklocale.c $(CPP) @<< $(CPP_PROJ) ..\..\port\chklocale.c << "$(INTDIR)\inet_net_ntop.obj" : ..\..\port\inet_net_ntop.c $(CPP) @<< $(CPP_PROJ) ..\..\port\inet_net_ntop.c << "$(INTDIR)\md5.obj" : ..\..\backend\libpq\md5.c $(CPP) @<< $(CPP_PROJ) ..\..\backend\libpq\md5.c << "$(INTDIR)\ip.obj" : ..\..\backend\libpq\ip.c $(CPP) @<< $(CPP_PROJ) ..\..\backend\libpq\ip.c << "$(INTDIR)\wchar.obj" : ..\..\backend\utils\mb\wchar.c $(CPP) @<< $(CPP_PROJ) /I"." ..\..\backend\utils\mb\wchar.c << "$(INTDIR)\encnames.obj" : ..\..\backend\utils\mb\encnames.c $(CPP) @<< $(CPP_PROJ) /I"." ..\..\backend\utils\mb\encnames.c << "$(INTDIR)\snprintf.obj" : ..\..\port\snprintf.c $(CPP) @<< $(CPP_PROJ) /I"." ..\..\port\snprintf.c << "$(INTDIR)\strlcpy.obj" : ..\..\port\strlcpy.c $(CPP) @<< $(CPP_PROJ) /I"." ..\..\port\strlcpy.c << "$(INTDIR)\dirent.obj" : ..\..\port\dirent.c $(CPP) @<< $(CPP_PROJ) /I"." ..\..\port\dirent.c << "$(INTDIR)\dirmod.obj" : ..\..\port\dirmod.c $(CPP) @<< $(CPP_PROJ) /I"." ..\..\port\dirmod.c << "$(INTDIR)\pgsleep.obj" : ..\..\port\pgsleep.c $(CPP) @<< $(CPP_PROJ) /I"." ..\..\port\pgsleep.c << "$(INTDIR)\open.obj" : ..\..\port\open.c $(CPP) @<< $(CPP_PROJ) /I"." ..\..\port\open.c << "$(INTDIR)\win32error.obj" : ..\..\port\win32error.c $(CPP) @<< $(CPP_PROJ) /I"." ..\..\port\win32error.c << "$(INTDIR)\win32setlocale.obj" : ..\..\port\win32setlocale.c $(CPP) @<< $(CPP_PROJ) /I"." ..\..\port\win32setlocale.c << .c{$(CPP_OBJS)}.obj: $(CPP) $(CPP_PROJ) $< .c.obj: $(CPP) $(CPP_PROJ) $< RPostgreSQL/src/libpq/libpq-dist.rc0000644000176000001440000000146711660061757016744 0ustar ripleyusers#include VS_VERSION_INFO VERSIONINFO FILEVERSION 9,1,1,11265 PRODUCTVERSION 9,1,1,11265 FILEFLAGSMASK 0x3fL FILEFLAGS 0 FILEOS VOS__WINDOWS32 FILETYPE VFT_DLL FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904B0" BEGIN VALUE "CompanyName", "\0" VALUE "FileDescription", "PostgreSQL Access Library\0" VALUE "FileVersion", "9.1.1\0" VALUE "InternalName", "libpq\0" VALUE "LegalCopyright", "Copyright (C) 2011\0" VALUE "LegalTrademarks", "\0" VALUE "OriginalFilename", "libpq.dll\0" VALUE "ProductName", "PostgreSQL\0" VALUE "ProductVersion", "9.1.1\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1200 END END RPostgreSQL/src/libpq/Makefile.global.win640000644000176000001440000004756411711132675020216 0ustar ripleyusers# -*-makefile-*- # src/Makefile.global.in #------------------------------------------------------------------------------ # All PostgreSQL makefiles include this file and use the variables it sets, # which in turn are put here by the configure script. There is no need for # users to edit this file -- if it turns out to be necessary then that's a # bug. # # A makefile that includes this file needs to set the variable `subdir' to # the relative path from the top to itself and `top_builddir' to the relative # path from itself to the top before including this file. (The "top" is the # parent directory of the directory this file is in.) #------------------------------------------------------------------------------ ########################################################################## # # Meta configuration standard_targets = all install installdirs uninstall distprep clean distclean maintainer-clean coverage check installcheck maintainer-check # these targets should recurse even into subdirectories not being built: standard_always_targets = distprep clean distclean maintainer-clean .PHONY: $(standard_targets) install-strip html man installcheck-parallel # make `all' the default target all: # Delete target files if the command fails after it has # started to update the file. .DELETE_ON_ERROR: # PostgreSQL version number VERSION = 9.1.1 MAJORVERSION = 9.1 # Support for VPATH builds vpath_build = no abs_top_srcdir = /cygdrive/c/R64/postgresql-9.1.1 ifneq ($(vpath_build),yes) top_srcdir = $(top_builddir) srcdir = . else # vpath_build = yes top_srcdir = $(abs_top_srcdir) srcdir = $(top_srcdir)/$(subdir) endif vpathsearch = `for f in $(addsuffix /$(1),$(subst :, ,. $(VPATH))); do test -r $$f && echo $$f && break; done` # Saved arguments from configure # configure_args = '--host=x86_64-w64-mingw32' '--without-zlib' 'host_alias=x86_64-w64-mingw32' ########################################################################## # # Installation directories # # These are set by the equivalent --xxxdir configure options. We # append "postgresql" to some of them, if the string does not already # contain "pgsql" or "postgres", in order to avoid directory clutter. # # In a PGXS build, we cannot use the values inserted into Makefile.global # by configure, since the installation tree may have been relocated. # Instead get the path values from pg_config. ifndef PGXS # Note that prefix, exec_prefix, and datarootdir aren't defined in a PGXS build; # makefiles may only use the derived variables such as bindir. prefix := /usr/local/pgsql exec_prefix := ${prefix} datarootdir := ${prefix}/share bindir := ${exec_prefix}/bin datadir := ${datarootdir} ifeq "$(findstring pgsql, $(datadir))" "" ifeq "$(findstring postgres, $(datadir))" "" override datadir := $(datadir)/postgresql endif endif sysconfdir := ${prefix}/etc ifeq "$(findstring pgsql, $(sysconfdir))" "" ifeq "$(findstring postgres, $(sysconfdir))" "" override sysconfdir := $(sysconfdir)/postgresql endif endif libdir := ${exec_prefix}/lib pkglibdir = $(libdir) ifeq "$(findstring pgsql, $(pkglibdir))" "" ifeq "$(findstring postgres, $(pkglibdir))" "" override pkglibdir := $(pkglibdir)/postgresql endif endif includedir := ${prefix}/include pkgincludedir = $(includedir) ifeq "$(findstring pgsql, $(pkgincludedir))" "" ifeq "$(findstring postgres, $(pkgincludedir))" "" override pkgincludedir := $(pkgincludedir)/postgresql endif endif mandir := ${datarootdir}/man docdir := ${datarootdir}/doc/${PACKAGE_TARNAME} ifeq "$(findstring pgsql, $(docdir))" "" ifeq "$(findstring postgres, $(docdir))" "" override docdir := $(docdir)/postgresql endif endif htmldir := ${docdir} localedir := ${datarootdir}/locale else # PGXS case # Extension makefiles should set PG_CONFIG, but older ones might not ifndef PG_CONFIG PG_CONFIG = pg_config endif bindir := $(shell $(PG_CONFIG) --bindir) datadir := $(shell $(PG_CONFIG) --sharedir) sysconfdir := $(shell $(PG_CONFIG) --sysconfdir) libdir := $(shell $(PG_CONFIG) --libdir) pkglibdir := $(shell $(PG_CONFIG) --pkglibdir) includedir := $(shell $(PG_CONFIG) --includedir) pkgincludedir := $(shell $(PG_CONFIG) --pkgincludedir) mandir := $(shell $(PG_CONFIG) --mandir) docdir := $(shell $(PG_CONFIG) --docdir) localedir := $(shell $(PG_CONFIG) --localedir) endif # PGXS # These derived path variables aren't separately configurable. includedir_server = $(pkgincludedir)/server includedir_internal = $(pkgincludedir)/internal pgxsdir = $(pkglibdir)/pgxs ########################################################################## # # Features # # Records the choice of the various --enable-xxx and --with-xxx options. with_perl = no with_python = no with_tcl = no with_openssl = no with_ossp_uuid = no with_selinux = no with_libxml = no with_libxslt = no with_system_tzdata = with_zlib = no enable_shared = yes enable_rpath = yes enable_nls = no enable_debug = no enable_dtrace = no enable_coverage = no enable_thread_safety = yes python_includespec = python_libdir = python_libspec = python_additional_libs = python_configdir = python_majorversion = python_version = krb_srvtab = TCLSH = TCL_LIB_FILE = TCL_LIBS = TCL_LIB_SPEC = TCL_INCLUDE_SPEC = TCL_SHARED_BUILD = TCL_SHLIB_LD_LIBS = PTHREAD_CFLAGS = PTHREAD_LIBS = ########################################################################## # # Programs and flags # Compilers #CPP = x86_64-w64-mingw32-gcc -E # hope this is set appropriately by the system CPPFLAGS = -I./src/include/port/win32 -DEXEC_BACKEND ifdef PGXS override CPPFLAGS := -I$(includedir_server) -I$(includedir_internal) $(CPPFLAGS) else # not PGXS override CPPFLAGS := -I$(top_srcdir)/src/include $(CPPFLAGS) ifdef VPATH override CPPFLAGS := -I$(top_builddir)/src/include $(CPPFLAGS) endif endif # not PGXS #CC = x86_64-w64-mingw32-gcc ifeq ($(CC),gcc) CC=gcc -m64 endif ifeq "$(CC)" "x86_64-w64-mingw32-gcc " CC=x86_64-w64-mingw32-gcc endif # hope this variable is set appropriately by the system GCC = yes SUN_STUDIO_CC = no CFLAGS = -O2 -Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement -Wendif-labels -Wformat-security -fno-strict-aliasing -fwrapv # Kind-of compilers BISON = /bin/bison BISONFLAGS = $(YFLAGS) FLEX = /bin/flex FLEXFLAGS = $(LFLAGS) DTRACE = DTRACEFLAGS = ZIC = # Linking ifeq "$(CC)" "x86_64-w64-mingw32-gcc" AR = x86_64-w64-mingw32-ar endif # hope this variable is set appropriately by the system ifeq "$(CC)" "x86_64-w64-mingw32-gcc" DLLTOOL = x86_64-w64-mingw32-dlltool DLLWRAP = x86_64-w64-mingw32-dllwrap else DLLTOOL = dlltool -m64 DLLWRAP = dllwrap -m64 endif LIBS = -lwsock32 -lm LDAP_LIBS_FE = LDAP_LIBS_BE = OSSP_UUID_LIBS = #LD = c:/rtools/mingw64/x86_64-w64-mingw32/bin/ld.exe # hope this variable is set appropriately by the system with_gnu_ld = yes ld_R_works = # We want -L for libpgport.a to be first in LDFLAGS. We also need LDFLAGS # to be a "recursively expanded" variable, else adjustments to rpathdir # don't work right. So we must NOT do LDFLAGS := something, meaning this has # to be done first and elsewhere we must only do LDFLAGS += something. ifdef PGXS LDFLAGS = -L$(libdir) else LDFLAGS = -L$(top_builddir)/src/port endif LDFLAGS += -Wl,--allow-multiple-definition -Wl,--as-needed LDFLAGS_EX = # LDFLAGS_SL might have already been assigned by calling makefile LDFLAGS_SL += LDREL = -r LDOUT = -o ifeq "$(CC)" "x86_64-w64-mingw32-gcc" RANLIB = x86_64-w64-mingw32-ranlib WINDRES = x86_64-w64-mingw32-windres else RANLIB = ranlib WINDRES = windres -F pe-x86-64 endif X = .exe # Perl ifneq (/bin/perl,) # quoted to protect pathname with spaces PERL = '/bin/perl' else PERL = $(missing) perl endif perl_archlibexp = perl_privlibexp = perl_useshrplib = perl_embed_ldflags = # Miscellaneous AWK = gawk LN_S = cp -p MSGFMT = MSGMERGE = PYTHON = TAR = /bin/tar XGETTEXT = GZIP = gzip BZIP2 = bzip2 # Installation. INSTALL = $(SHELL) $(top_srcdir)/config/install-sh -c INSTALL_SCRIPT_MODE = 755 INSTALL_DATA_MODE = 644 INSTALL_PROGRAM = $(INSTALL_PROGRAM_ENV) $(INSTALL) $(INSTALL_STRIP_FLAG) INSTALL_SCRIPT = $(INSTALL) -m $(INSTALL_SCRIPT_MODE) INSTALL_DATA = $(INSTALL) -m $(INSTALL_DATA_MODE) INSTALL_STLIB = $(INSTALL_STLIB_ENV) $(INSTALL_DATA) $(INSTALL_STRIP_FLAG) INSTALL_SHLIB = $(INSTALL_SHLIB_ENV) $(INSTALL) $(INSTALL_SHLIB_OPTS) $(INSTALL_STRIP_FLAG) # Override in Makefile.port if necessary INSTALL_SHLIB_OPTS = -m 755 MKDIR_P = /bin/mkdir -p missing = $(SHELL) $(top_srcdir)/config/missing ifeq "$(CC)" "x86_64-w64-mingw32-gcc" STRIP = x86_64-w64-mingw32-strip STRIP_STATIC_LIB = x86_64-w64-mingw32-strip -x STRIP_SHARED_LIB = x86_64-w64-mingw32-strip --strip-unneeded else STRIP = strip STRIP_STATIC_LIB = strip -x STRIP_SHARED_LIB = strip --strip-unneeded endif # Documentation have_docbook = no COLLATEINDEX = DOCBOOKSTYLE = JADE = NSGMLS = OSX = XSLTPROC = # Code coverage GCOV = LCOV = GENHTML = ifeq ($(enable_coverage),yes) # ccache loses .gcno files export CCACHE_DISABLE = 1 endif # Feature settings DEF_PGPORT = 5432 WANTED_LANGUAGES = ########################################################################## # # Additional platform-specific settings # # Name of the "template" PORTNAME= win32 build_os = mingw32 host_tuple = x86_64-w64-mingw32 host_os = mingw32 host_cpu = x86_64 # Make HAVE_IPV6 available for initdb script creation HAVE_IPV6= yes # The HP-UX port makefile, for one, needs access to this symbol HAVE_POSIX_SIGNALS= # This is mainly for use on FreeBSD, where we have both a.out and elf # systems now. May be applicable to other systems to? ELF_SYSTEM= # Backend stack size limit has to be hard-wired on Windows (it's in bytes) WIN32_STACK_RLIMIT=4194304 # Set if we have a working win32 crashdump header have_win32_dbghelp = yes # Pull in platform-specific magic include Makefile.port # Set up rpath if enabled. By default it will point to our libdir, # but individual Makefiles can force other rpath paths if needed. rpathdir = $(libdir) ifeq ($(enable_rpath), yes) LDFLAGS += $(rpath) endif ########################################################################## # # Some variables needed to find some client interfaces ifdef PGXS # some contribs assumes headers and libs are in the source tree... libpq_srcdir = $(includedir) libpq_builddir = $(libdir) else libpq_srcdir = $(top_srcdir)/src/interfaces/libpq libpq_builddir = $(top_builddir)/src/interfaces/libpq endif # This macro is for use by libraries linking to libpq. (Because libpgport # isn't created with the same link flags as libpq, it can't be used.) libpq = -L$(libpq_builddir) -lpq # If doing static linking, shared library dependency info isn't available, # so add in the libraries that libpq depends on. ifeq ($(enable_shared), no) libpq += $(filter -lintl -lssl -lcrypto -lkrb5 -lcrypt, $(LIBS)) \ $(LDAP_LIBS_FE) $(PTHREAD_LIBS) endif # This macro is for use by client executables (not libraries) that use libpq. # We force clients to pull symbols from the non-shared library libpgport # rather than pulling some libpgport symbols from libpq just because # libpq uses those functions too. This makes applications less # dependent on changes in libpq's usage of pgport. To do this we link to # pgport before libpq. This does cause duplicate -lpgport's to appear # on client link lines. ifdef PGXS libpq_pgport = -L$(libdir) -lpgport $(libpq) else libpq_pgport = -L$(top_builddir)/src/port -lpgport $(libpq) endif submake-libpq: $(MAKE) -C $(libpq_builddir) all submake-libpgport: $(MAKE) -C $(top_builddir)/src/port all .PHONY: submake-libpq submake-libpgport ########################################################################## # # Testing support PL_TESTDB = pl_regression CONTRIB_TESTDB = contrib_regression ifdef NO_LOCALE NOLOCALE += --no-locale endif pg_regress_locale_flags = $(if $(ENCODING),--encoding=$(ENCODING)) $(NOLOCALE) pg_regress_check = $(top_builddir)/src/test/regress/pg_regress --inputdir=$(srcdir) --temp-install=./tmp_check --top-builddir=$(top_builddir) $(pg_regress_locale_flags) pg_regress_installcheck = $(top_builddir)/src/test/regress/pg_regress --inputdir=$(srcdir) --psqldir='$(PSQLDIR)' $(pg_regress_locale_flags) pg_regress_clean_files = results/ regression.diffs regression.out tmp_check/ log/ ########################################################################## # # Customization # # This includes your local customizations if Makefile.custom exists # in the source directory. This file doesn't exist in the original # distribution so that it doesn't get overwritten when you upgrade. # # NOTE: Makefile.custom is from the pre-Autoconf days of PostgreSQL. # You are liable to shoot yourself in the foot if you use it without # knowing exactly what you're doing. The preferred (and more # reliable) method is to communicate what you want to do to the # configure script, and leave the makefiles alone. -include $(top_srcdir)/src/Makefile.custom ifneq ($(CUSTOM_INSTALL),) INSTALL= $(CUSTOM_INSTALL) endif ifneq ($(CUSTOM_CC),) CC= $(CUSTOM_CC) endif ifneq ($(CUSTOM_COPT),) COPT= $(CUSTOM_COPT) endif ifdef COPT CFLAGS += $(COPT) LDFLAGS += $(COPT) endif ifdef PROFILE CFLAGS += $(PROFILE) LDFLAGS += $(PROFILE) endif ########################################################################## # # substitute implementations of C library routines (see src/port/) # note we already included -L.../src/port in LDFLAGS above LIBOBJS = ${LIBOBJDIR}fseeko$U.o ${LIBOBJDIR}crypt$U.o ${LIBOBJDIR}erand48$U.o ${LIBOBJDIR}getrusage$U.o ${LIBOBJDIR}inet_aton$U.o ${LIBOBJDIR}random$U.o ${LIBOBJDIR}srandom$U.o ${LIBOBJDIR}strlcat$U.o ${LIBOBJDIR}strlcpy$U.o ${LIBOBJDIR}getaddrinfo$U.o ${LIBOBJDIR}getopt$U.o ${LIBOBJDIR}getopt_long$U.o ${LIBOBJDIR}kill$U.o ${LIBOBJDIR}open$U.o ${LIBOBJDIR}win32env$U.o ${LIBOBJDIR}win32error$U.o ${LIBOBJDIR}win32setlocale$U.o ${LIBOBJDIR}snprintf$U.o LIBS := -lpgport $(LIBS) # to make ws2_32.lib the last library, and always link with shfolder, # so SHGetFolderName isn't picked up from shell32.dll ifeq ($(PORTNAME),win32) LIBS += -lws2_32 -lshfolder endif # Not really standard libc functions, used by the backend. TAS = ########################################################################## # # Global targets and rules %.i: %.c $(CPP) $(CPPFLAGS) -o $@ $< %.gz: % $(GZIP) --best -c $< >$@ %.bz2: % $(BZIP2) -c $< >$@ ifndef PGXS # Remake Makefile.global from Makefile.global.in if the latter # changed. In order to trigger this rule, the including file must # write `include $(top_builddir)/src/Makefile.global', not some # shortcut thereof. $(top_builddir)/src/Makefile.global: $(top_srcdir)/src/Makefile.global.in $(top_builddir)/config.status cd $(top_builddir) && ./config.status src/Makefile.global # Remake pg_config.h from pg_config.h.in if the latter changed. # config.status will not change the timestamp on pg_config.h if it # doesn't change, so as to avoid recompiling the entire tree # unnecessarily. Therefore we make config.status update a timestamp file # stamp-h everytime it runs, so that we don't trigger this rule everytime. # (We do trigger the null rule for stamp-h to pg_config.h everytime; so it's # important for that rule to be null!) # # Of course you need to turn on dependency tracking to get any # dependencies on pg_config.h. $(top_builddir)/src/include/pg_config.h: $(top_builddir)/src/include/stamp-h $(top_builddir)/src/include/stamp-h: $(top_srcdir)/src/include/pg_config.h.in $(top_builddir)/config.status cd $(top_builddir) && ./config.status src/include/pg_config.h # Also remake ecpg_config.h from ecpg_config.h.in if the latter changed, same # logic as above. $(top_builddir)/src/interfaces/ecpg/include/ecpg_config.h: $(top_builddir)/src/interfaces/ecpg/include/stamp-h $(top_builddir)/src/interfaces/ecpg/include/stamp-h: $(top_builddir)/src/interfaces/ecpg/include/ecpg_config.h.in $(top_builddir)/config.status cd $(top_builddir) && ./config.status src/interfaces/ecpg/include/ecpg_config.h # When configure changes, rerun configure with the same options as # last time. To change configure, you need to run autoconf manually. $(top_builddir)/config.status: $(top_srcdir)/configure cd $(top_builddir) && ./config.status --recheck endif # not PGXS install-strip: @$(MAKE) INSTALL_PROGRAM_ENV="STRIPPROG='$(STRIP)'" \ INSTALL_STLIB_ENV="STRIPPROG='$(STRIP_STATIC_LIB)'" \ INSTALL_SHLIB_ENV="STRIPPROG='$(STRIP_SHARED_LIB)'" \ INSTALL_STRIP_FLAG=-s \ install ########################################################################## # # Automatic dependency generation # ------------------------------- # When we configure with --enable-depend then we override the default # compilation rule with the magic below. While or after creating the # actual output file we also create a dependency list for the .c file. # Next time we invoke make we will have top-notch information about # whether this file needs to be updated. The dependency files are kept # in the .deps subdirectory of each directory. autodepend = ifeq ($(autodepend), yes) ifndef COMPILE.c COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) -c endif DEPDIR = .deps ifeq ($(GCC), yes) # GCC allows us to create object and dependency file in one invocation. %.o : %.c @if test ! -d $(DEPDIR); then mkdir -p $(DEPDIR); fi $(COMPILE.c) -o $@ $< -MMD -MP -MF $(DEPDIR)/$(*F).Po endif # GCC # Include all the dependency files generated for the current # directory. List /dev/null as dummy because if the wildcard expands # to nothing then make would complain. -include $(wildcard $(DEPDIR)/*.Po) /dev/null # hook for clean-up clean distclean maintainer-clean: clean-deps .PHONY: clean-deps clean-deps: @rm -rf $(DEPDIR) # When in automatic dependency mode, never delete any intermediate # files automatically. Otherwise, the following could happen: When # starting from a clean source tree, the first build would delete the # intermediate file, but also create the dependency file, which # mentions the intermediate file, thus making it non-intermediate. # The second build will then need to rebuild the now non-intermediate # missing file. So the second build will do work even though nothing # had changed. One place where this happens is the .c -> .o -> .so # chain for some contrib modules. .SECONDARY: endif # autodepend ########################################################################## # # Native language support ifeq ($(enable_nls), yes) ifneq (,$(wildcard $(srcdir)/nls.mk)) include $(top_srcdir)/src/nls-global.mk endif # nls.mk endif # enable_nls ########################################################################## # # Coverage # Explanation of involved files: # foo.c source file # foo.o object file # foo.gcno gcov graph (a.k.a. "notes") file, created at compile time # (by gcc -ftest-coverage) # foo.gcda gcov data file, created when the program is run (for # programs compiled with gcc -fprofile-arcs) # foo.c.gcov gcov output file with coverage information, created by # gcov from foo.gcda (by "make coverage") # foo.c.gcov.out stdout captured when foo.c.gcov is created, mildly # interesting # lcov.info lcov tracefile, built from gcda files in one directory, # later collected by "make coverage-html" ifeq ($(enable_coverage), yes) # There is a strange interaction between lcov and existing .gcov # output files. Hence the rm command and the ordering dependency. gcda_files := $(wildcard *.gcda) lcov.info: $(gcda_files) rm -f *.gcov $(if $^,$(LCOV) -d . -c -o $@ $(LCOVFLAGS)) %.c.gcov: %.gcda | lcov.info $(GCOV) -b -f -p -o . $(GCOVFLAGS) $*.c >$*.c.gcov.out coverage: $(gcda_files:.gcda=.c.gcov) lcov.info .PHONY: coverage-html coverage-html: coverage rm -rf coverage mkdir coverage $(GENHTML) --show-details --legend --output-directory=coverage --title=PostgreSQL --num-spaces=4 --prefix=$(abs_top_srcdir) `find . -name lcov.info -print` # hook for clean-up clean distclean maintainer-clean: clean-coverage .PHONY: clean-coverage clean-coverage: rm -rf coverage rm -f *.gcda *.gcno lcov.info *.gcov *.gcov.out # User-callable target to reset counts between test runs coverage-clean: rm -f `find . -name '*.gcda' -print` endif # enable_coverage RPostgreSQL/src/libpq/fe-exec.c0000644000176000001440000024566712124517222016027 0ustar ripleyusers/*------------------------------------------------------------------------- * * fe-exec.c * functions related to sending a query down to the backend * * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * src/interfaces/libpq/fe-exec.c * *------------------------------------------------------------------------- */ #include "postgres_fe.h" #include #include #include "libpq-fe.h" #include "libpq-int.h" #include "mb/pg_wchar.h" #ifdef WIN32 #include "win32.h" #else #include #endif /* keep this in same order as ExecStatusType in libpq-fe.h */ char *const pgresStatus[] = { "PGRES_EMPTY_QUERY", "PGRES_COMMAND_OK", "PGRES_TUPLES_OK", "PGRES_COPY_OUT", "PGRES_COPY_IN", "PGRES_BAD_RESPONSE", "PGRES_NONFATAL_ERROR", "PGRES_FATAL_ERROR", "PGRES_COPY_BOTH" }; /* * static state needed by PQescapeString and PQescapeBytea; initialize to * values that result in backward-compatible behavior */ static int static_client_encoding = PG_SQL_ASCII; static bool static_std_strings = false; static PGEvent *dupEvents(PGEvent *events, int count); static bool PQsendQueryStart(PGconn *conn); static int PQsendQueryGuts(PGconn *conn, const char *command, const char *stmtName, int nParams, const Oid *paramTypes, const char *const * paramValues, const int *paramLengths, const int *paramFormats, int resultFormat); static void parseInput(PGconn *conn); static bool PQexecStart(PGconn *conn); static PGresult *PQexecFinish(PGconn *conn); static int PQsendDescribe(PGconn *conn, char desc_type, const char *desc_target); static int check_field_number(const PGresult *res, int field_num); /* ---------------- * Space management for PGresult. * * Formerly, libpq did a separate malloc() for each field of each tuple * returned by a query. This was remarkably expensive --- malloc/free * consumed a sizable part of the application's runtime. And there is * no real need to keep track of the fields separately, since they will * all be freed together when the PGresult is released. So now, we grab * large blocks of storage from malloc and allocate space for query data * within these blocks, using a trivially simple allocator. This reduces * the number of malloc/free calls dramatically, and it also avoids * fragmentation of the malloc storage arena. * The PGresult structure itself is still malloc'd separately. We could * combine it with the first allocation block, but that would waste space * for the common case that no extra storage is actually needed (that is, * the SQL command did not return tuples). * * We also malloc the top-level array of tuple pointers separately, because * we need to be able to enlarge it via realloc, and our trivial space * allocator doesn't handle that effectively. (Too bad the FE/BE protocol * doesn't tell us up front how many tuples will be returned.) * All other subsidiary storage for a PGresult is kept in PGresult_data blocks * of size PGRESULT_DATA_BLOCKSIZE. The overhead at the start of each block * is just a link to the next one, if any. Free-space management info is * kept in the owning PGresult. * A query returning a small amount of data will thus require three malloc * calls: one for the PGresult, one for the tuples pointer array, and one * PGresult_data block. * * Only the most recently allocated PGresult_data block is a candidate to * have more stuff added to it --- any extra space left over in older blocks * is wasted. We could be smarter and search the whole chain, but the point * here is to be simple and fast. Typical applications do not keep a PGresult * around very long anyway, so some wasted space within one is not a problem. * * Tuning constants for the space allocator are: * PGRESULT_DATA_BLOCKSIZE: size of a standard allocation block, in bytes * PGRESULT_ALIGN_BOUNDARY: assumed alignment requirement for binary data * PGRESULT_SEP_ALLOC_THRESHOLD: objects bigger than this are given separate * blocks, instead of being crammed into a regular allocation block. * Requirements for correct function are: * PGRESULT_ALIGN_BOUNDARY must be a multiple of the alignment requirements * of all machine data types. (Currently this is set from configure * tests, so it should be OK automatically.) * PGRESULT_SEP_ALLOC_THRESHOLD + PGRESULT_BLOCK_OVERHEAD <= * PGRESULT_DATA_BLOCKSIZE * pqResultAlloc assumes an object smaller than the threshold will fit * in a new block. * The amount of space wasted at the end of a block could be as much as * PGRESULT_SEP_ALLOC_THRESHOLD, so it doesn't pay to make that too large. * ---------------- */ #define PGRESULT_DATA_BLOCKSIZE 2048 #define PGRESULT_ALIGN_BOUNDARY MAXIMUM_ALIGNOF /* from configure */ #define PGRESULT_BLOCK_OVERHEAD Max(sizeof(PGresult_data), PGRESULT_ALIGN_BOUNDARY) #define PGRESULT_SEP_ALLOC_THRESHOLD (PGRESULT_DATA_BLOCKSIZE / 2) /* * PQmakeEmptyPGresult * returns a newly allocated, initialized PGresult with given status. * If conn is not NULL and status indicates an error, the conn's * errorMessage is copied. Also, any PGEvents are copied from the conn. */ PGresult * PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status) { PGresult *result; result = (PGresult *) malloc(sizeof(PGresult)); if (!result) return NULL; result->ntups = 0; result->numAttributes = 0; result->attDescs = NULL; result->tuples = NULL; result->tupArrSize = 0; result->numParameters = 0; result->paramDescs = NULL; result->resultStatus = status; result->cmdStatus[0] = '\0'; result->binary = 0; result->events = NULL; result->nEvents = 0; result->errMsg = NULL; result->errFields = NULL; result->null_field[0] = '\0'; result->curBlock = NULL; result->curOffset = 0; result->spaceLeft = 0; if (conn) { /* copy connection data we might need for operations on PGresult */ result->noticeHooks = conn->noticeHooks; result->client_encoding = conn->client_encoding; /* consider copying conn's errorMessage */ switch (status) { case PGRES_EMPTY_QUERY: case PGRES_COMMAND_OK: case PGRES_TUPLES_OK: case PGRES_COPY_OUT: case PGRES_COPY_IN: case PGRES_COPY_BOTH: /* non-error cases */ break; default: pqSetResultError(result, conn->errorMessage.data); break; } /* copy events last; result must be valid if we need to PQclear */ if (conn->nEvents > 0) { result->events = dupEvents(conn->events, conn->nEvents); if (!result->events) { PQclear(result); return NULL; } result->nEvents = conn->nEvents; } } else { /* defaults... */ result->noticeHooks.noticeRec = NULL; result->noticeHooks.noticeRecArg = NULL; result->noticeHooks.noticeProc = NULL; result->noticeHooks.noticeProcArg = NULL; result->client_encoding = PG_SQL_ASCII; } return result; } /* * PQsetResultAttrs * * Set the attributes for a given result. This function fails if there are * already attributes contained in the provided result. The call is * ignored if numAttributes is is zero or attDescs is NULL. If the * function fails, it returns zero. If the function succeeds, it * returns a non-zero value. */ int PQsetResultAttrs(PGresult *res, int numAttributes, PGresAttDesc *attDescs) { int i; /* If attrs already exist, they cannot be overwritten. */ if (!res || res->numAttributes > 0) return FALSE; /* ignore no-op request */ if (numAttributes <= 0 || !attDescs) return TRUE; res->attDescs = (PGresAttDesc *) PQresultAlloc(res, numAttributes * sizeof(PGresAttDesc)); if (!res->attDescs) return FALSE; res->numAttributes = numAttributes; memcpy(res->attDescs, attDescs, numAttributes * sizeof(PGresAttDesc)); /* deep-copy the attribute names, and determine format */ res->binary = 1; for (i = 0; i < res->numAttributes; i++) { if (res->attDescs[i].name) res->attDescs[i].name = pqResultStrdup(res, res->attDescs[i].name); else res->attDescs[i].name = res->null_field; if (!res->attDescs[i].name) return FALSE; if (res->attDescs[i].format == 0) res->binary = 0; } return TRUE; } /* * PQcopyResult * * Returns a deep copy of the provided 'src' PGresult, which cannot be NULL. * The 'flags' argument controls which portions of the result will or will * NOT be copied. The created result is always put into the * PGRES_TUPLES_OK status. The source result error message is not copied, * although cmdStatus is. * * To set custom attributes, use PQsetResultAttrs. That function requires * that there are no attrs contained in the result, so to use that * function you cannot use the PG_COPYRES_ATTRS or PG_COPYRES_TUPLES * options with this function. * * Options: * PG_COPYRES_ATTRS - Copy the source result's attributes * * PG_COPYRES_TUPLES - Copy the source result's tuples. This implies * copying the attrs, seeeing how the attrs are needed by the tuples. * * PG_COPYRES_EVENTS - Copy the source result's events. * * PG_COPYRES_NOTICEHOOKS - Copy the source result's notice hooks. */ PGresult * PQcopyResult(const PGresult *src, int flags) { PGresult *dest; int i; if (!src) return NULL; dest = PQmakeEmptyPGresult(NULL, PGRES_TUPLES_OK); if (!dest) return NULL; /* Always copy these over. Is cmdStatus really useful here? */ dest->client_encoding = src->client_encoding; strcpy(dest->cmdStatus, src->cmdStatus); /* Wants attrs? */ if (flags & (PG_COPYRES_ATTRS | PG_COPYRES_TUPLES)) { if (!PQsetResultAttrs(dest, src->numAttributes, src->attDescs)) { PQclear(dest); return NULL; } } /* Wants to copy tuples? */ if (flags & PG_COPYRES_TUPLES) { int tup, field; for (tup = 0; tup < src->ntups; tup++) { for (field = 0; field < src->numAttributes; field++) { if (!PQsetvalue(dest, tup, field, src->tuples[tup][field].value, src->tuples[tup][field].len)) { PQclear(dest); return NULL; } } } } /* Wants to copy notice hooks? */ if (flags & PG_COPYRES_NOTICEHOOKS) dest->noticeHooks = src->noticeHooks; /* Wants to copy PGEvents? */ if ((flags & PG_COPYRES_EVENTS) && src->nEvents > 0) { dest->events = dupEvents(src->events, src->nEvents); if (!dest->events) { PQclear(dest); return NULL; } dest->nEvents = src->nEvents; } /* Okay, trigger PGEVT_RESULTCOPY event */ for (i = 0; i < dest->nEvents; i++) { if (src->events[i].resultInitialized) { PGEventResultCopy evt; evt.src = src; evt.dest = dest; if (!dest->events[i].proc(PGEVT_RESULTCOPY, &evt, dest->events[i].passThrough)) { PQclear(dest); return NULL; } dest->events[i].resultInitialized = TRUE; } } return dest; } /* * Copy an array of PGEvents (with no extra space for more). * Does not duplicate the event instance data, sets this to NULL. * Also, the resultInitialized flags are all cleared. */ static PGEvent * dupEvents(PGEvent *events, int count) { PGEvent *newEvents; int i; if (!events || count <= 0) return NULL; newEvents = (PGEvent *) malloc(count * sizeof(PGEvent)); if (!newEvents) return NULL; for (i = 0; i < count; i++) { newEvents[i].proc = events[i].proc; newEvents[i].passThrough = events[i].passThrough; newEvents[i].data = NULL; newEvents[i].resultInitialized = FALSE; newEvents[i].name = strdup(events[i].name); if (!newEvents[i].name) { while (--i >= 0) free(newEvents[i].name); free(newEvents); return NULL; } } return newEvents; } /* * Sets the value for a tuple field. The tup_num must be less than or * equal to PQntuples(res). If it is equal, a new tuple is created and * added to the result. * Returns a non-zero value for success and zero for failure. */ int PQsetvalue(PGresult *res, int tup_num, int field_num, char *value, int len) { PGresAttValue *attval; if (!check_field_number(res, field_num)) return FALSE; /* Invalid tup_num, must be <= ntups */ if (tup_num < 0 || tup_num > res->ntups) return FALSE; /* need to allocate a new tuple? */ if (tup_num == res->ntups) { PGresAttValue *tup; int i; tup = (PGresAttValue *) pqResultAlloc(res, res->numAttributes * sizeof(PGresAttValue), TRUE); if (!tup) return FALSE; /* initialize each column to NULL */ for (i = 0; i < res->numAttributes; i++) { tup[i].len = NULL_LEN; tup[i].value = res->null_field; } /* add it to the array */ if (!pqAddTuple(res, tup)) return FALSE; } attval = &res->tuples[tup_num][field_num]; /* treat either NULL_LEN or NULL value pointer as a NULL field */ if (len == NULL_LEN || value == NULL) { attval->len = NULL_LEN; attval->value = res->null_field; } else if (len <= 0) { attval->len = 0; attval->value = res->null_field; } else { attval->value = (char *) pqResultAlloc(res, len + 1, TRUE); if (!attval->value) return FALSE; attval->len = len; memcpy(attval->value, value, len); attval->value[len] = '\0'; } return TRUE; } /* * pqResultAlloc - exported routine to allocate local storage in a PGresult. * * We force all such allocations to be maxaligned, since we don't know * whether the value might be binary. */ void * PQresultAlloc(PGresult *res, size_t nBytes) { return pqResultAlloc(res, nBytes, TRUE); } /* * pqResultAlloc - * Allocate subsidiary storage for a PGresult. * * nBytes is the amount of space needed for the object. * If isBinary is true, we assume that we need to align the object on * a machine allocation boundary. * If isBinary is false, we assume the object is a char string and can * be allocated on any byte boundary. */ void * pqResultAlloc(PGresult *res, size_t nBytes, bool isBinary) { char *space; PGresult_data *block; if (!res) return NULL; if (nBytes <= 0) return res->null_field; /* * If alignment is needed, round up the current position to an alignment * boundary. */ if (isBinary) { int offset = res->curOffset % PGRESULT_ALIGN_BOUNDARY; if (offset) { res->curOffset += PGRESULT_ALIGN_BOUNDARY - offset; res->spaceLeft -= PGRESULT_ALIGN_BOUNDARY - offset; } } /* If there's enough space in the current block, no problem. */ if (nBytes <= (size_t) res->spaceLeft) { space = res->curBlock->space + res->curOffset; res->curOffset += nBytes; res->spaceLeft -= nBytes; return space; } /* * If the requested object is very large, give it its own block; this * avoids wasting what might be most of the current block to start a new * block. (We'd have to special-case requests bigger than the block size * anyway.) The object is always given binary alignment in this case. */ if (nBytes >= PGRESULT_SEP_ALLOC_THRESHOLD) { block = (PGresult_data *) malloc(nBytes + PGRESULT_BLOCK_OVERHEAD); if (!block) return NULL; space = block->space + PGRESULT_BLOCK_OVERHEAD; if (res->curBlock) { /* * Tuck special block below the active block, so that we don't * have to waste the free space in the active block. */ block->next = res->curBlock->next; res->curBlock->next = block; } else { /* Must set up the new block as the first active block. */ block->next = NULL; res->curBlock = block; res->spaceLeft = 0; /* be sure it's marked full */ } return space; } /* Otherwise, start a new block. */ block = (PGresult_data *) malloc(PGRESULT_DATA_BLOCKSIZE); if (!block) return NULL; block->next = res->curBlock; res->curBlock = block; if (isBinary) { /* object needs full alignment */ res->curOffset = PGRESULT_BLOCK_OVERHEAD; res->spaceLeft = PGRESULT_DATA_BLOCKSIZE - PGRESULT_BLOCK_OVERHEAD; } else { /* we can cram it right after the overhead pointer */ res->curOffset = sizeof(PGresult_data); res->spaceLeft = PGRESULT_DATA_BLOCKSIZE - sizeof(PGresult_data); } space = block->space + res->curOffset; res->curOffset += nBytes; res->spaceLeft -= nBytes; return space; } /* * pqResultStrdup - * Like strdup, but the space is subsidiary PGresult space. */ char * pqResultStrdup(PGresult *res, const char *str) { char *space = (char *) pqResultAlloc(res, strlen(str) + 1, FALSE); if (space) strcpy(space, str); return space; } /* * pqSetResultError - * assign a new error message to a PGresult */ void pqSetResultError(PGresult *res, const char *msg) { if (!res) return; if (msg && *msg) res->errMsg = pqResultStrdup(res, msg); else res->errMsg = NULL; } /* * pqCatenateResultError - * concatenate a new error message to the one already in a PGresult */ void pqCatenateResultError(PGresult *res, const char *msg) { PQExpBufferData errorBuf; if (!res || !msg) return; initPQExpBuffer(&errorBuf); if (res->errMsg) appendPQExpBufferStr(&errorBuf, res->errMsg); appendPQExpBufferStr(&errorBuf, msg); pqSetResultError(res, errorBuf.data); termPQExpBuffer(&errorBuf); } /* * PQclear - * free's the memory associated with a PGresult */ void PQclear(PGresult *res) { PGresult_data *block; int i; if (!res) return; for (i = 0; i < res->nEvents; i++) { /* only send DESTROY to successfully-initialized event procs */ if (res->events[i].resultInitialized) { PGEventResultDestroy evt; evt.result = res; (void) res->events[i].proc(PGEVT_RESULTDESTROY, &evt, res->events[i].passThrough); } free(res->events[i].name); } if (res->events) free(res->events); /* Free all the subsidiary blocks */ while ((block = res->curBlock) != NULL) { res->curBlock = block->next; free(block); } /* Free the top-level tuple pointer array */ if (res->tuples) free(res->tuples); /* zero out the pointer fields to catch programming errors */ res->attDescs = NULL; res->tuples = NULL; res->paramDescs = NULL; res->errFields = NULL; res->events = NULL; res->nEvents = 0; /* res->curBlock was zeroed out earlier */ /* Free the PGresult structure itself */ free(res); } /* * Handy subroutine to deallocate any partially constructed async result. */ void pqClearAsyncResult(PGconn *conn) { if (conn->result) PQclear(conn->result); conn->result = NULL; conn->curTuple = NULL; } /* * This subroutine deletes any existing async result, sets conn->result * to a PGresult with status PGRES_FATAL_ERROR, and stores the current * contents of conn->errorMessage into that result. It differs from a * plain call on PQmakeEmptyPGresult() in that if there is already an * async result with status PGRES_FATAL_ERROR, the current error message * is APPENDED to the old error message instead of replacing it. This * behavior lets us report multiple error conditions properly, if necessary. * (An example where this is needed is when the backend sends an 'E' message * and immediately closes the connection --- we want to report both the * backend error and the connection closure error.) */ void pqSaveErrorResult(PGconn *conn) { /* * If no old async result, just let PQmakeEmptyPGresult make one. Likewise * if old result is not an error message. */ if (conn->result == NULL || conn->result->resultStatus != PGRES_FATAL_ERROR || conn->result->errMsg == NULL) { pqClearAsyncResult(conn); conn->result = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR); } else { /* Else, concatenate error message to existing async result. */ pqCatenateResultError(conn->result, conn->errorMessage.data); } } /* * This subroutine prepares an async result object for return to the caller. * If there is not already an async result object, build an error object * using whatever is in conn->errorMessage. In any case, clear the async * result storage and make sure PQerrorMessage will agree with the result's * error string. */ PGresult * pqPrepareAsyncResult(PGconn *conn) { PGresult *res; /* * conn->result is the PGresult to return. If it is NULL (which probably * shouldn't happen) we assume there is an appropriate error message in * conn->errorMessage. */ res = conn->result; conn->result = NULL; /* handing over ownership to caller */ conn->curTuple = NULL; /* just in case */ if (!res) res = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR); else { /* * Make sure PQerrorMessage agrees with result; it could be different * if we have concatenated messages. */ resetPQExpBuffer(&conn->errorMessage); appendPQExpBufferStr(&conn->errorMessage, PQresultErrorMessage(res)); } return res; } /* * pqInternalNotice - produce an internally-generated notice message * * A format string and optional arguments can be passed. Note that we do * libpq_gettext() here, so callers need not. * * The supplied text is taken as primary message (ie., it should not include * a trailing newline, and should not be more than one line). */ void pqInternalNotice(const PGNoticeHooks *hooks, const char *fmt,...) { char msgBuf[1024]; va_list args; PGresult *res; if (hooks->noticeRec == NULL) return; /* nobody home to receive notice? */ /* Format the message */ va_start(args, fmt); vsnprintf(msgBuf, sizeof(msgBuf), libpq_gettext(fmt), args); va_end(args); msgBuf[sizeof(msgBuf) - 1] = '\0'; /* make real sure it's terminated */ /* Make a PGresult to pass to the notice receiver */ res = PQmakeEmptyPGresult(NULL, PGRES_NONFATAL_ERROR); if (!res) return; res->noticeHooks = *hooks; /* * Set up fields of notice. */ pqSaveMessageField(res, PG_DIAG_MESSAGE_PRIMARY, msgBuf); pqSaveMessageField(res, PG_DIAG_SEVERITY, libpq_gettext("NOTICE")); /* XXX should provide a SQLSTATE too? */ /* * Result text is always just the primary message + newline. If we can't * allocate it, don't bother invoking the receiver. */ res->errMsg = (char *) pqResultAlloc(res, strlen(msgBuf) + 2, FALSE); if (res->errMsg) { sprintf(res->errMsg, "%s\n", msgBuf); /* * Pass to receiver, then free it. */ (*res->noticeHooks.noticeRec) (res->noticeHooks.noticeRecArg, res); } PQclear(res); } /* * pqAddTuple * add a row pointer to the PGresult structure, growing it if necessary * Returns TRUE if OK, FALSE if not enough memory to add the row */ int pqAddTuple(PGresult *res, PGresAttValue *tup) { if (res->ntups >= res->tupArrSize) { /* * Try to grow the array. * * We can use realloc because shallow copying of the structure is * okay. Note that the first time through, res->tuples is NULL. While * ANSI says that realloc() should act like malloc() in that case, * some old C libraries (like SunOS 4.1.x) coredump instead. On * failure realloc is supposed to return NULL without damaging the * existing allocation. Note that the positions beyond res->ntups are * garbage, not necessarily NULL. */ int newSize = (res->tupArrSize > 0) ? res->tupArrSize * 2 : 128; PGresAttValue **newTuples; if (res->tuples == NULL) newTuples = (PGresAttValue **) malloc(newSize * sizeof(PGresAttValue *)); else newTuples = (PGresAttValue **) realloc(res->tuples, newSize * sizeof(PGresAttValue *)); if (!newTuples) return FALSE; /* malloc or realloc failed */ res->tupArrSize = newSize; res->tuples = newTuples; } res->tuples[res->ntups] = tup; res->ntups++; return TRUE; } /* * pqSaveMessageField - save one field of an error or notice message */ void pqSaveMessageField(PGresult *res, char code, const char *value) { PGMessageField *pfield; pfield = (PGMessageField *) pqResultAlloc(res, sizeof(PGMessageField) + strlen(value), TRUE); if (!pfield) return; /* out of memory? */ pfield->code = code; strcpy(pfield->contents, value); pfield->next = res->errFields; res->errFields = pfield; } /* * pqSaveParameterStatus - remember parameter status sent by backend */ void pqSaveParameterStatus(PGconn *conn, const char *name, const char *value) { pgParameterStatus *pstatus; pgParameterStatus *prev; if (conn->Pfdebug) fprintf(conn->Pfdebug, "pqSaveParameterStatus: '%s' = '%s'\n", name, value); /* * Forget any old information about the parameter */ for (pstatus = conn->pstatus, prev = NULL; pstatus != NULL; prev = pstatus, pstatus = pstatus->next) { if (strcmp(pstatus->name, name) == 0) { if (prev) prev->next = pstatus->next; else conn->pstatus = pstatus->next; free(pstatus); /* frees name and value strings too */ break; } } /* * Store new info as a single malloc block */ pstatus = (pgParameterStatus *) malloc(sizeof(pgParameterStatus) + strlen(name) +strlen(value) + 2); if (pstatus) { char *ptr; ptr = ((char *) pstatus) + sizeof(pgParameterStatus); pstatus->name = ptr; strcpy(ptr, name); ptr += strlen(name) + 1; pstatus->value = ptr; strcpy(ptr, value); pstatus->next = conn->pstatus; conn->pstatus = pstatus; } /* * Special hacks: remember client_encoding and * standard_conforming_strings, and convert server version to a numeric * form. We keep the first two of these in static variables as well, so * that PQescapeString and PQescapeBytea can behave somewhat sanely (at * least in single-connection-using programs). */ if (strcmp(name, "client_encoding") == 0) { conn->client_encoding = pg_char_to_encoding(value); /* if we don't recognize the encoding name, fall back to SQL_ASCII */ if (conn->client_encoding < 0) conn->client_encoding = PG_SQL_ASCII; static_client_encoding = conn->client_encoding; } else if (strcmp(name, "standard_conforming_strings") == 0) { conn->std_strings = (strcmp(value, "on") == 0); static_std_strings = conn->std_strings; } else if (strcmp(name, "server_version") == 0) { int cnt; int vmaj, vmin, vrev; cnt = sscanf(value, "%d.%d.%d", &vmaj, &vmin, &vrev); if (cnt < 2) conn->sversion = 0; /* unknown */ else { if (cnt == 2) vrev = 0; conn->sversion = (100 * vmaj + vmin) * 100 + vrev; } } } /* * PQsendQuery * Submit a query, but don't wait for it to finish * * Returns: 1 if successfully submitted * 0 if error (conn->errorMessage is set) */ int PQsendQuery(PGconn *conn, const char *query) { if (!PQsendQueryStart(conn)) return 0; if (!query) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("command string is a null pointer\n")); return 0; } /* construct the outgoing Query message */ if (pqPutMsgStart('Q', false, conn) < 0 || pqPuts(query, conn) < 0 || pqPutMsgEnd(conn) < 0) { pqHandleSendFailure(conn); return 0; } /* remember we are using simple query protocol */ conn->queryclass = PGQUERY_SIMPLE; /* and remember the query text too, if possible */ /* if insufficient memory, last_query just winds up NULL */ if (conn->last_query) free(conn->last_query); conn->last_query = strdup(query); /* * Give the data a push. In nonblock mode, don't complain if we're unable * to send it all; PQgetResult() will do any additional flushing needed. */ if (pqFlush(conn) < 0) { pqHandleSendFailure(conn); return 0; } /* OK, it's launched! */ conn->asyncStatus = PGASYNC_BUSY; return 1; } /* * PQsendQueryParams * Like PQsendQuery, but use protocol 3.0 so we can pass parameters */ int PQsendQueryParams(PGconn *conn, const char *command, int nParams, const Oid *paramTypes, const char *const * paramValues, const int *paramLengths, const int *paramFormats, int resultFormat) { if (!PQsendQueryStart(conn)) return 0; if (!command) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("command string is a null pointer\n")); return 0; } return PQsendQueryGuts(conn, command, "", /* use unnamed statement */ nParams, paramTypes, paramValues, paramLengths, paramFormats, resultFormat); } /* * PQsendPrepare * Submit a Parse message, but don't wait for it to finish * * Returns: 1 if successfully submitted * 0 if error (conn->errorMessage is set) */ int PQsendPrepare(PGconn *conn, const char *stmtName, const char *query, int nParams, const Oid *paramTypes) { if (!PQsendQueryStart(conn)) return 0; if (!stmtName) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("statement name is a null pointer\n")); return 0; } if (!query) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("command string is a null pointer\n")); return 0; } /* This isn't gonna work on a 2.0 server */ if (PG_PROTOCOL_MAJOR(conn->pversion) < 3) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("function requires at least protocol version 3.0\n")); return 0; } /* construct the Parse message */ if (pqPutMsgStart('P', false, conn) < 0 || pqPuts(stmtName, conn) < 0 || pqPuts(query, conn) < 0) goto sendFailed; if (nParams > 0 && paramTypes) { int i; if (pqPutInt(nParams, 2, conn) < 0) goto sendFailed; for (i = 0; i < nParams; i++) { if (pqPutInt(paramTypes[i], 4, conn) < 0) goto sendFailed; } } else { if (pqPutInt(0, 2, conn) < 0) goto sendFailed; } if (pqPutMsgEnd(conn) < 0) goto sendFailed; /* construct the Sync message */ if (pqPutMsgStart('S', false, conn) < 0 || pqPutMsgEnd(conn) < 0) goto sendFailed; /* remember we are doing just a Parse */ conn->queryclass = PGQUERY_PREPARE; /* and remember the query text too, if possible */ /* if insufficient memory, last_query just winds up NULL */ if (conn->last_query) free(conn->last_query); conn->last_query = strdup(query); /* * Give the data a push. In nonblock mode, don't complain if we're unable * to send it all; PQgetResult() will do any additional flushing needed. */ if (pqFlush(conn) < 0) goto sendFailed; /* OK, it's launched! */ conn->asyncStatus = PGASYNC_BUSY; return 1; sendFailed: pqHandleSendFailure(conn); return 0; } /* * PQsendQueryPrepared * Like PQsendQuery, but execute a previously prepared statement, * using protocol 3.0 so we can pass parameters */ int PQsendQueryPrepared(PGconn *conn, const char *stmtName, int nParams, const char *const * paramValues, const int *paramLengths, const int *paramFormats, int resultFormat) { if (!PQsendQueryStart(conn)) return 0; if (!stmtName) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("statement name is a null pointer\n")); return 0; } return PQsendQueryGuts(conn, NULL, /* no command to parse */ stmtName, nParams, NULL, /* no param types */ paramValues, paramLengths, paramFormats, resultFormat); } /* * Common startup code for PQsendQuery and sibling routines */ static bool PQsendQueryStart(PGconn *conn) { if (!conn) return false; /* clear the error string */ resetPQExpBuffer(&conn->errorMessage); /* Don't try to send if we know there's no live connection. */ if (conn->status != CONNECTION_OK) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("no connection to the server\n")); return false; } /* Can't send while already busy, either. */ if (conn->asyncStatus != PGASYNC_IDLE) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("another command is already in progress\n")); return false; } /* initialize async result-accumulation state */ conn->result = NULL; conn->curTuple = NULL; /* ready to send command message */ return true; } /* * PQsendQueryGuts * Common code for protocol-3.0 query sending * PQsendQueryStart should be done already * * command may be NULL to indicate we use an already-prepared statement */ static int PQsendQueryGuts(PGconn *conn, const char *command, const char *stmtName, int nParams, const Oid *paramTypes, const char *const * paramValues, const int *paramLengths, const int *paramFormats, int resultFormat) { int i; /* This isn't gonna work on a 2.0 server */ if (PG_PROTOCOL_MAJOR(conn->pversion) < 3) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("function requires at least protocol version 3.0\n")); return 0; } /* * We will send Parse (if needed), Bind, Describe Portal, Execute, Sync, * using specified statement name and the unnamed portal. */ if (command) { /* construct the Parse message */ if (pqPutMsgStart('P', false, conn) < 0 || pqPuts(stmtName, conn) < 0 || pqPuts(command, conn) < 0) goto sendFailed; if (nParams > 0 && paramTypes) { if (pqPutInt(nParams, 2, conn) < 0) goto sendFailed; for (i = 0; i < nParams; i++) { if (pqPutInt(paramTypes[i], 4, conn) < 0) goto sendFailed; } } else { if (pqPutInt(0, 2, conn) < 0) goto sendFailed; } if (pqPutMsgEnd(conn) < 0) goto sendFailed; } /* Construct the Bind message */ if (pqPutMsgStart('B', false, conn) < 0 || pqPuts("", conn) < 0 || pqPuts(stmtName, conn) < 0) goto sendFailed; /* Send parameter formats */ if (nParams > 0 && paramFormats) { if (pqPutInt(nParams, 2, conn) < 0) goto sendFailed; for (i = 0; i < nParams; i++) { if (pqPutInt(paramFormats[i], 2, conn) < 0) goto sendFailed; } } else { if (pqPutInt(0, 2, conn) < 0) goto sendFailed; } if (pqPutInt(nParams, 2, conn) < 0) goto sendFailed; /* Send parameters */ for (i = 0; i < nParams; i++) { if (paramValues && paramValues[i]) { int nbytes; if (paramFormats && paramFormats[i] != 0) { /* binary parameter */ if (paramLengths) nbytes = paramLengths[i]; else { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("length must be given for binary parameter\n")); goto sendFailed; } } else { /* text parameter, do not use paramLengths */ nbytes = strlen(paramValues[i]); } if (pqPutInt(nbytes, 4, conn) < 0 || pqPutnchar(paramValues[i], nbytes, conn) < 0) goto sendFailed; } else { /* take the param as NULL */ if (pqPutInt(-1, 4, conn) < 0) goto sendFailed; } } if (pqPutInt(1, 2, conn) < 0 || pqPutInt(resultFormat, 2, conn)) goto sendFailed; if (pqPutMsgEnd(conn) < 0) goto sendFailed; /* construct the Describe Portal message */ if (pqPutMsgStart('D', false, conn) < 0 || pqPutc('P', conn) < 0 || pqPuts("", conn) < 0 || pqPutMsgEnd(conn) < 0) goto sendFailed; /* construct the Execute message */ if (pqPutMsgStart('E', false, conn) < 0 || pqPuts("", conn) < 0 || pqPutInt(0, 4, conn) < 0 || pqPutMsgEnd(conn) < 0) goto sendFailed; /* construct the Sync message */ if (pqPutMsgStart('S', false, conn) < 0 || pqPutMsgEnd(conn) < 0) goto sendFailed; /* remember we are using extended query protocol */ conn->queryclass = PGQUERY_EXTENDED; /* and remember the query text too, if possible */ /* if insufficient memory, last_query just winds up NULL */ if (conn->last_query) free(conn->last_query); if (command) conn->last_query = strdup(command); else conn->last_query = NULL; /* * Give the data a push. In nonblock mode, don't complain if we're unable * to send it all; PQgetResult() will do any additional flushing needed. */ if (pqFlush(conn) < 0) goto sendFailed; /* OK, it's launched! */ conn->asyncStatus = PGASYNC_BUSY; return 1; sendFailed: pqHandleSendFailure(conn); return 0; } /* * pqHandleSendFailure: try to clean up after failure to send command. * * Primarily, what we want to accomplish here is to process an async * NOTICE message that the backend might have sent just before it died. * * NOTE: this routine should only be called in PGASYNC_IDLE state. */ void pqHandleSendFailure(PGconn *conn) { /* * Accept any available input data, ignoring errors. Note that if * pqReadData decides the backend has closed the channel, it will close * our side of the socket --- that's just what we want here. */ while (pqReadData(conn) > 0) /* loop until no more data readable */ ; /* * Parse any available input messages. Since we are in PGASYNC_IDLE * state, only NOTICE and NOTIFY messages will be eaten. */ parseInput(conn); } /* * Consume any available input from the backend * 0 return: some kind of trouble * 1 return: no problem */ int PQconsumeInput(PGconn *conn) { if (!conn) return 0; /* * for non-blocking connections try to flush the send-queue, otherwise we * may never get a response for something that may not have already been * sent because it's in our write buffer! */ if (pqIsnonblocking(conn)) { if (pqFlush(conn) < 0) return 0; } /* * Load more data, if available. We do this no matter what state we are * in, since we are probably getting called because the application wants * to get rid of a read-select condition. Note that we will NOT block * waiting for more input. */ if (pqReadData(conn) < 0) return 0; /* Parsing of the data waits till later. */ return 1; } /* * parseInput: if appropriate, parse input data from backend * until input is exhausted or a stopping state is reached. * Note that this function will NOT attempt to read more data from the backend. */ static void parseInput(PGconn *conn) { if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3) pqParseInput3(conn); else pqParseInput2(conn); } /* * PQisBusy * Return TRUE if PQgetResult would block waiting for input. */ int PQisBusy(PGconn *conn) { if (!conn) return FALSE; /* Parse any available data, if our state permits. */ parseInput(conn); /* PQgetResult will return immediately in all states except BUSY. */ return conn->asyncStatus == PGASYNC_BUSY; } /* * PQgetResult * Get the next PGresult produced by a query. Returns NULL if no * query work remains or an error has occurred (e.g. out of * memory). */ PGresult * PQgetResult(PGconn *conn) { PGresult *res; if (!conn) return NULL; /* Parse any available data, if our state permits. */ parseInput(conn); /* If not ready to return something, block until we are. */ while (conn->asyncStatus == PGASYNC_BUSY) { int flushResult; /* * If data remains unsent, send it. Else we might be waiting for the * result of a command the backend hasn't even got yet. */ while ((flushResult = pqFlush(conn)) > 0) { if (pqWait(FALSE, TRUE, conn)) { flushResult = -1; break; } } /* Wait for some more data, and load it. */ if (flushResult || pqWait(TRUE, FALSE, conn) || pqReadData(conn) < 0) { /* * conn->errorMessage has been set by pqWait or pqReadData. We * want to append it to any already-received error message. */ pqSaveErrorResult(conn); conn->asyncStatus = PGASYNC_IDLE; return pqPrepareAsyncResult(conn); } /* Parse it. */ parseInput(conn); } /* Return the appropriate thing. */ switch (conn->asyncStatus) { case PGASYNC_IDLE: res = NULL; /* query is complete */ break; case PGASYNC_READY: res = pqPrepareAsyncResult(conn); /* Set the state back to BUSY, allowing parsing to proceed. */ conn->asyncStatus = PGASYNC_BUSY; break; case PGASYNC_COPY_IN: if (conn->result && conn->result->resultStatus == PGRES_COPY_IN) res = pqPrepareAsyncResult(conn); else res = PQmakeEmptyPGresult(conn, PGRES_COPY_IN); break; case PGASYNC_COPY_OUT: if (conn->result && conn->result->resultStatus == PGRES_COPY_OUT) res = pqPrepareAsyncResult(conn); else res = PQmakeEmptyPGresult(conn, PGRES_COPY_OUT); break; case PGASYNC_COPY_BOTH: if (conn->result && conn->result->resultStatus == PGRES_COPY_BOTH) res = pqPrepareAsyncResult(conn); else res = PQmakeEmptyPGresult(conn, PGRES_COPY_BOTH); break; default: printfPQExpBuffer(&conn->errorMessage, libpq_gettext("unexpected asyncStatus: %d\n"), (int) conn->asyncStatus); res = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR); break; } if (res) { int i; for (i = 0; i < res->nEvents; i++) { PGEventResultCreate evt; evt.conn = conn; evt.result = res; if (!res->events[i].proc(PGEVT_RESULTCREATE, &evt, res->events[i].passThrough)) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("PGEventProc \"%s\" failed during PGEVT_RESULTCREATE event\n"), res->events[i].name); pqSetResultError(res, conn->errorMessage.data); res->resultStatus = PGRES_FATAL_ERROR; break; } res->events[i].resultInitialized = TRUE; } } return res; } /* * PQexec * send a query to the backend and package up the result in a PGresult * * If the query was not even sent, return NULL; conn->errorMessage is set to * a relevant message. * If the query was sent, a new PGresult is returned (which could indicate * either success or failure). * The user is responsible for freeing the PGresult via PQclear() * when done with it. */ PGresult * PQexec(PGconn *conn, const char *query) { if (!PQexecStart(conn)) return NULL; if (!PQsendQuery(conn, query)) return NULL; return PQexecFinish(conn); } /* * PQexecParams * Like PQexec, but use protocol 3.0 so we can pass parameters */ PGresult * PQexecParams(PGconn *conn, const char *command, int nParams, const Oid *paramTypes, const char *const * paramValues, const int *paramLengths, const int *paramFormats, int resultFormat) { if (!PQexecStart(conn)) return NULL; if (!PQsendQueryParams(conn, command, nParams, paramTypes, paramValues, paramLengths, paramFormats, resultFormat)) return NULL; return PQexecFinish(conn); } /* * PQprepare * Creates a prepared statement by issuing a v3.0 parse message. * * If the query was not even sent, return NULL; conn->errorMessage is set to * a relevant message. * If the query was sent, a new PGresult is returned (which could indicate * either success or failure). * The user is responsible for freeing the PGresult via PQclear() * when done with it. */ PGresult * PQprepare(PGconn *conn, const char *stmtName, const char *query, int nParams, const Oid *paramTypes) { if (!PQexecStart(conn)) return NULL; if (!PQsendPrepare(conn, stmtName, query, nParams, paramTypes)) return NULL; return PQexecFinish(conn); } /* * PQexecPrepared * Like PQexec, but execute a previously prepared statement, * using protocol 3.0 so we can pass parameters */ PGresult * PQexecPrepared(PGconn *conn, const char *stmtName, int nParams, const char *const * paramValues, const int *paramLengths, const int *paramFormats, int resultFormat) { if (!PQexecStart(conn)) return NULL; if (!PQsendQueryPrepared(conn, stmtName, nParams, paramValues, paramLengths, paramFormats, resultFormat)) return NULL; return PQexecFinish(conn); } /* * Common code for PQexec and sibling routines: prepare to send command */ static bool PQexecStart(PGconn *conn) { PGresult *result; if (!conn) return false; /* * Silently discard any prior query result that application didn't eat. * This is probably poor design, but it's here for backward compatibility. */ while ((result = PQgetResult(conn)) != NULL) { ExecStatusType resultStatus = result->resultStatus; PQclear(result); /* only need its status */ if (resultStatus == PGRES_COPY_IN) { if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3) { /* In protocol 3, we can get out of a COPY IN state */ if (PQputCopyEnd(conn, libpq_gettext("COPY terminated by new PQexec")) < 0) return false; /* keep waiting to swallow the copy's failure message */ } else { /* In older protocols we have to punt */ printfPQExpBuffer(&conn->errorMessage, libpq_gettext("COPY IN state must be terminated first\n")); return false; } } else if (resultStatus == PGRES_COPY_OUT) { if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3) { /* * In protocol 3, we can get out of a COPY OUT state: we just * switch back to BUSY and allow the remaining COPY data to be * dropped on the floor. */ conn->asyncStatus = PGASYNC_BUSY; /* keep waiting to swallow the copy's completion message */ } else { /* In older protocols we have to punt */ printfPQExpBuffer(&conn->errorMessage, libpq_gettext("COPY OUT state must be terminated first\n")); return false; } } else if (resultStatus == PGRES_COPY_BOTH) { /* We don't allow PQexec during COPY BOTH */ printfPQExpBuffer(&conn->errorMessage, libpq_gettext("PQexec not allowed during COPY BOTH\n")); return false; } /* check for loss of connection, too */ if (conn->status == CONNECTION_BAD) return false; } /* OK to send a command */ return true; } /* * Common code for PQexec and sibling routines: wait for command result */ static PGresult * PQexecFinish(PGconn *conn) { PGresult *result; PGresult *lastResult; /* * For backwards compatibility, return the last result if there are more * than one --- but merge error messages if we get more than one error * result. * * We have to stop if we see copy in/out/both, however. We will resume * parsing after application performs the data transfer. * * Also stop if the connection is lost (else we'll loop infinitely). */ lastResult = NULL; while ((result = PQgetResult(conn)) != NULL) { if (lastResult) { if (lastResult->resultStatus == PGRES_FATAL_ERROR && result->resultStatus == PGRES_FATAL_ERROR) { pqCatenateResultError(lastResult, result->errMsg); PQclear(result); result = lastResult; /* * Make sure PQerrorMessage agrees with concatenated result */ resetPQExpBuffer(&conn->errorMessage); appendPQExpBufferStr(&conn->errorMessage, result->errMsg); } else PQclear(lastResult); } lastResult = result; if (result->resultStatus == PGRES_COPY_IN || result->resultStatus == PGRES_COPY_OUT || result->resultStatus == PGRES_COPY_BOTH || conn->status == CONNECTION_BAD) break; } return lastResult; } /* * PQdescribePrepared * Obtain information about a previously prepared statement * * If the query was not even sent, return NULL; conn->errorMessage is set to * a relevant message. * If the query was sent, a new PGresult is returned (which could indicate * either success or failure). On success, the PGresult contains status * PGRES_COMMAND_OK, and its parameter and column-heading fields describe * the statement's inputs and outputs respectively. * The user is responsible for freeing the PGresult via PQclear() * when done with it. */ PGresult * PQdescribePrepared(PGconn *conn, const char *stmt) { if (!PQexecStart(conn)) return NULL; if (!PQsendDescribe(conn, 'S', stmt)) return NULL; return PQexecFinish(conn); } /* * PQdescribePortal * Obtain information about a previously created portal * * This is much like PQdescribePrepared, except that no parameter info is * returned. Note that at the moment, libpq doesn't really expose portals * to the client; but this can be used with a portal created by a SQL * DECLARE CURSOR command. */ PGresult * PQdescribePortal(PGconn *conn, const char *portal) { if (!PQexecStart(conn)) return NULL; if (!PQsendDescribe(conn, 'P', portal)) return NULL; return PQexecFinish(conn); } /* * PQsendDescribePrepared * Submit a Describe Statement command, but don't wait for it to finish * * Returns: 1 if successfully submitted * 0 if error (conn->errorMessage is set) */ int PQsendDescribePrepared(PGconn *conn, const char *stmt) { return PQsendDescribe(conn, 'S', stmt); } /* * PQsendDescribePortal * Submit a Describe Portal command, but don't wait for it to finish * * Returns: 1 if successfully submitted * 0 if error (conn->errorMessage is set) */ int PQsendDescribePortal(PGconn *conn, const char *portal) { return PQsendDescribe(conn, 'P', portal); } /* * PQsendDescribe * Common code to send a Describe command * * Available options for desc_type are * 'S' to describe a prepared statement; or * 'P' to describe a portal. * Returns 1 on success and 0 on failure. */ static int PQsendDescribe(PGconn *conn, char desc_type, const char *desc_target) { /* Treat null desc_target as empty string */ if (!desc_target) desc_target = ""; if (!PQsendQueryStart(conn)) return 0; /* This isn't gonna work on a 2.0 server */ if (PG_PROTOCOL_MAJOR(conn->pversion) < 3) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("function requires at least protocol version 3.0\n")); return 0; } /* construct the Describe message */ if (pqPutMsgStart('D', false, conn) < 0 || pqPutc(desc_type, conn) < 0 || pqPuts(desc_target, conn) < 0 || pqPutMsgEnd(conn) < 0) goto sendFailed; /* construct the Sync message */ if (pqPutMsgStart('S', false, conn) < 0 || pqPutMsgEnd(conn) < 0) goto sendFailed; /* remember we are doing a Describe */ conn->queryclass = PGQUERY_DESCRIBE; /* reset last-query string (not relevant now) */ if (conn->last_query) { free(conn->last_query); conn->last_query = NULL; } /* * Give the data a push. In nonblock mode, don't complain if we're unable * to send it all; PQgetResult() will do any additional flushing needed. */ if (pqFlush(conn) < 0) goto sendFailed; /* OK, it's launched! */ conn->asyncStatus = PGASYNC_BUSY; return 1; sendFailed: pqHandleSendFailure(conn); return 0; } /* * PQnotifies * returns a PGnotify* structure of the latest async notification * that has not yet been handled * * returns NULL, if there is currently * no unhandled async notification from the backend * * the CALLER is responsible for FREE'ing the structure returned */ PGnotify * PQnotifies(PGconn *conn) { PGnotify *event; if (!conn) return NULL; /* Parse any available data to see if we can extract NOTIFY messages. */ parseInput(conn); event = conn->notifyHead; if (event) { conn->notifyHead = event->next; if (!conn->notifyHead) conn->notifyTail = NULL; event->next = NULL; /* don't let app see the internal state */ } return event; } /* * PQputCopyData - send some data to the backend during COPY IN or COPY BOTH * * Returns 1 if successful, 0 if data could not be sent (only possible * in nonblock mode), or -1 if an error occurs. */ int PQputCopyData(PGconn *conn, const char *buffer, int nbytes) { if (!conn) return -1; if (conn->asyncStatus != PGASYNC_COPY_IN && conn->asyncStatus != PGASYNC_COPY_BOTH) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("no COPY in progress\n")); return -1; } /* * Process any NOTICE or NOTIFY messages that might be pending in the * input buffer. Since the server might generate many notices during the * COPY, we want to clean those out reasonably promptly to prevent * indefinite expansion of the input buffer. (Note: the actual read of * input data into the input buffer happens down inside pqSendSome, but * it's not authorized to get rid of the data again.) */ parseInput(conn); if (nbytes > 0) { /* * Try to flush any previously sent data in preference to growing the * output buffer. If we can't enlarge the buffer enough to hold the * data, return 0 in the nonblock case, else hard error. (For * simplicity, always assume 5 bytes of overhead even in protocol 2.0 * case.) */ if ((conn->outBufSize - conn->outCount - 5) < nbytes) { if (pqFlush(conn) < 0) return -1; if (pqCheckOutBufferSpace(conn->outCount + 5 + (size_t) nbytes, conn)) return pqIsnonblocking(conn) ? 0 : -1; } /* Send the data (too simple to delegate to fe-protocol files) */ if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3) { if (pqPutMsgStart('d', false, conn) < 0 || pqPutnchar(buffer, nbytes, conn) < 0 || pqPutMsgEnd(conn) < 0) return -1; } else { if (pqPutMsgStart(0, false, conn) < 0 || pqPutnchar(buffer, nbytes, conn) < 0 || pqPutMsgEnd(conn) < 0) return -1; } } return 1; } /* * PQputCopyEnd - send EOF indication to the backend during COPY IN * * After calling this, use PQgetResult() to check command completion status. * * Returns 1 if successful, 0 if data could not be sent (only possible * in nonblock mode), or -1 if an error occurs. */ int PQputCopyEnd(PGconn *conn, const char *errormsg) { if (!conn) return -1; if (conn->asyncStatus != PGASYNC_COPY_IN) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("no COPY in progress\n")); return -1; } /* * Send the COPY END indicator. This is simple enough that we don't * bother delegating it to the fe-protocol files. */ if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3) { if (errormsg) { /* Send COPY FAIL */ if (pqPutMsgStart('f', false, conn) < 0 || pqPuts(errormsg, conn) < 0 || pqPutMsgEnd(conn) < 0) return -1; } else { /* Send COPY DONE */ if (pqPutMsgStart('c', false, conn) < 0 || pqPutMsgEnd(conn) < 0) return -1; } /* * If we sent the COPY command in extended-query mode, we must issue a * Sync as well. */ if (conn->queryclass != PGQUERY_SIMPLE) { if (pqPutMsgStart('S', false, conn) < 0 || pqPutMsgEnd(conn) < 0) return -1; } } else { if (errormsg) { /* Ooops, no way to do this in 2.0 */ printfPQExpBuffer(&conn->errorMessage, libpq_gettext("function requires at least protocol version 3.0\n")); return -1; } else { /* Send old-style end-of-data marker */ if (pqPutMsgStart(0, false, conn) < 0 || pqPutnchar("\\.\n", 3, conn) < 0 || pqPutMsgEnd(conn) < 0) return -1; } } /* Return to active duty */ conn->asyncStatus = PGASYNC_BUSY; resetPQExpBuffer(&conn->errorMessage); /* Try to flush data */ if (pqFlush(conn) < 0) return -1; return 1; } /* * PQgetCopyData - read a row of data from the backend during COPY OUT * or COPY BOTH * * If successful, sets *buffer to point to a malloc'd row of data, and * returns row length (always > 0) as result. * Returns 0 if no row available yet (only possible if async is true), * -1 if end of copy (consult PQgetResult), or -2 if error (consult * PQerrorMessage). */ int PQgetCopyData(PGconn *conn, char **buffer, int async) { *buffer = NULL; /* for all failure cases */ if (!conn) return -2; if (conn->asyncStatus != PGASYNC_COPY_OUT && conn->asyncStatus != PGASYNC_COPY_BOTH) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("no COPY in progress\n")); return -2; } if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3) return pqGetCopyData3(conn, buffer, async); else return pqGetCopyData2(conn, buffer, async); } /* * PQgetline - gets a newline-terminated string from the backend. * * Chiefly here so that applications can use "COPY to stdout" * and read the output string. Returns a null-terminated string in s. * * XXX this routine is now deprecated, because it can't handle binary data. * If called during a COPY BINARY we return EOF. * * PQgetline reads up to maxlen-1 characters (like fgets(3)) but strips * the terminating \n (like gets(3)). * * CAUTION: the caller is responsible for detecting the end-of-copy signal * (a line containing just "\.") when using this routine. * * RETURNS: * EOF if error (eg, invalid arguments are given) * 0 if EOL is reached (i.e., \n has been read) * (this is required for backward-compatibility -- this * routine used to always return EOF or 0, assuming that * the line ended within maxlen bytes.) * 1 in other cases (i.e., the buffer was filled before \n is reached) */ int PQgetline(PGconn *conn, char *s, int maxlen) { if (!s || maxlen <= 0) return EOF; *s = '\0'; /* maxlen must be at least 3 to hold the \. terminator! */ if (maxlen < 3) return EOF; if (!conn) return EOF; if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3) return pqGetline3(conn, s, maxlen); else return pqGetline2(conn, s, maxlen); } /* * PQgetlineAsync - gets a COPY data row without blocking. * * This routine is for applications that want to do "COPY to stdout" * asynchronously, that is without blocking. Having issued the COPY command * and gotten a PGRES_COPY_OUT response, the app should call PQconsumeInput * and this routine until the end-of-data signal is detected. Unlike * PQgetline, this routine takes responsibility for detecting end-of-data. * * On each call, PQgetlineAsync will return data if a complete data row * is available in libpq's input buffer. Otherwise, no data is returned * until the rest of the row arrives. * * If -1 is returned, the end-of-data signal has been recognized (and removed * from libpq's input buffer). The caller *must* next call PQendcopy and * then return to normal processing. * * RETURNS: * -1 if the end-of-copy-data marker has been recognized * 0 if no data is available * >0 the number of bytes returned. * * The data returned will not extend beyond a data-row boundary. If possible * a whole row will be returned at one time. But if the buffer offered by * the caller is too small to hold a row sent by the backend, then a partial * data row will be returned. In text mode this can be detected by testing * whether the last returned byte is '\n' or not. * * The returned data is *not* null-terminated. */ int PQgetlineAsync(PGconn *conn, char *buffer, int bufsize) { if (!conn) return -1; if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3) return pqGetlineAsync3(conn, buffer, bufsize); else return pqGetlineAsync2(conn, buffer, bufsize); } /* * PQputline -- sends a string to the backend during COPY IN. * Returns 0 if OK, EOF if not. * * This is deprecated primarily because the return convention doesn't allow * caller to tell the difference between a hard error and a nonblock-mode * send failure. */ int PQputline(PGconn *conn, const char *s) { return PQputnbytes(conn, s, strlen(s)); } /* * PQputnbytes -- like PQputline, but buffer need not be null-terminated. * Returns 0 if OK, EOF if not. */ int PQputnbytes(PGconn *conn, const char *buffer, int nbytes) { if (PQputCopyData(conn, buffer, nbytes) > 0) return 0; else return EOF; } /* * PQendcopy * After completing the data transfer portion of a copy in/out, * the application must call this routine to finish the command protocol. * * When using protocol 3.0 this is deprecated; it's cleaner to use PQgetResult * to get the transfer status. Note however that when using 2.0 protocol, * recovering from a copy failure often requires a PQreset. PQendcopy will * take care of that, PQgetResult won't. * * RETURNS: * 0 on success * 1 on failure */ int PQendcopy(PGconn *conn) { if (!conn) return 0; if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3) return pqEndcopy3(conn); else return pqEndcopy2(conn); } /* ---------------- * PQfn - Send a function call to the POSTGRES backend. * * conn : backend connection * fnid : function id * result_buf : pointer to result buffer (&int if integer) * result_len : length of return value. * actual_result_len: actual length returned. (differs from result_len * for varlena structures.) * result_type : If the result is an integer, this must be 1, * otherwise this should be 0 * args : pointer to an array of function arguments. * (each has length, if integer, and value/pointer) * nargs : # of arguments in args array. * * RETURNS * PGresult with status = PGRES_COMMAND_OK if successful. * *actual_result_len is > 0 if there is a return value, 0 if not. * PGresult with status = PGRES_FATAL_ERROR if backend returns an error. * NULL on communications failure. conn->errorMessage will be set. * ---------------- */ PGresult * PQfn(PGconn *conn, int fnid, int *result_buf, int *actual_result_len, int result_is_int, const PQArgBlock *args, int nargs) { *actual_result_len = 0; if (!conn) return NULL; /* clear the error string */ resetPQExpBuffer(&conn->errorMessage); if (conn->sock < 0 || conn->asyncStatus != PGASYNC_IDLE || conn->result != NULL) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("connection in wrong state\n")); return NULL; } if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3) return pqFunctionCall3(conn, fnid, result_buf, actual_result_len, result_is_int, args, nargs); else return pqFunctionCall2(conn, fnid, result_buf, actual_result_len, result_is_int, args, nargs); } /* ====== accessor funcs for PGresult ======== */ ExecStatusType PQresultStatus(const PGresult *res) { if (!res) return PGRES_FATAL_ERROR; return res->resultStatus; } char * PQresStatus(ExecStatusType status) { if (status < 0 || status >= sizeof pgresStatus / sizeof pgresStatus[0]) return libpq_gettext("invalid ExecStatusType code"); return pgresStatus[status]; } char * PQresultErrorMessage(const PGresult *res) { if (!res || !res->errMsg) return ""; return res->errMsg; } char * PQresultErrorField(const PGresult *res, int fieldcode) { PGMessageField *pfield; if (!res) return NULL; for (pfield = res->errFields; pfield != NULL; pfield = pfield->next) { if (pfield->code == fieldcode) return pfield->contents; } return NULL; } int PQntuples(const PGresult *res) { if (!res) return 0; return res->ntups; } int PQnfields(const PGresult *res) { if (!res) return 0; return res->numAttributes; } int PQbinaryTuples(const PGresult *res) { if (!res) return 0; return res->binary; } /* * Helper routines to range-check field numbers and tuple numbers. * Return TRUE if OK, FALSE if not */ static int check_field_number(const PGresult *res, int field_num) { if (!res) return FALSE; /* no way to display error message... */ if (field_num < 0 || field_num >= res->numAttributes) { pqInternalNotice(&res->noticeHooks, "column number %d is out of range 0..%d", field_num, res->numAttributes - 1); return FALSE; } return TRUE; } static int check_tuple_field_number(const PGresult *res, int tup_num, int field_num) { if (!res) return FALSE; /* no way to display error message... */ if (tup_num < 0 || tup_num >= res->ntups) { pqInternalNotice(&res->noticeHooks, "row number %d is out of range 0..%d", tup_num, res->ntups - 1); return FALSE; } if (field_num < 0 || field_num >= res->numAttributes) { pqInternalNotice(&res->noticeHooks, "column number %d is out of range 0..%d", field_num, res->numAttributes - 1); return FALSE; } return TRUE; } static int check_param_number(const PGresult *res, int param_num) { if (!res) return FALSE; /* no way to display error message... */ if (param_num < 0 || param_num >= res->numParameters) { pqInternalNotice(&res->noticeHooks, "parameter number %d is out of range 0..%d", param_num, res->numParameters - 1); return FALSE; } return TRUE; } /* * returns NULL if the field_num is invalid */ char * PQfname(const PGresult *res, int field_num) { if (!check_field_number(res, field_num)) return NULL; if (res->attDescs) return res->attDescs[field_num].name; else return NULL; } /* * PQfnumber: find column number given column name * * The column name is parsed as if it were in a SQL statement, including * case-folding and double-quote processing. But note a possible gotcha: * downcasing in the frontend might follow different locale rules than * downcasing in the backend... * * Returns -1 if no match. In the present backend it is also possible * to have multiple matches, in which case the first one is found. */ int PQfnumber(const PGresult *res, const char *field_name) { char *field_case; bool in_quotes; char *iptr; char *optr; int i; if (!res) return -1; /* * Note: it is correct to reject a zero-length input string; the proper * input to match a zero-length field name would be "". */ if (field_name == NULL || field_name[0] == '\0' || res->attDescs == NULL) return -1; /* * Note: this code will not reject partially quoted strings, eg * foo"BAR"foo will become fooBARfoo when it probably ought to be an error * condition. */ field_case = strdup(field_name); if (field_case == NULL) return -1; /* grotty */ in_quotes = false; optr = field_case; for (iptr = field_case; *iptr; iptr++) { char c = *iptr; if (in_quotes) { if (c == '"') { if (iptr[1] == '"') { /* doubled quotes become a single quote */ *optr++ = '"'; iptr++; } else in_quotes = false; } else *optr++ = c; } else if (c == '"') in_quotes = true; else { c = pg_tolower((unsigned char) c); *optr++ = c; } } *optr = '\0'; for (i = 0; i < res->numAttributes; i++) { if (strcmp(field_case, res->attDescs[i].name) == 0) { free(field_case); return i; } } free(field_case); return -1; } Oid PQftable(const PGresult *res, int field_num) { if (!check_field_number(res, field_num)) return InvalidOid; if (res->attDescs) return res->attDescs[field_num].tableid; else return InvalidOid; } int PQftablecol(const PGresult *res, int field_num) { if (!check_field_number(res, field_num)) return 0; if (res->attDescs) return res->attDescs[field_num].columnid; else return 0; } int PQfformat(const PGresult *res, int field_num) { if (!check_field_number(res, field_num)) return 0; if (res->attDescs) return res->attDescs[field_num].format; else return 0; } Oid PQftype(const PGresult *res, int field_num) { if (!check_field_number(res, field_num)) return InvalidOid; if (res->attDescs) return res->attDescs[field_num].typid; else return InvalidOid; } int PQfsize(const PGresult *res, int field_num) { if (!check_field_number(res, field_num)) return 0; if (res->attDescs) return res->attDescs[field_num].typlen; else return 0; } int PQfmod(const PGresult *res, int field_num) { if (!check_field_number(res, field_num)) return 0; if (res->attDescs) return res->attDescs[field_num].atttypmod; else return 0; } char * PQcmdStatus(PGresult *res) { if (!res) return NULL; return res->cmdStatus; } /* * PQoidStatus - * if the last command was an INSERT, return the oid string * if not, return "" */ char * PQoidStatus(const PGresult *res) { /* * This must be enough to hold the result. Don't laugh, this is better * than what this function used to do. */ static char buf[24]; size_t len; if (!res || !res->cmdStatus || strncmp(res->cmdStatus, "INSERT ", 7) != 0) return ""; len = strspn(res->cmdStatus + 7, "0123456789"); if (len > 23) len = 23; strncpy(buf, res->cmdStatus + 7, len); buf[len] = '\0'; return buf; } /* * PQoidValue - * a perhaps preferable form of the above which just returns * an Oid type */ Oid PQoidValue(const PGresult *res) { char *endptr = NULL; unsigned long result; if (!res || !res->cmdStatus || strncmp(res->cmdStatus, "INSERT ", 7) != 0 || res->cmdStatus[7] < '0' || res->cmdStatus[7] > '9') return InvalidOid; result = strtoul(res->cmdStatus + 7, &endptr, 10); if (!endptr || (*endptr != ' ' && *endptr != '\0')) return InvalidOid; else return (Oid) result; } /* * PQcmdTuples - * If the last command was INSERT/UPDATE/DELETE/MOVE/FETCH/COPY, return * a string containing the number of inserted/affected tuples. If not, * return "". * * XXX: this should probably return an int */ char * PQcmdTuples(PGresult *res) { char *p, *c; if (!res) return ""; if (strncmp(res->cmdStatus, "INSERT ", 7) == 0) { p = res->cmdStatus + 7; /* INSERT: skip oid and space */ while (*p && *p != ' ') p++; if (*p == 0) goto interpret_error; /* no space? */ p++; } else if (strncmp(res->cmdStatus, "SELECT ", 7) == 0 || strncmp(res->cmdStatus, "DELETE ", 7) == 0 || strncmp(res->cmdStatus, "UPDATE ", 7) == 0) p = res->cmdStatus + 7; else if (strncmp(res->cmdStatus, "FETCH ", 6) == 0) p = res->cmdStatus + 6; else if (strncmp(res->cmdStatus, "MOVE ", 5) == 0 || strncmp(res->cmdStatus, "COPY ", 5) == 0) p = res->cmdStatus + 5; else return ""; /* check that we have an integer (at least one digit, nothing else) */ for (c = p; *c; c++) { if (!isdigit((unsigned char) *c)) goto interpret_error; } if (c == p) goto interpret_error; return p; interpret_error: pqInternalNotice(&res->noticeHooks, "could not interpret result from server: %s", res->cmdStatus); return ""; } /* * PQgetvalue: * return the value of field 'field_num' of row 'tup_num' */ char * PQgetvalue(const PGresult *res, int tup_num, int field_num) { if (!check_tuple_field_number(res, tup_num, field_num)) return NULL; return res->tuples[tup_num][field_num].value; } /* PQgetlength: * returns the actual length of a field value in bytes. */ int PQgetlength(const PGresult *res, int tup_num, int field_num) { if (!check_tuple_field_number(res, tup_num, field_num)) return 0; if (res->tuples[tup_num][field_num].len != NULL_LEN) return res->tuples[tup_num][field_num].len; else return 0; } /* PQgetisnull: * returns the null status of a field value. */ int PQgetisnull(const PGresult *res, int tup_num, int field_num) { if (!check_tuple_field_number(res, tup_num, field_num)) return 1; /* pretend it is null */ if (res->tuples[tup_num][field_num].len == NULL_LEN) return 1; else return 0; } /* PQnparams: * returns the number of input parameters of a prepared statement. */ int PQnparams(const PGresult *res) { if (!res) return 0; return res->numParameters; } /* PQparamtype: * returns type Oid of the specified statement parameter. */ Oid PQparamtype(const PGresult *res, int param_num) { if (!check_param_number(res, param_num)) return InvalidOid; if (res->paramDescs) return res->paramDescs[param_num].typid; else return InvalidOid; } /* PQsetnonblocking: * sets the PGconn's database connection non-blocking if the arg is TRUE * or makes it blocking if the arg is FALSE, this will not protect * you from PQexec(), you'll only be safe when using the non-blocking API. * Needs to be called only on a connected database connection. */ int PQsetnonblocking(PGconn *conn, int arg) { bool barg; if (!conn || conn->status == CONNECTION_BAD) return -1; barg = (arg ? TRUE : FALSE); /* early out if the socket is already in the state requested */ if (barg == conn->nonblocking) return 0; /* * to guarantee constancy for flushing/query/result-polling behavior we * need to flush the send queue at this point in order to guarantee proper * behavior. this is ok because either they are making a transition _from_ * or _to_ blocking mode, either way we can block them. */ /* if we are going from blocking to non-blocking flush here */ if (pqFlush(conn)) return -1; conn->nonblocking = barg; return 0; } /* * return the blocking status of the database connection * TRUE == nonblocking, FALSE == blocking */ int PQisnonblocking(const PGconn *conn) { return pqIsnonblocking(conn); } /* libpq is thread-safe? */ int PQisthreadsafe(void) { #ifdef ENABLE_THREAD_SAFETY return true; #else return false; #endif } /* try to force data out, really only useful for non-blocking users */ int PQflush(PGconn *conn) { return pqFlush(conn); } /* * PQfreemem - safely frees memory allocated * * Needed mostly by Win32, unless multithreaded DLL (/MD in VC6) * Used for freeing memory from PQescapeByte()a/PQunescapeBytea() */ void PQfreemem(void *ptr) { free(ptr); } /* * PQfreeNotify - free's the memory associated with a PGnotify * * This function is here only for binary backward compatibility. * New code should use PQfreemem(). A macro will automatically map * calls to PQfreemem. It should be removed in the future. bjm 2003-03-24 */ #undef PQfreeNotify void PQfreeNotify(PGnotify *notify); void PQfreeNotify(PGnotify *notify) { PQfreemem(notify); } /* * Escaping arbitrary strings to get valid SQL literal strings. * * Replaces "'" with "''", and if not std_strings, replaces "\" with "\\". * * length is the length of the source string. (Note: if a terminating NUL * is encountered sooner, PQescapeString stops short of "length"; the behavior * is thus rather like strncpy.) * * For safety the buffer at "to" must be at least 2*length + 1 bytes long. * A terminating NUL character is added to the output string, whether the * input is NUL-terminated or not. * * Returns the actual length of the output (not counting the terminating NUL). */ static size_t PQescapeStringInternal(PGconn *conn, char *to, const char *from, size_t length, int *error, int encoding, bool std_strings) { const char *source = from; char *target = to; size_t remaining = length; if (error) *error = 0; while (remaining > 0 && *source != '\0') { char c = *source; int len; int i; /* Fast path for plain ASCII */ if (!IS_HIGHBIT_SET(c)) { /* Apply quoting if needed */ if (SQL_STR_DOUBLE(c, !std_strings)) *target++ = c; /* Copy the character */ *target++ = c; source++; remaining--; continue; } /* Slow path for possible multibyte characters */ len = pg_encoding_mblen(encoding, source); /* Copy the character */ for (i = 0; i < len; i++) { if (remaining == 0 || *source == '\0') break; *target++ = *source++; remaining--; } /* * If we hit premature end of string (ie, incomplete multibyte * character), try to pad out to the correct length with spaces. We * may not be able to pad completely, but we will always be able to * insert at least one pad space (since we'd not have quoted a * multibyte character). This should be enough to make a string that * the server will error out on. */ if (i < len) { if (error) *error = 1; if (conn) printfPQExpBuffer(&conn->errorMessage, libpq_gettext("incomplete multibyte character\n")); for (; i < len; i++) { if (((size_t) (target - to)) / 2 >= length) break; *target++ = ' '; } break; } } /* Write the terminating NUL character. */ *target = '\0'; return target - to; } size_t PQescapeStringConn(PGconn *conn, char *to, const char *from, size_t length, int *error) { if (!conn) { /* force empty-string result */ *to = '\0'; if (error) *error = 1; return 0; } return PQescapeStringInternal(conn, to, from, length, error, conn->client_encoding, conn->std_strings); } size_t PQescapeString(char *to, const char *from, size_t length) { return PQescapeStringInternal(NULL, to, from, length, NULL, static_client_encoding, static_std_strings); } /* * Escape arbitrary strings. If as_ident is true, we escape the result * as an identifier; if false, as a literal. The result is returned in * a newly allocated buffer. If we fail due to an encoding violation or out * of memory condition, we return NULL, storing an error message into conn. */ static char * PQescapeInternal(PGconn *conn, const char *str, size_t len, bool as_ident) { const char *s; char *result; char *rp; int num_quotes = 0; /* single or double, depending on as_ident */ int num_backslashes = 0; int input_len; int result_size; char quote_char = as_ident ? '"' : '\''; /* We must have a connection, else fail immediately. */ if (!conn) return NULL; /* Scan the string for characters that must be escaped. */ for (s = str; (s - str) < len && *s != '\0'; ++s) { if (*s == quote_char) ++num_quotes; else if (*s == '\\') ++num_backslashes; else if (IS_HIGHBIT_SET(*s)) { int charlen; /* Slow path for possible multibyte characters */ charlen = pg_encoding_mblen(conn->client_encoding, s); /* Multibyte character overruns allowable length. */ if ((s - str) + charlen > len || memchr(s, 0, charlen) != NULL) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("incomplete multibyte character\n")); return NULL; } /* Adjust s, bearing in mind that for loop will increment it. */ s += charlen - 1; } } /* Allocate output buffer. */ input_len = s - str; result_size = input_len + num_quotes + 3; /* two quotes, plus a NUL */ if (!as_ident && num_backslashes > 0) result_size += num_backslashes + 2; result = rp = (char *) malloc(result_size); if (rp == NULL) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("out of memory\n")); return NULL; } /* * If we are escaping a literal that contains backslashes, we use the * escape string syntax so that the result is correct under either value * of standard_conforming_strings. We also emit a leading space in this * case, to guard against the possibility that the result might be * interpolated immediately following an identifier. */ if (!as_ident && num_backslashes > 0) { *rp++ = ' '; *rp++ = 'E'; } /* Opening quote. */ *rp++ = quote_char; /* * Use fast path if possible. * * We've already verified that the input string is well-formed in the * current encoding. If it contains no quotes and, in the case of * literal-escaping, no backslashes, then we can just copy it directly to * the output buffer, adding the necessary quotes. * * If not, we must rescan the input and process each character * individually. */ if (num_quotes == 0 && (num_backslashes == 0 || as_ident)) { memcpy(rp, str, input_len); rp += input_len; } else { for (s = str; s - str < input_len; ++s) { if (*s == quote_char || (!as_ident && *s == '\\')) { *rp++ = *s; *rp++ = *s; } else if (!IS_HIGHBIT_SET(*s)) *rp++ = *s; else { int i = pg_encoding_mblen(conn->client_encoding, s); while (1) { *rp++ = *s; if (--i == 0) break; ++s; /* for loop will provide the final increment */ } } } } /* Closing quote and terminating NUL. */ *rp++ = quote_char; *rp = '\0'; return result; } char * PQescapeLiteral(PGconn *conn, const char *str, size_t len) { return PQescapeInternal(conn, str, len, false); } char * PQescapeIdentifier(PGconn *conn, const char *str, size_t len) { return PQescapeInternal(conn, str, len, true); } /* HEX encoding support for bytea */ static const char hextbl[] = "0123456789abcdef"; static const int8 hexlookup[128] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, }; static inline char get_hex(char c) { int res = -1; if (c > 0 && c < 127) res = hexlookup[(unsigned char) c]; return (char) res; } /* * PQescapeBytea - converts from binary string to the * minimal encoding necessary to include the string in an SQL * INSERT statement with a bytea type column as the target. * * We can use either hex or escape (traditional) encoding. * In escape mode, the following transformations are applied: * '\0' == ASCII 0 == \000 * '\'' == ASCII 39 == '' * '\\' == ASCII 92 == \\ * anything < 0x20, or > 0x7e ---> \ooo * (where ooo is an octal expression) * * If not std_strings, all backslashes sent to the output are doubled. */ static unsigned char * PQescapeByteaInternal(PGconn *conn, const unsigned char *from, size_t from_length, size_t *to_length, bool std_strings, bool use_hex) { const unsigned char *vp; unsigned char *rp; unsigned char *result; size_t i; size_t len; size_t bslash_len = (std_strings ? 1 : 2); /* * empty string has 1 char ('\0') */ len = 1; if (use_hex) { len += bslash_len + 1 + 2 * from_length; } else { vp = from; for (i = from_length; i > 0; i--, vp++) { if (*vp < 0x20 || *vp > 0x7e) len += bslash_len + 3; else if (*vp == '\'') len += 2; else if (*vp == '\\') len += bslash_len + bslash_len; else len++; } } *to_length = len; rp = result = (unsigned char *) malloc(len); if (rp == NULL) { if (conn) printfPQExpBuffer(&conn->errorMessage, libpq_gettext("out of memory\n")); return NULL; } if (use_hex) { if (!std_strings) *rp++ = '\\'; *rp++ = '\\'; *rp++ = 'x'; } vp = from; for (i = from_length; i > 0; i--, vp++) { unsigned char c = *vp; if (use_hex) { *rp++ = hextbl[(c >> 4) & 0xF]; *rp++ = hextbl[c & 0xF]; } else if (c < 0x20 || c > 0x7e) { if (!std_strings) *rp++ = '\\'; *rp++ = '\\'; *rp++ = (c >> 6) + '0'; *rp++ = ((c >> 3) & 07) + '0'; *rp++ = (c & 07) + '0'; } else if (c == '\'') { *rp++ = '\''; *rp++ = '\''; } else if (c == '\\') { if (!std_strings) { *rp++ = '\\'; *rp++ = '\\'; } *rp++ = '\\'; *rp++ = '\\'; } else *rp++ = c; } *rp = '\0'; return result; } unsigned char * PQescapeByteaConn(PGconn *conn, const unsigned char *from, size_t from_length, size_t *to_length) { if (!conn) return NULL; return PQescapeByteaInternal(conn, from, from_length, to_length, conn->std_strings, (conn->sversion >= 90000)); } unsigned char * PQescapeBytea(const unsigned char *from, size_t from_length, size_t *to_length) { return PQescapeByteaInternal(NULL, from, from_length, to_length, static_std_strings, false /* can't use hex */ ); } #define ISFIRSTOCTDIGIT(CH) ((CH) >= '0' && (CH) <= '3') #define ISOCTDIGIT(CH) ((CH) >= '0' && (CH) <= '7') #define OCTVAL(CH) ((CH) - '0') /* * PQunescapeBytea - converts the null terminated string representation * of a bytea, strtext, into binary, filling a buffer. It returns a * pointer to the buffer (or NULL on error), and the size of the * buffer in retbuflen. The pointer may subsequently be used as an * argument to the function PQfreemem. * * The following transformations are made: * \\ == ASCII 92 == \ * \ooo == a byte whose value = ooo (ooo is an octal number) * \x == x (x is any character not matched by the above transformations) */ unsigned char * PQunescapeBytea(const unsigned char *strtext, size_t *retbuflen) { size_t strtextlen, buflen; unsigned char *buffer, *tmpbuf; size_t i, j; if (strtext == NULL) return NULL; strtextlen = strlen((const char *) strtext); if (strtext[0] == '\\' && strtext[1] == 'x') { const unsigned char *s; unsigned char *p; buflen = (strtextlen - 2) / 2; /* Avoid unportable malloc(0) */ buffer = (unsigned char *) malloc(buflen > 0 ? buflen : 1); if (buffer == NULL) return NULL; s = strtext + 2; p = buffer; while (*s) { char v1, v2; /* * Bad input is silently ignored. Note that this includes * whitespace between hex pairs, which is allowed by byteain. */ v1 = get_hex(*s++); if (!*s || v1 == (char) -1) continue; v2 = get_hex(*s++); if (v2 != (char) -1) *p++ = (v1 << 4) | v2; } buflen = p - buffer; } else { /* * Length of input is max length of output, but add one to avoid * unportable malloc(0) if input is zero-length. */ buffer = (unsigned char *) malloc(strtextlen + 1); if (buffer == NULL) return NULL; for (i = j = 0; i < strtextlen;) { switch (strtext[i]) { case '\\': i++; if (strtext[i] == '\\') buffer[j++] = strtext[i++]; else { if ((ISFIRSTOCTDIGIT(strtext[i])) && (ISOCTDIGIT(strtext[i + 1])) && (ISOCTDIGIT(strtext[i + 2]))) { int byte; byte = OCTVAL(strtext[i++]); byte = (byte << 3) + OCTVAL(strtext[i++]); byte = (byte << 3) + OCTVAL(strtext[i++]); buffer[j++] = byte; } } /* * Note: if we see '\' followed by something that isn't a * recognized escape sequence, we loop around having done * nothing except advance i. Therefore the something will * be emitted as ordinary data on the next cycle. Corner * case: '\' at end of string will just be discarded. */ break; default: buffer[j++] = strtext[i++]; break; } } buflen = j; /* buflen is the length of the dequoted data */ } /* Shrink the buffer to be no larger than necessary */ /* +1 avoids unportable behavior when buflen==0 */ tmpbuf = realloc(buffer, buflen + 1); /* It would only be a very brain-dead realloc that could fail, but... */ if (!tmpbuf) { free(buffer); return NULL; } *retbuflen = buflen; return tmpbuf; } RPostgreSQL/src/libpq/pg_service.conf.sample0000644000176000001440000000113411660061757020612 0ustar ripleyusers# # Connection configuration file # # A service is a set of named connection parameters. You may specify # multiple services in this file. Each starts with a service name in # brackets. Subsequent lines have connection configuration parameters of # the pattern "param=value" or LDAP URLs starting with "ldap://" # to look up such parameters. A sample configuration for postgres is # included in this file. Lines beginning with '#' are comments. # # Copy this to your sysconf directory (typically /usr/local/pgsql/etc) and # rename it pg_service.conf. # # #[postgres] #dbname=postgres #user=postgres RPostgreSQL/src/libpq/win32.h0000644000176000001440000000132012124517222015432 0ustar ripleyusers/* * src/interfaces/libpq/win32.h */ #ifndef __win32_h_included #define __win32_h_included /* * Some compatibility functions */ #ifdef __BORLANDC__ #define _timeb timeb #define _ftime(a) ftime(a) #define _errno errno #define popen(a,b) _popen(a,b) #else /* open provided elsewhere */ #define close(a) _close(a) #define read(a,b,c) _read(a,b,c) #define write(a,b,c) _write(a,b,c) #endif #undef EAGAIN /* doesn't apply on sockets */ #undef EINTR #define EINTR WSAEINTR #define EWOULDBLOCK WSAEWOULDBLOCK #define ECONNRESET WSAECONNRESET #define EINPROGRESS WSAEINPROGRESS /* * support for handling Windows Socket errors */ extern const char *winsock_strerror(int err, char *strerrbuf, size_t buflen); #endif RPostgreSQL/src/libpq/strlcpy.c0000644000176000001440000000403612124517222016172 0ustar ripleyusers/*------------------------------------------------------------------------- * * strlcpy.c * strncpy done right * * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * * * IDENTIFICATION * src/port/strlcpy.c * * This file was taken from OpenBSD and is used on platforms that don't * provide strlcpy(). The OpenBSD copyright terms follow. *------------------------------------------------------------------------- */ /* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $ */ /* * Copyright (c) 1998 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "c.h" /* * Copy src to string dst of size siz. At most siz-1 characters * will be copied. Always NUL terminates (unless siz == 0). * Returns strlen(src); if retval >= siz, truncation occurred. * Function creation history: http://www.gratisoft.us/todd/papers/strlcpy.html */ size_t strlcpy(char *dst, const char *src, size_t siz) { char *d = dst; const char *s = src; size_t n = siz; /* Copy as many bytes as will fit */ if (n != 0) { while (--n != 0) { if ((*d++ = *s++) == '\0') break; } } /* Not enough room in dst, add NUL and traverse rest of src */ if (n == 0) { if (siz != 0) *d = '\0'; /* NUL-terminate dst */ while (*s++) ; } return (s - src - 1); /* count does not include NUL */ } RPostgreSQL/src/libpq/pthread-win32.h0000644000176000001440000000073212124517222017065 0ustar ripleyusers/* * src/port/pthread-win32.h */ #ifndef __PTHREAD_H #define __PTHREAD_H typedef ULONG pthread_key_t; typedef CRITICAL_SECTION *pthread_mutex_t; typedef int pthread_once_t; DWORD pthread_self(void); void pthread_setspecific(pthread_key_t, void *); void *pthread_getspecific(pthread_key_t); int pthread_mutex_init(pthread_mutex_t *, void *attr); int pthread_mutex_lock(pthread_mutex_t *); /* blocking */ int pthread_mutex_unlock(pthread_mutex_t *); #endif RPostgreSQL/src/libpq/pg_config.h.darwin0000644000176000001440000006434711663173071017737 0ustar ripleyusers/* src/include/pg_config.h. Generated from pg_config.h.in by configure. */ /* src/include/pg_config.h.in. Generated from configure.in by autoheader. */ /* Define to the type of arg 1 of 'accept' */ #define ACCEPT_TYPE_ARG1 int /* Define to the type of arg 2 of 'accept' */ #define ACCEPT_TYPE_ARG2 struct sockaddr * /* Define to the type of arg 3 of 'accept' */ #define ACCEPT_TYPE_ARG3 socklen_t /* Define to the return type of 'accept' */ #define ACCEPT_TYPE_RETURN int /* Define if building universal (internal helper macro) */ /* #undef AC_APPLE_UNIVERSAL_BUILD */ /* The normal alignment of `double', in bytes. */ #define ALIGNOF_DOUBLE 8 /* The normal alignment of `int', in bytes. */ #define ALIGNOF_INT 4 /* The normal alignment of `long', in bytes. */ #define ALIGNOF_LONG 8 /* The normal alignment of `long long int', in bytes. */ /* #undef ALIGNOF_LONG_LONG_INT */ /* The normal alignment of `short', in bytes. */ #define ALIGNOF_SHORT 2 /* Size of a disk block --- this also limits the size of a tuple. You can set it bigger if you need bigger tuples (although TOAST should reduce the need to have large tuples, since fields can be spread across multiple tuples). BLCKSZ must be a power of 2. The maximum possible value of BLCKSZ is currently 2^15 (32768). This is determined by the 15-bit widths of the lp_off and lp_len fields in ItemIdData (see include/storage/itemid.h). Changing BLCKSZ requires an initdb. */ #define BLCKSZ 8192 /* Define to the default TCP port number on which the server listens and to which clients will try to connect. This can be overridden at run-time, but it's convenient if your clients have the right default compiled in. (--with-pgport=PORTNUM) */ #define DEF_PGPORT 5432 /* Define to the default TCP port number as a string constant. */ #define DEF_PGPORT_STR "5432" /* Define to 1 to enable DTrace support. (--enable-dtrace) */ /* #undef ENABLE_DTRACE */ /* Define to build with GSSAPI support. (--with-gssapi) */ /* #undef ENABLE_GSS */ /* Define to 1 if you want National Language Support. (--enable-nls) */ /* #undef ENABLE_NLS */ /* Define to 1 to build client libraries as thread-safe code. (--enable-thread-safety) */ #define ENABLE_THREAD_SAFETY 1 /* float4 values are passed by value if 'true', by reference if 'false' */ #define FLOAT4PASSBYVAL true /* float8, int8, and related values are passed by value if 'true', by reference if 'false' */ #define FLOAT8PASSBYVAL true /* Define to 1 if getpwuid_r() takes a 5th argument. */ #define GETPWUID_R_5ARG /**/ /* Define to 1 if gettimeofday() takes only 1 argument. */ /* #undef GETTIMEOFDAY_1ARG */ #ifdef GETTIMEOFDAY_1ARG # define gettimeofday(a,b) gettimeofday(a) #endif /* Define to 1 if you have the `append_history' function. */ /* #undef HAVE_APPEND_HISTORY */ /* Define to 1 if you have the `atexit' function. */ #define HAVE_ATEXIT 1 /* Define to 1 if you have the `cbrt' function. */ #define HAVE_CBRT 1 /* Define to 1 if you have the `class' function. */ /* #undef HAVE_CLASS */ /* Define to 1 if you have the `crypt' function. */ #define HAVE_CRYPT 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_CRYPT_H */ /* Define to 1 if you have the declaration of `fdatasync', and to 0 if you don't. */ #define HAVE_DECL_FDATASYNC 0 /* Define to 1 if you have the declaration of `F_FULLFSYNC', and to 0 if you don't. */ #define HAVE_DECL_F_FULLFSYNC 1 /* Define to 1 if you have the declaration of `posix_fadvise', and to 0 if you don't. */ #define HAVE_DECL_POSIX_FADVISE 0 /* Define to 1 if you have the declaration of `snprintf', and to 0 if you don't. */ #define HAVE_DECL_SNPRINTF 1 /* Define to 1 if you have the declaration of `strlcat', and to 0 if you don't. */ #define HAVE_DECL_STRLCAT 1 /* Define to 1 if you have the declaration of `strlcpy', and to 0 if you don't. */ #define HAVE_DECL_STRLCPY 1 /* Define to 1 if you have the declaration of `sys_siglist', and to 0 if you don't. */ #define HAVE_DECL_SYS_SIGLIST 1 /* Define to 1 if you have the declaration of `vsnprintf', and to 0 if you don't. */ #define HAVE_DECL_VSNPRINTF 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_DLD_H */ /* Define to 1 if you have the `dlopen' function. */ #define HAVE_DLOPEN 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_EDITLINE_HISTORY_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_EDITLINE_READLINE_H */ /* Define to 1 if you have the `erand48' function. */ #define HAVE_ERAND48 1 /* Define to 1 if you have the `ERR_set_mark' function. */ /* #undef HAVE_ERR_SET_MARK */ /* Define to 1 if you have the `fcvt' function. */ #define HAVE_FCVT 1 /* Define to 1 if you have the `fdatasync' function. */ #define HAVE_FDATASYNC 1 /* Define to 1 if you have the `fpclass' function. */ /* #undef HAVE_FPCLASS */ /* Define to 1 if you have the `fp_class' function. */ /* #undef HAVE_FP_CLASS */ /* Define to 1 if you have the `fp_class_d' function. */ /* #undef HAVE_FP_CLASS_D */ /* Define to 1 if you have the header file. */ /* #undef HAVE_FP_CLASS_H */ /* Define to 1 if fseeko (and presumably ftello) exists and is declared. */ #define HAVE_FSEEKO 1 /* Define to 1 if your compiler understands __func__. */ #define HAVE_FUNCNAME__FUNC 1 /* Define to 1 if your compiler understands __FUNCTION__. */ /* #undef HAVE_FUNCNAME__FUNCTION */ /* Define to 1 if you have the `getaddrinfo' function. */ #define HAVE_GETADDRINFO 1 /* Define to 1 if you have the `gethostbyname_r' function. */ /* #undef HAVE_GETHOSTBYNAME_R */ /* Define to 1 if you have the `getifaddrs' function. */ #define HAVE_GETIFADDRS 1 /* Define to 1 if you have the `getopt' function. */ #define HAVE_GETOPT 1 /* Define to 1 if you have the header file. */ #define HAVE_GETOPT_H 1 /* Define to 1 if you have the `getopt_long' function. */ #define HAVE_GETOPT_LONG 1 /* Define to 1 if you have the `getpeereid' function. */ #define HAVE_GETPEEREID 1 /* Define to 1 if you have the `getpeerucred' function. */ /* #undef HAVE_GETPEERUCRED */ /* Define to 1 if you have the `getpwuid_r' function. */ #define HAVE_GETPWUID_R 1 /* Define to 1 if you have the `getrlimit' function. */ #define HAVE_GETRLIMIT 1 /* Define to 1 if you have the `getrusage' function. */ #define HAVE_GETRUSAGE 1 /* Define to 1 if you have the `gettimeofday' function. */ /* #undef HAVE_GETTIMEOFDAY */ /* Define to 1 if you have the header file. */ /* #undef HAVE_GSSAPI_GSSAPI_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_GSSAPI_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_HISTORY_H */ /* Define to 1 if you have the `history_truncate_file' function. */ #define HAVE_HISTORY_TRUNCATE_FILE 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_IEEEFP_H */ /* Define to 1 if you have the header file. */ #define HAVE_IFADDRS_H 1 /* Define to 1 if you have the `inet_aton' function. */ #define HAVE_INET_ATON 1 /* Define to 1 if the system has the type `int64'. */ /* #undef HAVE_INT64 */ /* Define to 1 if the system has the type `int8'. */ /* #undef HAVE_INT8 */ /* Define to 1 if the system has the type `intptr_t'. */ #define HAVE_INTPTR_T 1 /* Define to 1 if you have the header file. */ #define HAVE_INTTYPES_H 1 /* Define to 1 if you have the global variable 'int opterr'. */ #define HAVE_INT_OPTERR 1 /* Define to 1 if you have the global variable 'int optreset'. */ #define HAVE_INT_OPTRESET 1 /* Define to 1 if you have the global variable 'int timezone'. */ #define HAVE_INT_TIMEZONE /**/ /* Define to 1 if you have support for IPv6. */ #define HAVE_IPV6 1 /* Define to 1 if you have isinf(). */ #define HAVE_ISINF 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_KERNEL_IMAGE_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_KERNEL_OS_H */ /* Define to 1 if `e_data' is member of `krb5_error'. */ /* #undef HAVE_KRB5_ERROR_E_DATA */ /* Define to 1 if `text.data' is member of `krb5_error'. */ /* #undef HAVE_KRB5_ERROR_TEXT_DATA */ /* Define to 1 if you have krb5_free_unparsed_name */ /* #undef HAVE_KRB5_FREE_UNPARSED_NAME */ /* Define to 1 if `client' is member of `krb5_ticket'. */ /* #undef HAVE_KRB5_TICKET_CLIENT */ /* Define to 1 if `enc_part2' is member of `krb5_ticket'. */ /* #undef HAVE_KRB5_TICKET_ENC_PART2 */ /* Define to 1 if you have the header file. */ #define HAVE_LANGINFO_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_LDAP_H */ /* Define to 1 if you have the `crypto' library (-lcrypto). */ /* #undef HAVE_LIBCRYPTO */ /* Define to 1 if you have the `eay32' library (-leay32). */ /* #undef HAVE_LIBEAY32 */ /* Define to 1 if you have the `ldap' library (-lldap). */ /* #undef HAVE_LIBLDAP */ /* Define to 1 if you have the `ldap_r' library (-lldap_r). */ /* #undef HAVE_LIBLDAP_R */ /* Define to 1 if you have the `m' library (-lm). */ #define HAVE_LIBM 1 /* Define to 1 if you have the `pam' library (-lpam). */ /* #undef HAVE_LIBPAM */ /* Define if you have a function readline library */ #define HAVE_LIBREADLINE 1 /* Define to 1 if you have the `selinux' library (-lselinux). */ /* #undef HAVE_LIBSELINUX */ /* Define to 1 if you have the `ssl' library (-lssl). */ /* #undef HAVE_LIBSSL */ /* Define to 1 if you have the `ssleay32' library (-lssleay32). */ /* #undef HAVE_LIBSSLEAY32 */ /* Define to 1 if you have the `wldap32' library (-lwldap32). */ /* #undef HAVE_LIBWLDAP32 */ /* Define to 1 if you have the `xml2' library (-lxml2). */ /* #undef HAVE_LIBXML2 */ /* Define to 1 if you have the `xslt' library (-lxslt). */ /* #undef HAVE_LIBXSLT */ /* Define to 1 if you have the `z' library (-lz). */ #define HAVE_LIBZ 1 /* Define to 1 if constants of type 'long long int' should have the suffix LL. */ /* #undef HAVE_LL_CONSTANTS */ /* Define to 1 if the system has the type `locale_t'. */ #define HAVE_LOCALE_T 1 /* Define to 1 if `long int' works and is 64 bits. */ #define HAVE_LONG_INT_64 1 /* Define to 1 if the system has the type `long long int'. */ #define HAVE_LONG_LONG_INT 1 /* Define to 1 if `long long int' works and is 64 bits. */ /* #undef HAVE_LONG_LONG_INT_64 */ /* Define to 1 if you have the `memmove' function. */ #define HAVE_MEMMOVE 1 /* Define to 1 if you have the header file. */ #define HAVE_MEMORY_H 1 /* Define to 1 if the system has the type `MINIDUMP_TYPE'. */ /* #undef HAVE_MINIDUMP_TYPE */ /* Define to 1 if you have the header file. */ #define HAVE_NETINET_IN_H 1 /* Define to 1 if you have the header file. */ #define HAVE_NETINET_TCP_H 1 /* Define to 1 if you have the header file. */ #define HAVE_NET_IF_H 1 /* Define to 1 if you have the `on_exit' function. */ /* #undef HAVE_ON_EXIT */ /* Define to 1 if you have the header file. */ /* #undef HAVE_OSSP_UUID_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_PAM_PAM_APPL_H */ /* Define to 1 if you have the `poll' function. */ #define HAVE_POLL 1 /* Define to 1 if you have the header file. */ #define HAVE_POLL_H 1 /* Define to 1 if you have the `posix_fadvise' function. */ /* #undef HAVE_POSIX_FADVISE */ /* Define to 1 if you have the POSIX signal interface. */ #define HAVE_POSIX_SIGNALS /**/ /* Define to 1 if you have the `pstat' function. */ /* #undef HAVE_PSTAT */ /* Define to 1 if the PS_STRINGS thing exists. */ /* #undef HAVE_PS_STRINGS */ /* Define if you have POSIX threads libraries and header files. */ /* #undef HAVE_PTHREAD */ /* Define to 1 if you have the header file. */ #define HAVE_PWD_H 1 /* Define to 1 if you have the `random' function. */ #define HAVE_RANDOM 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_READLINE_H */ /* Define to 1 if you have the header file. */ #define HAVE_READLINE_HISTORY_H 1 /* Define to 1 if you have the header file. */ #define HAVE_READLINE_READLINE_H 1 /* Define to 1 if you have the `readlink' function. */ #define HAVE_READLINK 1 /* Define to 1 if you have the `rint' function. */ #define HAVE_RINT 1 /* Define to 1 if you have the global variable 'rl_completion_append_character'. */ #define HAVE_RL_COMPLETION_APPEND_CHARACTER 1 /* Define to 1 if you have the `rl_completion_matches' function. */ #define HAVE_RL_COMPLETION_MATCHES 1 /* Define to 1 if you have the `rl_filename_completion_function' function. */ #define HAVE_RL_FILENAME_COMPLETION_FUNCTION 1 /* Define to 1 if you have the `scandir' function. */ #define HAVE_SCANDIR 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SECURITY_PAM_APPL_H */ /* Define to 1 if you have the `setproctitle' function. */ /* #undef HAVE_SETPROCTITLE */ /* Define to 1 if you have the `setsid' function. */ #define HAVE_SETSID 1 /* Define to 1 if you have the `sigprocmask' function. */ #define HAVE_SIGPROCMASK 1 /* Define to 1 if you have sigsetjmp(). */ #define HAVE_SIGSETJMP 1 /* Define to 1 if the system has the type `sig_atomic_t'. */ #define HAVE_SIG_ATOMIC_T 1 /* Define to 1 if you have the `snprintf' function. */ #define HAVE_SNPRINTF 1 /* Define to 1 if you have spinlocks. */ #define HAVE_SPINLOCKS 1 /* Define to 1 if you have the `srandom' function. */ #define HAVE_SRANDOM 1 /* Define to 1 if you have the header file. */ #define HAVE_STDINT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDLIB_H 1 /* Define to 1 if you have the `strdup' function. */ #define HAVE_STRDUP 1 /* Define to 1 if you have the `strerror' function. */ #define HAVE_STRERROR 1 /* Define to 1 if you have the `strerror_r' function. */ #define HAVE_STRERROR_R 1 /* Define to 1 if cpp supports the ANSI # stringizing operator. */ #define HAVE_STRINGIZE 1 /* Define to 1 if you have the header file. */ #define HAVE_STRINGS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRING_H 1 /* Define to 1 if you have the `strlcat' function. */ #define HAVE_STRLCAT 1 /* Define to 1 if you have the `strlcpy' function. */ #define HAVE_STRLCPY 1 /* Define to 1 if you have the `strtol' function. */ #define HAVE_STRTOL 1 /* Define to 1 if you have the `strtoll' function. */ #define HAVE_STRTOLL 1 /* Define to 1 if you have the `strtoq' function. */ /* #undef HAVE_STRTOQ */ /* Define to 1 if you have the `strtoul' function. */ #define HAVE_STRTOUL 1 /* Define to 1 if you have the `strtoull' function. */ #define HAVE_STRTOULL 1 /* Define to 1 if you have the `strtouq' function. */ /* #undef HAVE_STRTOUQ */ /* Define to 1 if the system has the type `struct addrinfo'. */ #define HAVE_STRUCT_ADDRINFO 1 /* Define to 1 if the system has the type `struct cmsgcred'. */ /* #undef HAVE_STRUCT_CMSGCRED */ /* Define to 1 if the system has the type `struct option'. */ #define HAVE_STRUCT_OPTION 1 /* Define to 1 if `sa_len' is member of `struct sockaddr'. */ #define HAVE_STRUCT_SOCKADDR_SA_LEN 1 /* Define to 1 if the system has the type `struct sockaddr_storage'. */ #define HAVE_STRUCT_SOCKADDR_STORAGE 1 /* Define to 1 if `ss_family' is member of `struct sockaddr_storage'. */ #define HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY 1 /* Define to 1 if `ss_len' is member of `struct sockaddr_storage'. */ #define HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN 1 /* Define to 1 if `__ss_family' is member of `struct sockaddr_storage'. */ /* #undef HAVE_STRUCT_SOCKADDR_STORAGE___SS_FAMILY */ /* Define to 1 if `__ss_len' is member of `struct sockaddr_storage'. */ /* #undef HAVE_STRUCT_SOCKADDR_STORAGE___SS_LEN */ /* Define to 1 if the system has the type `struct sockaddr_un'. */ #define HAVE_STRUCT_SOCKADDR_UN 1 /* Define to 1 if `tm_zone' is member of `struct tm'. */ #define HAVE_STRUCT_TM_TM_ZONE 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SUPPORTDEFS_H */ /* Define to 1 if you have the `symlink' function. */ #define HAVE_SYMLINK 1 /* Define to 1 if you have the `sysconf' function. */ #define HAVE_SYSCONF 1 /* Define to 1 if you have the syslog interface. */ #define HAVE_SYSLOG 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_IOCTL_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_IPC_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_POLL_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_PSTAT_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_RESOURCE_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_SELECT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_SEM_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_SHM_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_SOCKET_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_SOCKIO_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_STAT_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_TAS_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_TIME_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_UCRED_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_UN_H 1 /* Define to 1 if you have the header file. */ #define HAVE_TERMIOS_H 1 /* Define to 1 if your `struct tm' has `tm_zone'. Deprecated, use `HAVE_STRUCT_TM_TM_ZONE' instead. */ #define HAVE_TM_ZONE 1 /* Define to 1 if you have the `towlower' function. */ #define HAVE_TOWLOWER 1 /* Define to 1 if you have the external array `tzname'. */ #define HAVE_TZNAME 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_UCRED_H */ /* Define to 1 if the system has the type `uint64'. */ /* #undef HAVE_UINT64 */ /* Define to 1 if the system has the type `uint8'. */ /* #undef HAVE_UINT8 */ /* Define to 1 if the system has the type `uintptr_t'. */ #define HAVE_UINTPTR_T 1 /* Define to 1 if the system has the type `union semun'. */ #define HAVE_UNION_SEMUN 1 /* Define to 1 if you have the header file. */ #define HAVE_UNISTD_H 1 /* Define to 1 if you have unix sockets. */ #define HAVE_UNIX_SOCKETS 1 /* Define to 1 if you have the `unsetenv' function. */ #define HAVE_UNSETENV 1 /* Define to 1 if you have the `utime' function. */ #define HAVE_UTIME 1 /* Define to 1 if you have the `utimes' function. */ #define HAVE_UTIMES 1 /* Define to 1 if you have the header file. */ #define HAVE_UTIME_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_UUID_H */ /* Define to 1 if you have the `vsnprintf' function. */ #define HAVE_VSNPRINTF 1 /* Define to 1 if you have the `waitpid' function. */ #define HAVE_WAITPID 1 /* Define to 1 if you have the header file. */ #define HAVE_WCHAR_H 1 /* Define to 1 if you have the `wcstombs' function. */ #define HAVE_WCSTOMBS 1 /* Define to 1 if you have the `wcstombs_l' function. */ #define HAVE_WCSTOMBS_L 1 /* Define to 1 if you have the header file. */ #define HAVE_WCTYPE_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_WINLDAP_H */ /* Define to the appropriate snprintf format for 64-bit ints. */ #define INT64_FORMAT "%ld" /* Define to build with Kerberos 5 support. (--with-krb5) */ /* #undef KRB5 */ /* Define to 1 if `locale_t' requires . */ #define LOCALE_T_IN_XLOCALE 1 /* Define as the maximum alignment requirement of any C data type. */ #define MAXIMUM_ALIGNOF 8 /* Define bytes to use libc memset(). */ #define MEMSET_LOOP_LIMIT 1024 /* Define to the address where bug reports for this package should be sent. */ #define PACKAGE_BUGREPORT "pgsql-bugs@postgresql.org" /* Define to the full name of this package. */ #define PACKAGE_NAME "PostgreSQL" /* Define to the full name and version of this package. */ #define PACKAGE_STRING "PostgreSQL 9.1.1" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "postgresql" /* Define to the version of this package. */ #define PACKAGE_VERSION "9.1.1" /* Define to the name of the default PostgreSQL service principal in Kerberos. (--with-krb-srvnam=NAME) */ #define PG_KRB_SRVNAM "postgres" /* PostgreSQL major version as a string */ #define PG_MAJORVERSION "9.1" /* PostgreSQL version as a string */ #define PG_VERSION "9.1.1" /* PostgreSQL version as a number */ #define PG_VERSION_NUM 90101 /* A string containing the version number, platform, and C compiler */ #define PG_VERSION_STR "PostgreSQL 9.1.1 on x86_64-apple-darwin10.8.0, compiled by i686-apple-darwin10-gcc-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5666) (dot 3), 64-bit" /* Define to 1 to allow profiling output to be saved separately for each process. */ /* #undef PROFILE_PID_DIR */ /* Define to the necessary symbol if this constant uses a non-standard name on your system. */ /* #undef PTHREAD_CREATE_JOINABLE */ /* RELSEG_SIZE is the maximum number of blocks allowed in one disk file. Thus, the maximum size of a single file is RELSEG_SIZE * BLCKSZ; relations bigger than that are divided into multiple files. RELSEG_SIZE * BLCKSZ must be less than your OS' limit on file size. This is often 2 GB or 4GB in a 32-bit operating system, unless you have large file support enabled. By default, we make the limit 1 GB to avoid any possible integer-overflow problems within the OS. A limit smaller than necessary only means we divide a large relation into more chunks than necessary, so it seems best to err in the direction of a small limit. A power-of-2 value is recommended to save a few cycles in md.c, but is not absolutely required. Changing RELSEG_SIZE requires an initdb. */ #define RELSEG_SIZE 131072 /* The size of `long', as computed by sizeof. */ #define SIZEOF_LONG 8 /* The size of `off_t', as computed by sizeof. */ #define SIZEOF_OFF_T 8 /* The size of `size_t', as computed by sizeof. */ #define SIZEOF_SIZE_T 8 /* The size of `void *', as computed by sizeof. */ #define SIZEOF_VOID_P 8 /* Define to 1 if you have the ANSI C header files. */ #define STDC_HEADERS 1 /* Define to 1 if strerror_r() returns a int. */ #define STRERROR_R_INT /**/ /* Define to 1 if your declares `struct tm'. */ /* #undef TM_IN_SYS_TIME */ /* Define to the appropriate snprintf format for unsigned 64-bit ints. */ #define UINT64_FORMAT "%lu" /* Define to 1 to build with assertion checks. (--enable-cassert) */ /* #undef USE_ASSERT_CHECKING */ /* Define to 1 to build with Bonjour support. (--with-bonjour) */ /* #undef USE_BONJOUR */ /* Define to 1 if you want float4 values to be passed by value. (--enable-float4-byval) */ #define USE_FLOAT4_BYVAL 1 /* Define to 1 if you want float8, int8, etc values to be passed by value. (--enable-float8-byval) */ #define USE_FLOAT8_BYVAL 1 /* Define to 1 if "static inline" works without unwanted warnings from compilations where static inline functions are defined but not called. */ #define USE_INLINE 1 /* Define to 1 if you want 64-bit integer timestamp and interval support. (--enable-integer-datetimes) */ #define USE_INTEGER_DATETIMES 1 /* Define to 1 to build with LDAP support. (--with-ldap) */ /* #undef USE_LDAP */ /* Define to 1 to build with XML support. (--with-libxml) */ /* #undef USE_LIBXML */ /* Define to 1 to use XSLT support when building contrib/xml2. (--with-libxslt) */ /* #undef USE_LIBXSLT */ /* Define to select named POSIX semaphores. */ /* #undef USE_NAMED_POSIX_SEMAPHORES */ /* Define to 1 to build with PAM support. (--with-pam) */ /* #undef USE_PAM */ /* Use replacement snprintf() functions. */ /* #undef USE_REPL_SNPRINTF */ /* Define to build with (Open)SSL support. (--with-openssl) */ /* #undef USE_SSL */ /* Define to select SysV-style semaphores. */ #define USE_SYSV_SEMAPHORES 1 /* Define to select SysV-style shared memory. */ #define USE_SYSV_SHARED_MEMORY 1 /* Define to select unnamed POSIX semaphores. */ /* #undef USE_UNNAMED_POSIX_SEMAPHORES */ /* Define to select Win32-style semaphores. */ /* #undef USE_WIN32_SEMAPHORES */ /* Define to select Win32-style shared memory. */ /* #undef USE_WIN32_SHARED_MEMORY */ /* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel). */ #if defined AC_APPLE_UNIVERSAL_BUILD # if defined __BIG_ENDIAN__ # define WORDS_BIGENDIAN 1 # endif #else # ifndef WORDS_BIGENDIAN /* # undef WORDS_BIGENDIAN */ # endif #endif /* Size of a WAL file block. This need have no particular relation to BLCKSZ. XLOG_BLCKSZ must be a power of 2, and if your system supports O_DIRECT I/O, XLOG_BLCKSZ must be a multiple of the alignment requirement for direct-I/O buffers, else direct I/O may fail. Changing XLOG_BLCKSZ requires an initdb. */ #define XLOG_BLCKSZ 8192 /* XLOG_SEG_SIZE is the size of a single WAL file. This must be a power of 2 and larger than XLOG_BLCKSZ (preferably, a great deal larger than XLOG_BLCKSZ). Changing XLOG_SEG_SIZE requires an initdb. */ #define XLOG_SEG_SIZE (16 * 1024 * 1024) /* Number of bits in a file offset, on hosts where this is settable. */ /* #undef _FILE_OFFSET_BITS */ /* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */ /* #undef _LARGEFILE_SOURCE */ /* Define for large files, on AIX-style hosts. */ /* #undef _LARGE_FILES */ /* Define to empty if `const' does not conform to ANSI C. */ /* #undef const */ /* Define to `__inline__' or `__inline' if that's what the C compiler calls it, or to nothing if 'inline' is not supported under any name. */ #ifndef __cplusplus /* #undef inline */ #endif /* Define to the type of a signed integer type wide enough to hold a pointer, if such a type exists, and if the system does not define it. */ /* #undef intptr_t */ /* Define to empty if the C compiler does not understand signed types. */ /* #undef signed */ /* Define to the type of an unsigned integer type wide enough to hold a pointer, if such a type exists, and if the system does not define it. */ /* #undef uintptr_t */ /* Define to empty if the keyword `volatile' does not work. Warning: valid code using `volatile' can become incorrect without. Disable with care. */ /* #undef volatile */ RPostgreSQL/src/libpq/nls.mk0000644000176000001440000000043611660061757015466 0ustar ripleyusers# src/interfaces/libpq/nls.mk CATALOG_NAME := libpq AVAIL_LANGUAGES := cs de es fr it ja ko pl pt_BR ru sv tr zh_CN zh_TW GETTEXT_FILES := fe-auth.c fe-connect.c fe-exec.c fe-lobj.c fe-misc.c fe-protocol2.c fe-protocol3.c fe-secure.c GETTEXT_TRIGGERS:= libpq_gettext pqInternalNotice:2 RPostgreSQL/src/libpq/libpqddll.def0000644000176000001440000001310411660061757016764 0ustar ripleyusers; DEF file for MS VC++ LIBRARY LIBPQD EXPORTS PQconnectdb @ 1 PQsetdbLogin @ 2 PQconndefaults @ 3 PQfinish @ 4 PQreset @ 5 PQrequestCancel @ 6 PQdb @ 7 PQuser @ 8 PQpass @ 9 PQhost @ 10 PQport @ 11 PQtty @ 12 PQoptions @ 13 PQstatus @ 14 PQerrorMessage @ 15 PQsocket @ 16 PQbackendPID @ 17 PQtrace @ 18 PQuntrace @ 19 PQsetNoticeProcessor @ 20 PQexec @ 21 PQnotifies @ 22 PQsendQuery @ 23 PQgetResult @ 24 PQisBusy @ 25 PQconsumeInput @ 26 PQgetline @ 27 PQputline @ 28 PQgetlineAsync @ 29 PQputnbytes @ 30 PQendcopy @ 31 PQfn @ 32 PQresultStatus @ 33 PQntuples @ 34 PQnfields @ 35 PQbinaryTuples @ 36 PQfname @ 37 PQfnumber @ 38 PQftype @ 39 PQfsize @ 40 PQfmod @ 41 PQcmdStatus @ 42 PQoidStatus @ 43 PQcmdTuples @ 44 PQgetvalue @ 45 PQgetlength @ 46 PQgetisnull @ 47 PQclear @ 48 PQmakeEmptyPGresult @ 49 PQprint @ 50 PQdisplayTuples @ 51 PQprintTuples @ 52 lo_open @ 53 lo_close @ 54 lo_read @ 55 lo_write @ 56 lo_lseek @ 57 lo_creat @ 58 lo_tell @ 59 lo_unlink @ 60 lo_import @ 61 lo_export @ 62 pgresStatus @ 63 PQmblen @ 64 PQresultErrorMessage @ 65 PQresStatus @ 66 termPQExpBuffer @ 67 appendPQExpBufferChar @ 68 initPQExpBuffer @ 69 resetPQExpBuffer @ 70 PQoidValue @ 71 PQclientEncoding @ 72 PQenv2encoding @ 73 appendBinaryPQExpBuffer @ 74 appendPQExpBufferStr @ 75 destroyPQExpBuffer @ 76 createPQExpBuffer @ 77 PQconninfoFree @ 78 PQconnectPoll @ 79 PQconnectStart @ 80 PQflush @ 81 PQisnonblocking @ 82 PQresetPoll @ 83 PQresetStart @ 84 PQsetClientEncoding @ 85 PQsetnonblocking @ 86 PQfreeNotify @ 87 PQescapeString @ 88 PQescapeBytea @ 89 printfPQExpBuffer @ 90 appendPQExpBuffer @ 91 pg_encoding_to_char @ 92 pg_utf_mblen @ 93 PQunescapeBytea @ 94 PQfreemem @ 95 PQtransactionStatus @ 96 PQparameterStatus @ 97 PQprotocolVersion @ 98 PQsetErrorVerbosity @ 99 PQsetNoticeReceiver @ 100 PQexecParams @ 101 PQsendQueryParams @ 102 PQputCopyData @ 103 PQputCopyEnd @ 104 PQgetCopyData @ 105 PQresultErrorField @ 106 PQftable @ 107 PQftablecol @ 108 PQfformat @ 109 PQexecPrepared @ 110 PQsendQueryPrepared @ 111 PQdsplen @ 112 PQserverVersion @ 113 PQgetssl @ 114 pg_char_to_encoding @ 115 pg_valid_server_encoding @ 116 pqsignal @ 117 PQprepare @ 118 PQsendPrepare @ 119 PQgetCancel @ 120 PQfreeCancel @ 121 PQcancel @ 122 lo_create @ 123 PQinitSSL @ 124 PQregisterThreadLock @ 125 PQescapeStringConn @ 126 PQescapeByteaConn @ 127 PQencryptPassword @ 128 PQisthreadsafe @ 129 enlargePQExpBuffer @ 130 PQnparams @ 131 PQparamtype @ 132 PQdescribePrepared @ 133 PQdescribePortal @ 134 PQsendDescribePrepared @ 135 PQsendDescribePortal @ 136 lo_truncate @ 137 PQconnectionUsedPassword @ 138 pg_valid_server_encoding_id @ 139 PQconnectionNeedsPassword @ 140 lo_import_with_oid @ 141 PQcopyResult @ 142 PQsetResultAttrs @ 143 PQsetvalue @ 144 PQresultAlloc @ 145 PQregisterEventProc @ 146 PQinstanceData @ 147 PQsetInstanceData @ 148 PQresultInstanceData @ 149 PQresultSetInstanceData @ 150 PQfireResultCreateEvents @ 151 PQconninfoParse @ 152 PQinitOpenSSL @ 153 PQescapeLiteral @ 154 PQescapeIdentifier @ 155 PQconnectdbParams @ 156 PQconnectStartParams @ 157 PQping @ 158 PQpingParams @ 159 PQlibVersion @ 160 RPostgreSQL/src/libpq/libpq.rc.in0000644000176000001440000000145711660061757016407 0ustar ripleyusers#include VS_VERSION_INFO VERSIONINFO FILEVERSION 9,1,1,0 PRODUCTVERSION 9,1,1,0 FILEFLAGSMASK 0x3fL FILEFLAGS 0 FILEOS VOS__WINDOWS32 FILETYPE VFT_DLL FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904B0" BEGIN VALUE "CompanyName", "\0" VALUE "FileDescription", "PostgreSQL Access Library\0" VALUE "FileVersion", "9.1.1\0" VALUE "InternalName", "libpq\0" VALUE "LegalCopyright", "Copyright (C) 2011\0" VALUE "LegalTrademarks", "\0" VALUE "OriginalFilename", "libpq.dll\0" VALUE "ProductName", "PostgreSQL\0" VALUE "ProductVersion", "9.1.1\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1200 END END RPostgreSQL/src/libpq/Makefile.global.darwin0000644000176000001440000005245111663173071020523 0ustar ripleyusers# -*-makefile-*- # src/Makefile.global.in #------------------------------------------------------------------------------ # All PostgreSQL makefiles include this file and use the variables it sets, # which in turn are put here by the configure script. There is no need for # users to edit this file -- if it turns out to be necessary then that's a # bug. # # A makefile that includes this file needs to set the variable `subdir' to # the relative path from the top to itself and `top_builddir' to the relative # path from itself to the top before including this file. (The "top" is the # parent directory of the directory this file is in.) #------------------------------------------------------------------------------ ########################################################################## # # Meta configuration standard_targets = all install installdirs uninstall distprep clean distclean maintainer-clean coverage check installcheck maintainer-check # these targets should recurse even into subdirectories not being built: standard_always_targets = distprep clean distclean maintainer-clean .PHONY: $(standard_targets) install-strip html man installcheck-parallel # make `all' the default target all: # Delete target files if the command fails after it has # started to update the file. .DELETE_ON_ERROR: # PostgreSQL version number VERSION = 9.1.1 MAJORVERSION = 9.1 # Support for VPATH builds vpath_build = no ifneq ($(vpath_build),yes) top_srcdir = $(top_builddir) srcdir = . else # vpath_build = yes top_srcdir = $(abs_top_srcdir) srcdir = $(top_srcdir)/$(subdir) endif vpathsearch = `for f in $(addsuffix /$(1),$(subst :, ,. $(VPATH))); do test -r $$f && echo $$f && break; done` # Saved arguments from configure configure_args = ########################################################################## # # Installation directories # # These are set by the equivalent --xxxdir configure options. We # append "postgresql" to some of them, if the string does not already # contain "pgsql" or "postgres", in order to avoid directory clutter. # # In a PGXS build, we cannot use the values inserted into Makefile.global # by configure, since the installation tree may have been relocated. # Instead get the path values from pg_config. ifndef PGXS # Note that prefix, exec_prefix, and datarootdir aren't defined in a PGXS build; # makefiles may only use the derived variables such as bindir. prefix := /usr/local/pgsql exec_prefix := ${prefix} datarootdir := ${prefix}/share bindir := ${exec_prefix}/bin datadir := ${datarootdir} ifeq "$(findstring pgsql, $(datadir))" "" ifeq "$(findstring postgres, $(datadir))" "" override datadir := $(datadir)/postgresql endif endif sysconfdir := ${prefix}/etc ifeq "$(findstring pgsql, $(sysconfdir))" "" ifeq "$(findstring postgres, $(sysconfdir))" "" override sysconfdir := $(sysconfdir)/postgresql endif endif libdir := ${exec_prefix}/lib pkglibdir = $(libdir) ifeq "$(findstring pgsql, $(pkglibdir))" "" ifeq "$(findstring postgres, $(pkglibdir))" "" override pkglibdir := $(pkglibdir)/postgresql endif endif includedir := ${prefix}/include pkgincludedir = $(includedir) ifeq "$(findstring pgsql, $(pkgincludedir))" "" ifeq "$(findstring postgres, $(pkgincludedir))" "" override pkgincludedir := $(pkgincludedir)/postgresql endif endif mandir := ${datarootdir}/man docdir := ${datarootdir}/doc/${PACKAGE_TARNAME} ifeq "$(findstring pgsql, $(docdir))" "" ifeq "$(findstring postgres, $(docdir))" "" override docdir := $(docdir)/postgresql endif endif htmldir := ${docdir} localedir := ${datarootdir}/locale else # PGXS case # Extension makefiles should set PG_CONFIG, but older ones might not ifndef PG_CONFIG PG_CONFIG = pg_config endif bindir := $(shell $(PG_CONFIG) --bindir) datadir := $(shell $(PG_CONFIG) --sharedir) sysconfdir := $(shell $(PG_CONFIG) --sysconfdir) libdir := $(shell $(PG_CONFIG) --libdir) pkglibdir := $(shell $(PG_CONFIG) --pkglibdir) includedir := $(shell $(PG_CONFIG) --includedir) pkgincludedir := $(shell $(PG_CONFIG) --pkgincludedir) mandir := $(shell $(PG_CONFIG) --mandir) docdir := $(shell $(PG_CONFIG) --docdir) localedir := $(shell $(PG_CONFIG) --localedir) endif # PGXS # These derived path variables aren't separately configurable. includedir_server = $(pkgincludedir)/server includedir_internal = $(pkgincludedir)/internal pgxsdir = $(pkglibdir)/pgxs ########################################################################## # # Features # # Records the choice of the various --enable-xxx and --with-xxx options. with_perl = no with_python = no with_tcl = no with_openssl = no with_ossp_uuid = no with_selinux = no with_libxml = no with_libxslt = no with_system_tzdata = with_zlib = yes enable_shared = yes enable_rpath = yes enable_nls = no enable_debug = no enable_dtrace = no enable_coverage = no enable_thread_safety = yes python_includespec = python_libdir = python_libspec = python_additional_libs = python_configdir = python_majorversion = python_version = krb_srvtab = TCLSH = TCL_LIB_FILE = TCL_LIBS = TCL_LIB_SPEC = TCL_INCLUDE_SPEC = TCL_SHARED_BUILD = TCL_SHLIB_LD_LIBS = PTHREAD_CFLAGS = -Kthread -kthread -pthread -pthreads -D_REENTRANT -D_THREAD_SAFE -D_POSIX_PTHREAD_SEMANTICS PTHREAD_LIBS = -lpthread ########################################################################## # # Programs and flags # Compilers CPP = gcc -E CPPFLAGS = ifdef PGXS override CPPFLAGS := -I$(includedir_server) -I$(includedir_internal) $(CPPFLAGS) else # not PGXS override CPPFLAGS := -I$(top_srcdir)/src/include $(CPPFLAGS) ifdef VPATH override CPPFLAGS := -I$(top_builddir)/src/include $(CPPFLAGS) endif endif # not PGXS CC = gcc GCC = yes SUN_STUDIO_CC = no CFLAGS = -O2 -Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement -Wendif-labels -Wformat-security -fno-strict-aliasing -fwrapv # Kind-of compilers BISON = /usr/bin/bison BISONFLAGS = $(YFLAGS) FLEX = /usr/bin/flex FLEXFLAGS = $(LFLAGS) DTRACE = DTRACEFLAGS = ZIC = # Linking AR = ar DLLTOOL = DLLWRAP = LIBS = -lz -lreadline -lm LDAP_LIBS_FE = LDAP_LIBS_BE = OSSP_UUID_LIBS = #LD = /usr/libexec/gcc/i686-apple-darwin10/4.2.1/ld with_gnu_ld = no ld_R_works = # We want -L for libpgport.a to be first in LDFLAGS. We also need LDFLAGS # to be a "recursively expanded" variable, else adjustments to rpathdir # don't work right. So we must NOT do LDFLAGS := something, meaning this has # to be done first and elsewhere we must only do LDFLAGS += something. ifdef PGXS LDFLAGS = -L$(libdir) else LDFLAGS = -L. endif LDFLAGS += -Wl,-dead_strip_dylibs LDFLAGS_EX = # LDFLAGS_SL might have already been assigned by calling makefile LDFLAGS_SL += LDREL = -r LDOUT = -o RANLIB = ranlib WINDRES = X = # Perl ifneq (/usr/bin/perl,) # quoted to protect pathname with spaces PERL = '/usr/bin/perl' else PERL = $(missing) perl endif perl_archlibexp = perl_privlibexp = perl_useshrplib = perl_embed_ldflags = # Miscellaneous AWK = awk LN_S = ln -s MSGFMT = MSGMERGE = PYTHON = TAR = /usr/bin/tar XGETTEXT = GZIP = gzip BZIP2 = bzip2 # Installation. INSTALL = $(SHELL) $(top_srcdir)/config/install-sh -c INSTALL_SCRIPT_MODE = 755 INSTALL_DATA_MODE = 644 INSTALL_PROGRAM = $(INSTALL_PROGRAM_ENV) $(INSTALL) $(INSTALL_STRIP_FLAG) INSTALL_SCRIPT = $(INSTALL) -m $(INSTALL_SCRIPT_MODE) INSTALL_DATA = $(INSTALL) -m $(INSTALL_DATA_MODE) INSTALL_STLIB = $(INSTALL_STLIB_ENV) $(INSTALL_DATA) $(INSTALL_STRIP_FLAG) INSTALL_SHLIB = $(INSTALL_SHLIB_ENV) $(INSTALL) $(INSTALL_SHLIB_OPTS) $(INSTALL_STRIP_FLAG) # Override in Makefile.port if necessary INSTALL_SHLIB_OPTS = -m 755 MKDIR_P = ${SHELL} ${top_srcdir}/config/install-sh -c -d missing = $(SHELL) $(top_srcdir)/config/missing STRIP = strip STRIP_STATIC_LIB = : STRIP_SHARED_LIB = : # Documentation have_docbook = no COLLATEINDEX = DOCBOOKSTYLE = JADE = NSGMLS = OSX = XSLTPROC = xsltproc # Code coverage GCOV = LCOV = GENHTML = ifeq ($(enable_coverage),yes) # ccache loses .gcno files export CCACHE_DISABLE = 1 endif # Feature settings DEF_PGPORT = 5432 WANTED_LANGUAGES = ########################################################################## # # Additional platform-specific settings # # Name of the "template" PORTNAME= darwin build_os = darwin10.8.0 host_tuple = x86_64-apple-darwin10.8.0 host_os = darwin10.8.0 host_cpu = x86_64 # Make HAVE_IPV6 available for initdb script creation HAVE_IPV6= yes # The HP-UX port makefile, for one, needs access to this symbol HAVE_POSIX_SIGNALS= yes # This is mainly for use on FreeBSD, where we have both a.out and elf # systems now. May be applicable to other systems to? ELF_SYSTEM= # Backend stack size limit has to be hard-wired on Windows (it's in bytes) WIN32_STACK_RLIMIT=4194304 # Set if we have a working win32 crashdump header have_win32_dbghelp = no # Pull in platform-specific magic include Makefile.port.darwin # Set up rpath if enabled. By default it will point to our libdir, # but individual Makefiles can force other rpath paths if needed. rpathdir = $(libdir) ifeq ($(enable_rpath), yes) LDFLAGS += $(rpath) endif ########################################################################## # # Some variables needed to find some client interfaces ifdef PGXS # some contribs assumes headers and libs are in the source tree... libpq_srcdir = $(includedir) libpq_builddir = $(libdir) else libpq_srcdir = $(top_srcdir)/src/interfaces/libpq libpq_builddir = $(top_builddir)/src/interfaces/libpq endif # This macro is for use by libraries linking to libpq. (Because libpgport # isn't created with the same link flags as libpq, it can't be used.) libpq = -L$(libpq_builddir) -lpq # If doing static linking, shared library dependency info isn't available, # so add in the libraries that libpq depends on. ifeq ($(enable_shared), no) libpq += $(filter -lintl -lssl -lcrypto -lkrb5 -lcrypt, $(LIBS)) \ $(LDAP_LIBS_FE) $(PTHREAD_LIBS) endif # This macro is for use by client executables (not libraries) that use libpq. # We force clients to pull symbols from the non-shared library libpgport # rather than pulling some libpgport symbols from libpq just because # libpq uses those functions too. This makes applications less # dependent on changes in libpq's usage of pgport. To do this we link to # pgport before libpq. This does cause duplicate -lpgport's to appear # on client link lines. ifdef PGXS libpq_pgport = -L$(libdir) -lpgport $(libpq) else libpq_pgport = -L$(top_builddir)/src/port -lpgport $(libpq) endif submake-libpq: $(MAKE) -C $(libpq_builddir) all submake-libpgport: $(MAKE) -C $(top_builddir)/src/port all .PHONY: submake-libpq submake-libpgport ########################################################################## # # Testing support PL_TESTDB = pl_regression CONTRIB_TESTDB = contrib_regression ifdef NO_LOCALE NOLOCALE += --no-locale endif pg_regress_locale_flags = $(if $(ENCODING),--encoding=$(ENCODING)) $(NOLOCALE) pg_regress_check = $(top_builddir)/src/test/regress/pg_regress --inputdir=$(srcdir) --temp-install=./tmp_check --top-builddir=$(top_builddir) $(pg_regress_locale_flags) pg_regress_installcheck = $(top_builddir)/src/test/regress/pg_regress --inputdir=$(srcdir) --psqldir='$(PSQLDIR)' $(pg_regress_locale_flags) pg_regress_clean_files = results/ regression.diffs regression.out tmp_check/ log/ ########################################################################## # # Customization # # This includes your local customizations if Makefile.custom exists # in the source directory. This file doesn't exist in the original # distribution so that it doesn't get overwritten when you upgrade. # # NOTE: Makefile.custom is from the pre-Autoconf days of PostgreSQL. # You are liable to shoot yourself in the foot if you use it without # knowing exactly what you're doing. The preferred (and more # reliable) method is to communicate what you want to do to the # configure script, and leave the makefiles alone. -include $(top_srcdir)/src/Makefile.custom ifneq ($(CUSTOM_INSTALL),) INSTALL= $(CUSTOM_INSTALL) endif ifneq ($(CUSTOM_CC),) CC= $(CUSTOM_CC) endif ifneq ($(CUSTOM_COPT),) COPT= $(CUSTOM_COPT) endif ifdef COPT CFLAGS += $(COPT) LDFLAGS += $(COPT) endif ifdef PROFILE CFLAGS += $(PROFILE) LDFLAGS += $(PROFILE) endif ########################################################################## # # substitute implementations of C library routines (see src/port/) # note we already included -L.../src/port in LDFLAGS above LIBOBJS = LIBS := -lpgport $(LIBS) # to make ws2_32.lib the last library, and always link with shfolder, # so SHGetFolderName isn't picked up from shell32.dll ifeq ($(PORTNAME),win32) LIBS += -lws2_32 -lshfolder endif # Not really standard libc functions, used by the backend. TAS = ########################################################################## # # Global targets and rules %.i: %.c $(CPP) $(CPPFLAGS) -o $@ $< %.gz: % $(GZIP) --best -c $< >$@ %.bz2: % $(BZIP2) -c $< >$@ ifndef PGXS # Remake Makefile.global from Makefile.global.in if the latter # changed. In order to trigger this rule, the including file must # write `include $(top_builddir)/src/Makefile.global', not some # shortcut thereof. $(top_builddir)/src/Makefile.global: $(top_srcdir)/src/Makefile.global.in $(top_builddir)/config.status cd $(top_builddir) && ./config.status src/Makefile.global # Remake pg_config.h from pg_config.h.in if the latter changed. # config.status will not change the timestamp on pg_config.h if it # doesn't change, so as to avoid recompiling the entire tree # unnecessarily. Therefore we make config.status update a timestamp file # stamp-h everytime it runs, so that we don't trigger this rule everytime. # (We do trigger the null rule for stamp-h to pg_config.h everytime; so it's # important for that rule to be null!) # # Of course you need to turn on dependency tracking to get any # dependencies on pg_config.h. $(top_builddir)/src/include/pg_config.h: $(top_builddir)/src/include/stamp-h $(top_builddir)/src/include/stamp-h: $(top_srcdir)/src/include/pg_config.h.in $(top_builddir)/config.status cd $(top_builddir) && ./config.status src/include/pg_config.h # Also remake ecpg_config.h from ecpg_config.h.in if the latter changed, same # logic as above. $(top_builddir)/src/interfaces/ecpg/include/ecpg_config.h: $(top_builddir)/src/interfaces/ecpg/include/stamp-h $(top_builddir)/src/interfaces/ecpg/include/stamp-h: $(top_builddir)/src/interfaces/ecpg/include/ecpg_config.h.in $(top_builddir)/config.status cd $(top_builddir) && ./config.status src/interfaces/ecpg/include/ecpg_config.h # When configure changes, rerun configure with the same options as # last time. To change configure, you need to run autoconf manually. $(top_builddir)/config.status: $(top_srcdir)/configure cd $(top_builddir) && ./config.status --recheck endif # not PGXS install-strip: @$(MAKE) INSTALL_PROGRAM_ENV="STRIPPROG='$(STRIP)'" \ INSTALL_STLIB_ENV="STRIPPROG='$(STRIP_STATIC_LIB)'" \ INSTALL_SHLIB_ENV="STRIPPROG='$(STRIP_SHARED_LIB)'" \ INSTALL_STRIP_FLAG=-s \ install ########################################################################## # # Recursive make support # ---------------------- # Instead of recursing through subdirectories with a for loop or # repeated $(MAKE) -C whatever calls, this is a little smarter: it # allows parallel make across directories and lets make -k and -q work # correctly. # We need the $(eval) function and order-only prerequisites, which are # available in GNU make 3.80. That also happens to be the version # where the .VARIABLES variable was introduced, so this is a simple check. ifndef .VARIABLES $(error GNU make 3.80 or newer is required. You are using version $(MAKE_VERSION)) endif # This function is only for internal use below. It should be called # using $(eval). It will set up a target so that it recurses into # a given subdirectory. Note that to avoid a nasty bug in make 3.80, # this function has to avoid using any complicated constructs (like # multiple targets on a line) and also not contain any lines that expand # to more than about 200 bytes. This is why we make it apply to just one # subdirectory at a time, rather than to a list of subdirectories. # $1: target name, e.g., all # $2: subdir name # $3: target to run in subdir, usually same as $1 define _create_recursive_target .PHONY: $(1)-$(2)-recurse $(1): $(1)-$(2)-recurse $(1)-$(2)-recurse: $$(MAKE) -C $(2) $(3) endef # Note that the use of $$ on the last line above is important; we want # $(MAKE) to be evaluated when the rule is run, not when the $(eval) is run # to create the rule. This is necessary to get make -q working. # Call this function in a makefile that needs to recurse into subdirectories. # In the normal case all arguments can be defaulted. # $1: targets to make recursive (defaults to list of standard targets) # $2: list of subdirs (defaults to SUBDIRS variable) # $3: target to run in subdir (defaults to current element of $1) recurse = $(foreach target,$(if $1,$1,$(standard_targets)),$(foreach subdir,$(if $2,$2,$(SUBDIRS)),$(eval $(call _create_recursive_target,$(target),$(subdir),$(if $3,$3,$(target)))))) # If a makefile's list of SUBDIRS varies depending on configuration, then # any subdirectories excluded from SUBDIRS should instead be added to # ALWAYS_SUBDIRS, and then it must call recurse_always as well as recurse. # This ensures that distprep, distclean, etc will apply to all subdirectories. # In the normal case all arguments will be defaulted. # $1: targets to make recursive (defaults to standard_always_targets) # $2: list of subdirs (defaults to ALWAYS_SUBDIRS variable) # $3: target to run in subdir (defaults to current element of $1) recurse_always = $(foreach target,$(if $1,$1,$(standard_always_targets)),$(foreach subdir,$(if $2,$2,$(ALWAYS_SUBDIRS)),$(eval $(call _create_recursive_target,$(target),$(subdir),$(if $3,$3,$(target)))))) ########################################################################## # # Automatic dependency generation # ------------------------------- # When we configure with --enable-depend then we override the default # compilation rule with the magic below. While or after creating the # actual output file we also create a dependency list for the .c file. # Next time we invoke make we will have top-notch information about # whether this file needs to be updated. The dependency files are kept # in the .deps subdirectory of each directory. autodepend = ifeq ($(autodepend), yes) ifndef COMPILE.c COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) -c endif DEPDIR = .deps ifeq ($(GCC), yes) # GCC allows us to create object and dependency file in one invocation. %.o : %.c @if test ! -d $(DEPDIR); then mkdir -p $(DEPDIR); fi $(COMPILE.c) -o $@ $< -MMD -MP -MF $(DEPDIR)/$(*F).Po endif # GCC # Include all the dependency files generated for the current # directory. List /dev/null as dummy because if the wildcard expands # to nothing then make would complain. -include $(wildcard $(DEPDIR)/*.Po) /dev/null # hook for clean-up clean distclean maintainer-clean: clean-deps .PHONY: clean-deps clean-deps: @rm -rf $(DEPDIR) # When in automatic dependency mode, never delete any intermediate # files automatically. Otherwise, the following could happen: When # starting from a clean source tree, the first build would delete the # intermediate file, but also create the dependency file, which # mentions the intermediate file, thus making it non-intermediate. # The second build will then need to rebuild the now non-intermediate # missing file. So the second build will do work even though nothing # had changed. One place where this happens is the .c -> .o -> .so # chain for some contrib modules. .SECONDARY: endif # autodepend ########################################################################## # # Native language support ifeq ($(enable_nls), yes) ifneq (,$(wildcard $(srcdir)/nls.mk)) include $(top_srcdir)/src/nls-global.mk endif # nls.mk endif # enable_nls ########################################################################## # # Coverage # Explanation of involved files: # foo.c source file # foo.o object file # foo.gcno gcov graph (a.k.a. "notes") file, created at compile time # (by gcc -ftest-coverage) # foo.gcda gcov data file, created when the program is run (for # programs compiled with gcc -fprofile-arcs) # foo.c.gcov gcov output file with coverage information, created by # gcov from foo.gcda (by "make coverage") # foo.c.gcov.out stdout captured when foo.c.gcov is created, mildly # interesting # lcov.info lcov tracefile, built from gcda files in one directory, # later collected by "make coverage-html" ifeq ($(enable_coverage), yes) # There is a strange interaction between lcov and existing .gcov # output files. Hence the rm command and the ordering dependency. gcda_files := $(wildcard *.gcda) lcov.info: $(gcda_files) rm -f *.gcov $(if $^,$(LCOV) -d . -c -o $@ $(LCOVFLAGS)) %.c.gcov: %.gcda | lcov.info $(GCOV) -b -f -p -o . $(GCOVFLAGS) $*.c >$*.c.gcov.out coverage: $(gcda_files:.gcda=.c.gcov) lcov.info .PHONY: coverage-html coverage-html: coverage rm -rf coverage mkdir coverage $(GENHTML) --show-details --legend --output-directory=coverage --title=PostgreSQL --num-spaces=4 --prefix=$(abs_top_srcdir) `find . -name lcov.info -print` # hook for clean-up clean distclean maintainer-clean: clean-coverage .PHONY: clean-coverage clean-coverage: rm -rf coverage rm -f *.gcda *.gcno lcov.info *.gcov *.gcov.out # User-callable target to reset counts between test runs coverage-clean: rm -f `find . -name '*.gcda' -print` endif # enable_coverage RPostgreSQL/src/libpq/libpq-events.h0000644000176000001440000000424312124517222017110 0ustar ripleyusers/*------------------------------------------------------------------------- * * libpq-events.h * This file contains definitions that are useful to applications * that invoke the libpq "events" API, but are not interesting to * ordinary users of libpq. * * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/interfaces/libpq/libpq-events.h * *------------------------------------------------------------------------- */ #ifndef LIBPQ_EVENTS_H #define LIBPQ_EVENTS_H #include "libpq-fe.h" #ifdef __cplusplus extern "C" { #endif /* Callback Event Ids */ typedef enum { PGEVT_REGISTER, PGEVT_CONNRESET, PGEVT_CONNDESTROY, PGEVT_RESULTCREATE, PGEVT_RESULTCOPY, PGEVT_RESULTDESTROY } PGEventId; typedef struct { PGconn *conn; } PGEventRegister; typedef struct { PGconn *conn; } PGEventConnReset; typedef struct { PGconn *conn; } PGEventConnDestroy; typedef struct { PGconn *conn; PGresult *result; } PGEventResultCreate; typedef struct { const PGresult *src; PGresult *dest; } PGEventResultCopy; typedef struct { PGresult *result; } PGEventResultDestroy; typedef int (*PGEventProc) (PGEventId evtId, void *evtInfo, void *passThrough); /* Registers an event proc with the given PGconn. */ extern int PQregisterEventProc(PGconn *conn, PGEventProc proc, const char *name, void *passThrough); /* Sets the PGconn instance data for the provided proc to data. */ extern int PQsetInstanceData(PGconn *conn, PGEventProc proc, void *data); /* Gets the PGconn instance data for the provided proc. */ extern void *PQinstanceData(const PGconn *conn, PGEventProc proc); /* Sets the PGresult instance data for the provided proc to data. */ extern int PQresultSetInstanceData(PGresult *result, PGEventProc proc, void *data); /* Gets the PGresult instance data for the provided proc. */ extern void *PQresultInstanceData(const PGresult *result, PGEventProc proc); /* Fires RESULTCREATE events for an application-created PGresult. */ extern int PQfireResultCreateEvents(PGconn *conn, PGresult *res); #ifdef __cplusplus } #endif #endif /* LIBPQ_EVENTS_H */ RPostgreSQL/src/libpq/libpq.rc0000644000176000001440000000146711660061757016003 0ustar ripleyusers#include VS_VERSION_INFO VERSIONINFO FILEVERSION 9,1,1,11316 PRODUCTVERSION 9,1,1,11316 FILEFLAGSMASK 0x3fL FILEFLAGS 0 FILEOS VOS__WINDOWS32 FILETYPE VFT_DLL FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904B0" BEGIN VALUE "CompanyName", "\0" VALUE "FileDescription", "PostgreSQL Access Library\0" VALUE "FileVersion", "9.1.1\0" VALUE "InternalName", "libpq\0" VALUE "LegalCopyright", "Copyright (C) 2011\0" VALUE "LegalTrademarks", "\0" VALUE "OriginalFilename", "libpq.dll\0" VALUE "ProductName", "PostgreSQL\0" VALUE "ProductVersion", "9.1.1\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1200 END END RPostgreSQL/src/libpq/noblock.c0000644000176000001440000000214312124517222016116 0ustar ripleyusers/*------------------------------------------------------------------------- * * noblock.c * set a file descriptor as non-blocking * * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION * src/port/noblock.c * *------------------------------------------------------------------------- */ #include "c.h" #include bool pg_set_noblock(pgsocket sock) { #if !defined(WIN32) return (fcntl(sock, F_SETFL, O_NONBLOCK) != -1); #else unsigned long ioctlsocket_ret = 1; /* Returns non-0 on failure, while fcntl() returns -1 on failure */ return (ioctlsocket(sock, FIONBIO, &ioctlsocket_ret) == 0); #endif } bool pg_set_block(pgsocket sock) { #if !defined(WIN32) int flags; flags = fcntl(sock, F_GETFL); if (flags < 0 || fcntl(sock, F_SETFL, (long) (flags & ~O_NONBLOCK))) return false; return true; #else unsigned long ioctlsocket_ret = 0; /* Returns non-0 on failure, while fcntl() returns -1 on failure */ return (ioctlsocket(sock, FIONBIO, &ioctlsocket_ret) == 0); #endif } RPostgreSQL/src/libpq/pg_config_manual.h0000644000176000001440000001752012124517222017771 0ustar ripleyusers/*------------------------------------------------------------------------ * PostgreSQL manual configuration settings * * This file contains various configuration symbols and limits. In * all cases, changing them is only useful in very rare situations or * for developers. If you edit any of these, be sure to do a *full* * rebuild (and an initdb if noted). * * src/include/pg_config_manual.h *------------------------------------------------------------------------ */ /* * Maximum length for identifiers (e.g. table names, column names, * function names). Names actually are limited to one less byte than this, * because the length must include a trailing zero byte. * * Changing this requires an initdb. */ #define NAMEDATALEN 64 /* * Maximum number of arguments to a function. * * The minimum value is 9 (index cost estimation uses 9-argument functions). * The maximum possible value is around 600 (limited by index tuple size in * pg_proc's index; BLCKSZ larger than 8K would allow more). Values larger * than needed will waste memory and processing time, but do not directly * cost disk space. * * Changing this does not require an initdb, but it does require a full * backend recompile (including any user-defined C functions). */ #define FUNC_MAX_ARGS 100 /* * Maximum number of columns in an index. There is little point in making * this anything but a multiple of 32, because the main cost is associated * with index tuple header size (see access/itup.h). * * Changing this requires an initdb. */ #define INDEX_MAX_KEYS 32 /* * Set the upper and lower bounds of sequence values. */ #define SEQ_MAXVALUE INT64CONST(0x7FFFFFFFFFFFFFFF) #define SEQ_MINVALUE (-SEQ_MAXVALUE) /* * Number of spare LWLocks to allocate for user-defined add-on code. */ #define NUM_USER_DEFINED_LWLOCKS 4 /* * Define this if you want to allow the lo_import and lo_export SQL * functions to be executed by ordinary users. By default these * functions are only available to the Postgres superuser. CAUTION: * These functions are SECURITY HOLES since they can read and write * any file that the PostgreSQL server has permission to access. If * you turn this on, don't say we didn't warn you. */ /* #define ALLOW_DANGEROUS_LO_FUNCTIONS */ /* * MAXPGPATH: standard size of a pathname buffer in PostgreSQL (hence, * maximum usable pathname length is one less). * * We'd use a standard system header symbol for this, if there weren't * so many to choose from: MAXPATHLEN, MAX_PATH, PATH_MAX are all * defined by different "standards", and often have different values * on the same platform! So we just punt and use a reasonably * generous setting here. */ #define MAXPGPATH 1024 /* * PG_SOMAXCONN: maximum accept-queue length limit passed to * listen(2). You'd think we should use SOMAXCONN from * , but on many systems that symbol is much smaller * than the kernel's actual limit. In any case, this symbol need be * twiddled only if you have a kernel that refuses large limit values, * rather than silently reducing the value to what it can handle * (which is what most if not all Unixen do). */ #define PG_SOMAXCONN 10000 /* * You can try changing this if you have a machine with bytes of * another size, but no guarantee... */ #define BITS_PER_BYTE 8 /* * Preferred alignment for disk I/O buffers. On some CPUs, copies between * user space and kernel space are significantly faster if the user buffer * is aligned on a larger-than-MAXALIGN boundary. Ideally this should be * a platform-dependent value, but for now we just hard-wire it. */ #define ALIGNOF_BUFFER 32 /* * Disable UNIX sockets for certain operating systems. */ #if defined(WIN32) #undef HAVE_UNIX_SOCKETS #endif /* * Define this if your operating system supports link() */ #if !defined(WIN32) && !defined(__CYGWIN__) #define HAVE_WORKING_LINK 1 #endif /* * USE_POSIX_FADVISE controls whether Postgres will attempt to use the * posix_fadvise() kernel call. Usually the automatic configure tests are * sufficient, but some older Linux distributions had broken versions of * posix_fadvise(). If necessary you can remove the #define here. */ #if HAVE_DECL_POSIX_FADVISE && defined(HAVE_POSIX_FADVISE) #define USE_POSIX_FADVISE #endif /* * USE_PREFETCH code should be compiled only if we have a way to implement * prefetching. (This is decoupled from USE_POSIX_FADVISE because there * might in future be support for alternative low-level prefetch APIs.) */ #ifdef USE_POSIX_FADVISE #define USE_PREFETCH #endif /* * This is the default directory in which AF_UNIX socket files are * placed. Caution: changing this risks breaking your existing client * applications, which are likely to continue to look in the old * directory. But if you just hate the idea of sockets in /tmp, * here's where to twiddle it. You can also override this at runtime * with the postmaster's -k switch. */ #define DEFAULT_PGSOCKET_DIR "/tmp" /* * The random() function is expected to yield values between 0 and * MAX_RANDOM_VALUE. Currently, all known implementations yield * 0..2^31-1, so we just hardwire this constant. We could do a * configure test if it proves to be necessary. CAUTION: Think not to * replace this with RAND_MAX. RAND_MAX defines the maximum value of * the older rand() function, which is often different from --- and * considerably inferior to --- random(). */ #define MAX_RANDOM_VALUE (0x7FFFFFFF) /* * Set the format style used by gcc to check printf type functions. We really * want the "gnu_printf" style set, which includes what glibc uses, such * as %m for error strings and %lld for 64 bit long longs. But not all gcc * compilers are known to support it, so we just use "printf" which all * gcc versions alive are known to support, except on Windows where * using "gnu_printf" style makes a dramatic difference. Maybe someday * we'll have a configure test for this, if we ever discover use of more * variants to be necessary. */ #ifdef WIN32 #define PG_PRINTF_ATTRIBUTE gnu_printf #else #define PG_PRINTF_ATTRIBUTE printf #endif /* *------------------------------------------------------------------------ * The following symbols are for enabling debugging code, not for * controlling user-visible features or resource limits. *------------------------------------------------------------------------ */ /* * Define this to cause pfree()'d memory to be cleared immediately, to * facilitate catching bugs that refer to already-freed values. * Right now, this gets defined automatically if --enable-cassert. */ #ifdef USE_ASSERT_CHECKING #define CLOBBER_FREED_MEMORY #endif /* * Define this to check memory allocation errors (scribbling on more * bytes than were allocated). Right now, this gets defined * automatically if --enable-cassert. */ #ifdef USE_ASSERT_CHECKING #define MEMORY_CONTEXT_CHECKING #endif /* * Define this to cause palloc()'d memory to be filled with random data, to * facilitate catching code that depends on the contents of uninitialized * memory. Caution: this is horrendously expensive. */ /* #define RANDOMIZE_ALLOCATED_MEMORY */ /* * Define this to force all parse and plan trees to be passed through * copyObject(), to facilitate catching errors and omissions in * copyObject(). */ /* #define COPY_PARSE_PLAN_TREES */ /* * Enable debugging print statements for lock-related operations. */ /* #define LOCK_DEBUG */ /* * Enable debugging print statements for WAL-related operations; see * also the wal_debug GUC var. */ #define WAL_DEBUG /* * Enable tracing of resource consumption during sort operations; * see also the trace_sort GUC var. For 8.1 this is enabled by default. */ #define TRACE_SORT 1 /* * Enable tracing of syncscan operations (see also the trace_syncscan GUC var). */ /* #define TRACE_SYNCSCAN */ /* * Other debug #defines (documentation, anyone?) */ /* #define HEAPDEBUGALL */ /* #define ACLDEBUG */ /* #define RTDEBUG */ RPostgreSQL/src/libpq/open.c0000644000176000001440000001011712124517222015430 0ustar ripleyusers/*------------------------------------------------------------------------- * * open.c * Win32 open() replacement * * * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * * src/port/open.c * *------------------------------------------------------------------------- */ #ifdef WIN32 #ifndef FRONTEND #include "postgres.h" #else #include "postgres_fe.h" #endif #include #include #include static int openFlagsToCreateFileFlags(int openFlags) { switch (openFlags & (O_CREAT | O_TRUNC | O_EXCL)) { /* O_EXCL is meaningless without O_CREAT */ case 0: case O_EXCL: return OPEN_EXISTING; case O_CREAT: return OPEN_ALWAYS; /* O_EXCL is meaningless without O_CREAT */ case O_TRUNC: case O_TRUNC | O_EXCL: return TRUNCATE_EXISTING; case O_CREAT | O_TRUNC: return CREATE_ALWAYS; /* O_TRUNC is meaningless with O_CREAT */ case O_CREAT | O_EXCL: case O_CREAT | O_TRUNC | O_EXCL: return CREATE_NEW; } /* will never get here */ return 0; } /* * - file attribute setting, based on fileMode? */ int pgwin32_open(const char *fileName, int fileFlags,...) { int fd; HANDLE h = INVALID_HANDLE_VALUE; SECURITY_ATTRIBUTES sa; int loops = 0; /* Check that we can handle the request */ assert((fileFlags & ((O_RDONLY | O_WRONLY | O_RDWR) | O_APPEND | (O_RANDOM | O_SEQUENTIAL | O_TEMPORARY) | _O_SHORT_LIVED | O_DSYNC | O_DIRECT | (O_CREAT | O_TRUNC | O_EXCL) | (O_TEXT | O_BINARY))) == fileFlags); sa.nLength = sizeof(sa); sa.bInheritHandle = TRUE; sa.lpSecurityDescriptor = NULL; while ((h = CreateFile(fileName, /* cannot use O_RDONLY, as it == 0 */ (fileFlags & O_RDWR) ? (GENERIC_WRITE | GENERIC_READ) : ((fileFlags & O_WRONLY) ? GENERIC_WRITE : GENERIC_READ), /* These flags allow concurrent rename/unlink */ (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE), &sa, openFlagsToCreateFileFlags(fileFlags), FILE_ATTRIBUTE_NORMAL | ((fileFlags & O_RANDOM) ? FILE_FLAG_RANDOM_ACCESS : 0) | ((fileFlags & O_SEQUENTIAL) ? FILE_FLAG_SEQUENTIAL_SCAN : 0) | ((fileFlags & _O_SHORT_LIVED) ? FILE_ATTRIBUTE_TEMPORARY : 0) | ((fileFlags & O_TEMPORARY) ? FILE_FLAG_DELETE_ON_CLOSE : 0) | ((fileFlags & O_DIRECT) ? FILE_FLAG_NO_BUFFERING : 0) | ((fileFlags & O_DSYNC) ? FILE_FLAG_WRITE_THROUGH : 0), NULL)) == INVALID_HANDLE_VALUE) { /* * Sharing violation or locking error can indicate antivirus, backup * or similar software that's locking the file. Try again for 30 * seconds before giving up. */ DWORD err = GetLastError(); if (err == ERROR_SHARING_VIOLATION || err == ERROR_LOCK_VIOLATION) { pg_usleep(100000); loops++; #ifndef FRONTEND if (loops == 50) ereport(LOG, (errmsg("could not open file \"%s\": %s", fileName, (err == ERROR_SHARING_VIOLATION) ? _("sharing violation") : _("lock violation")), errdetail("Continuing to retry for 30 seconds."), errhint("You might have antivirus, backup, or similar software interfering with the database system."))); #endif if (loops < 300) continue; } _dosmaperr(err); return -1; } /* _open_osfhandle will, on error, set errno accordingly */ if ((fd = _open_osfhandle((intptr_t) h, fileFlags & O_APPEND)) < 0) CloseHandle(h); /* will not affect errno */ else if (fileFlags & (O_TEXT | O_BINARY) && _setmode(fd, fileFlags & (O_TEXT | O_BINARY)) < 0) { _close(fd); return -1; } return fd; } FILE * pgwin32_fopen(const char *fileName, const char *mode) { int openmode = 0; int fd; if (strstr(mode, "r+")) openmode |= O_RDWR; else if (strchr(mode, 'r')) openmode |= O_RDONLY; if (strstr(mode, "w+")) openmode |= O_RDWR | O_CREAT | O_TRUNC; else if (strchr(mode, 'w')) openmode |= O_WRONLY | O_CREAT | O_TRUNC; if (strchr(mode, 'a')) openmode |= O_WRONLY | O_CREAT | O_APPEND; if (strchr(mode, 'b')) openmode |= O_BINARY; if (strchr(mode, 't')) openmode |= O_TEXT; fd = pgwin32_open(fileName, openmode); if (fd == -1) return NULL; return _fdopen(fd, mode); } #endif RPostgreSQL/src/libpq/fe-connect.c0000644000176000001440000036344612124517222016530 0ustar ripleyusers/*------------------------------------------------------------------------- * * fe-connect.c * functions related to setting up a connection to the backend * * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * src/interfaces/libpq/fe-connect.c * *------------------------------------------------------------------------- */ #include "postgres_fe.h" #include #include #include #include #include #include #include "libpq-fe.h" #include "libpq-int.h" #include "fe-auth.h" #include "pg_config_paths.h" #ifdef WIN32 #include "win32.h" #ifdef _WIN32_IE #undef _WIN32_IE #endif #define _WIN32_IE 0x0500 #ifdef near #undef near #endif #define near #include #ifdef WIN32_ONLY_COMPILER /* mstcpip.h is missing on mingw */ #include #endif #else #include #include #include #ifdef HAVE_NETINET_TCP_H #include #endif #include #endif #ifdef ENABLE_THREAD_SAFETY #ifdef WIN32 #include "pthread-win32.h" #else #include #endif #endif #ifdef USE_LDAP #ifdef WIN32 #include #else /* OpenLDAP deprecates RFC 1823, but we want standard conformance */ #define LDAP_DEPRECATED 1 #include typedef struct timeval LDAP_TIMEVAL; #endif static int ldapServiceLookup(const char *purl, PQconninfoOption *options, PQExpBuffer errorMessage); #endif #include "libpq/ip.h" #include "mb/pg_wchar.h" #ifndef FD_CLOEXEC #define FD_CLOEXEC 1 #endif #ifndef WIN32 #define PGPASSFILE ".pgpass" #else #define PGPASSFILE "pgpass.conf" #endif /* * Pre-9.0 servers will return this SQLSTATE if asked to set * application_name in a startup packet. We hard-wire the value rather * than looking into errcodes.h since it reflects historical behavior * rather than that of the current code. */ #define ERRCODE_APPNAME_UNKNOWN "42704" /* This is part of the protocol so just define it */ #define ERRCODE_INVALID_PASSWORD "28P01" /* This too */ #define ERRCODE_CANNOT_CONNECT_NOW "57P03" /* * fall back options if they are not specified by arguments or defined * by environment variables */ #define DefaultHost "localhost" #define DefaultTty "" #define DefaultOption "" #define DefaultAuthtype "" #define DefaultPassword "" #ifdef USE_SSL #define DefaultSSLMode "prefer" #else #define DefaultSSLMode "disable" #endif /* ---------- * Definition of the conninfo parameters and their fallback resources. * * If Environment-Var and Compiled-in are specified as NULL, no * fallback is available. If after all no value can be determined * for an option, an error is returned. * * The value for the username is treated specially in conninfo_parse. * If the Compiled-in resource is specified as a NULL value, the * user is determined by pg_fe_getauthname(). * * The Label and Disp-Char entries are provided for applications that * want to use PQconndefaults() to create a generic database connection * dialog. Disp-Char is defined as follows: * "" Normal input field * "*" Password field - hide value * "D" Debug option - don't show by default * * PQconninfoOptions[] is a constant static array that we use to initialize * a dynamically allocated working copy. All the "val" fields in * PQconninfoOptions[] *must* be NULL. In a working copy, non-null "val" * fields point to malloc'd strings that should be freed when the working * array is freed (see PQconninfoFree). * ---------- */ static const PQconninfoOption PQconninfoOptions[] = { /* * "authtype" is no longer used, so mark it "don't show". We keep it in * the array so as not to reject conninfo strings from old apps that might * still try to set it. */ {"authtype", "PGAUTHTYPE", DefaultAuthtype, NULL, "Database-Authtype", "D", 20}, {"service", "PGSERVICE", NULL, NULL, "Database-Service", "", 20}, {"user", "PGUSER", NULL, NULL, "Database-User", "", 20}, {"password", "PGPASSWORD", NULL, NULL, "Database-Password", "*", 20}, {"connect_timeout", "PGCONNECT_TIMEOUT", NULL, NULL, "Connect-timeout", "", 10}, /* strlen(INT32_MAX) == 10 */ {"dbname", "PGDATABASE", NULL, NULL, "Database-Name", "", 20}, {"host", "PGHOST", NULL, NULL, "Database-Host", "", 40}, {"hostaddr", "PGHOSTADDR", NULL, NULL, "Database-Host-IP-Address", "", 45}, {"port", "PGPORT", DEF_PGPORT_STR, NULL, "Database-Port", "", 6}, {"client_encoding", "PGCLIENTENCODING", NULL, NULL, "Client-Encoding", "", 10}, /* * "tty" is no longer used either, but keep it present for backwards * compatibility. */ {"tty", "PGTTY", DefaultTty, NULL, "Backend-Debug-TTY", "D", 40}, {"options", "PGOPTIONS", DefaultOption, NULL, "Backend-Debug-Options", "D", 40}, {"application_name", "PGAPPNAME", NULL, NULL, "Application-Name", "", 64}, {"fallback_application_name", NULL, NULL, NULL, "Fallback-Application-Name", "", 64}, {"keepalives", NULL, NULL, NULL, "TCP-Keepalives", "", 1}, /* should be just '0' or '1' */ {"keepalives_idle", NULL, NULL, NULL, "TCP-Keepalives-Idle", "", 10}, /* strlen(INT32_MAX) == 10 */ {"keepalives_interval", NULL, NULL, NULL, "TCP-Keepalives-Interval", "", 10}, /* strlen(INT32_MAX) == 10 */ {"keepalives_count", NULL, NULL, NULL, "TCP-Keepalives-Count", "", 10}, /* strlen(INT32_MAX) == 10 */ #ifdef USE_SSL /* * "requiressl" is deprecated, its purpose having been taken over by * "sslmode". It remains for backwards compatibility. */ {"requiressl", "PGREQUIRESSL", "0", NULL, "Require-SSL", "D", 1}, #endif /* * ssl options are allowed even without client SSL support because the * client can still handle SSL modes "disable" and "allow". Other * parameters have no effect on non-SSL connections, so there is no reason * to exclude them since none of them are mandatory. */ {"sslmode", "PGSSLMODE", DefaultSSLMode, NULL, "SSL-Mode", "", 8}, /* sizeof("disable") == 8 */ {"sslcert", "PGSSLCERT", NULL, NULL, "SSL-Client-Cert", "", 64}, {"sslkey", "PGSSLKEY", NULL, NULL, "SSL-Client-Key", "", 64}, {"sslrootcert", "PGSSLROOTCERT", NULL, NULL, "SSL-Root-Certificate", "", 64}, {"sslcrl", "PGSSLCRL", NULL, NULL, "SSL-Revocation-List", "", 64}, {"requirepeer", "PGREQUIREPEER", NULL, NULL, "Require-Peer", "", 10}, #if defined(KRB5) || defined(ENABLE_GSS) || defined(ENABLE_SSPI) /* Kerberos and GSSAPI authentication support specifying the service name */ {"krbsrvname", "PGKRBSRVNAME", PG_KRB_SRVNAM, NULL, "Kerberos-service-name", "", 20}, #endif #if defined(ENABLE_GSS) && defined(ENABLE_SSPI) /* * GSSAPI and SSPI both enabled, give a way to override which is used by * default */ {"gsslib", "PGGSSLIB", NULL, NULL, "GSS-library", "", 7}, /* sizeof("gssapi") = 7 */ #endif {"replication", NULL, NULL, NULL, "Replication", "D", 5}, /* Terminating entry --- MUST BE LAST */ {NULL, NULL, NULL, NULL, NULL, NULL, 0} }; static const PQEnvironmentOption EnvironmentOptions[] = { /* common user-interface settings */ { "PGDATESTYLE", "datestyle" }, { "PGTZ", "timezone" }, /* internal performance-related settings */ { "PGGEQO", "geqo" }, { NULL, NULL } }; static bool connectOptions1(PGconn *conn, const char *conninfo); static bool connectOptions2(PGconn *conn); static int connectDBStart(PGconn *conn); static int connectDBComplete(PGconn *conn); static PGPing internal_ping(PGconn *conn); static PGconn *makeEmptyPGconn(void); static void fillPGconn(PGconn *conn, PQconninfoOption *connOptions); static void freePGconn(PGconn *conn); static void closePGconn(PGconn *conn); static PQconninfoOption *conninfo_parse(const char *conninfo, PQExpBuffer errorMessage, bool use_defaults); static PQconninfoOption *conninfo_array_parse(const char **keywords, const char **values, PQExpBuffer errorMessage, bool use_defaults, int expand_dbname); static char *conninfo_getval(PQconninfoOption *connOptions, const char *keyword); static void defaultNoticeReceiver(void *arg, const PGresult *res); static void defaultNoticeProcessor(void *arg, const char *message); static int parseServiceInfo(PQconninfoOption *options, PQExpBuffer errorMessage); static int parseServiceFile(const char *serviceFile, const char *service, PQconninfoOption *options, PQExpBuffer errorMessage, bool *group_found); static char *pwdfMatchesString(char *buf, char *token); static char *PasswordFromFile(char *hostname, char *port, char *dbname, char *username); static bool getPgPassFilename(char *pgpassfile); static void dot_pg_pass_warning(PGconn *conn); static void default_threadlock(int acquire); /* global variable because fe-auth.c needs to access it */ pgthreadlock_t pg_g_threadlock = default_threadlock; /* * Connecting to a Database * * There are now six different ways a user of this API can connect to the * database. Two are not recommended for use in new code, because of their * lack of extensibility with respect to the passing of options to the * backend. These are PQsetdb and PQsetdbLogin (the former now being a macro * to the latter). * * If it is desired to connect in a synchronous (blocking) manner, use the * function PQconnectdb or PQconnectdbParams. The former accepts a string * of option = value pairs which must be parsed; the latter takes two NULL * terminated arrays instead. * * To connect in an asynchronous (non-blocking) manner, use the functions * PQconnectStart or PQconnectStartParams (which differ in the same way as * PQconnectdb and PQconnectdbParams) and PQconnectPoll. * * Internally, the static functions connectDBStart, connectDBComplete * are part of the connection procedure. */ /* * PQconnectdbParams * * establishes a connection to a postgres backend through the postmaster * using connection information in two arrays. * * The keywords array is defined as * * const char *params[] = {"option1", "option2", NULL} * * The values array is defined as * * const char *values[] = {"value1", "value2", NULL} * * Returns a PGconn* which is needed for all subsequent libpq calls, or NULL * if a memory allocation failed. * If the status field of the connection returned is CONNECTION_BAD, * then some fields may be null'ed out instead of having valid values. * * You should call PQfinish (if conn is not NULL) regardless of whether this * call succeeded. */ PGconn * PQconnectdbParams(const char **keywords, const char **values, int expand_dbname) { PGconn *conn = PQconnectStartParams(keywords, values, expand_dbname); if (conn && conn->status != CONNECTION_BAD) (void) connectDBComplete(conn); return conn; } /* * PQpingParams * * check server status, accepting parameters identical to PQconnectdbParams */ PGPing PQpingParams(const char **keywords, const char **values, int expand_dbname) { PGconn *conn = PQconnectStartParams(keywords, values, expand_dbname); PGPing ret; ret = internal_ping(conn); PQfinish(conn); return ret; } /* * PQconnectdb * * establishes a connection to a postgres backend through the postmaster * using connection information in a string. * * The conninfo string is a white-separated list of * * option = value * * definitions. Value might be a single value containing no whitespaces or * a single quoted string. If a single quote should appear anywhere in * the value, it must be escaped with a backslash like \' * * Returns a PGconn* which is needed for all subsequent libpq calls, or NULL * if a memory allocation failed. * If the status field of the connection returned is CONNECTION_BAD, * then some fields may be null'ed out instead of having valid values. * * You should call PQfinish (if conn is not NULL) regardless of whether this * call succeeded. */ PGconn * PQconnectdb(const char *conninfo) { PGconn *conn = PQconnectStart(conninfo); if (conn && conn->status != CONNECTION_BAD) (void) connectDBComplete(conn); return conn; } /* * PQping * * check server status, accepting parameters identical to PQconnectdb */ PGPing PQping(const char *conninfo) { PGconn *conn = PQconnectStart(conninfo); PGPing ret; ret = internal_ping(conn); PQfinish(conn); return ret; } /* * PQconnectStartParams * * Begins the establishment of a connection to a postgres backend through the * postmaster using connection information in a struct. * * See comment for PQconnectdbParams for the definition of the string format. * * Returns a PGconn*. If NULL is returned, a malloc error has occurred, and * you should not attempt to proceed with this connection. If the status * field of the connection returned is CONNECTION_BAD, an error has * occurred. In this case you should call PQfinish on the result, (perhaps * inspecting the error message first). Other fields of the structure may not * be valid if that occurs. If the status field is not CONNECTION_BAD, then * this stage has succeeded - call PQconnectPoll, using select(2) to see when * this is necessary. * * See PQconnectPoll for more info. */ PGconn * PQconnectStartParams(const char **keywords, const char **values, int expand_dbname) { PGconn *conn; PQconninfoOption *connOptions; /* * Allocate memory for the conn structure */ conn = makeEmptyPGconn(); if (conn == NULL) return NULL; /* * Parse the conninfo arrays */ connOptions = conninfo_array_parse(keywords, values, &conn->errorMessage, true, expand_dbname); if (connOptions == NULL) { conn->status = CONNECTION_BAD; /* errorMessage is already set */ return conn; } /* * Move option values into conn structure */ fillPGconn(conn, connOptions); /* * Free the option info - all is in conn now */ PQconninfoFree(connOptions); /* * Compute derived options */ if (!connectOptions2(conn)) return conn; /* * Connect to the database */ if (!connectDBStart(conn)) { /* Just in case we failed to set it in connectDBStart */ conn->status = CONNECTION_BAD; } return conn; } /* * PQconnectStart * * Begins the establishment of a connection to a postgres backend through the * postmaster using connection information in a string. * * See comment for PQconnectdb for the definition of the string format. * * Returns a PGconn*. If NULL is returned, a malloc error has occurred, and * you should not attempt to proceed with this connection. If the status * field of the connection returned is CONNECTION_BAD, an error has * occurred. In this case you should call PQfinish on the result, (perhaps * inspecting the error message first). Other fields of the structure may not * be valid if that occurs. If the status field is not CONNECTION_BAD, then * this stage has succeeded - call PQconnectPoll, using select(2) to see when * this is necessary. * * See PQconnectPoll for more info. */ PGconn * PQconnectStart(const char *conninfo) { PGconn *conn; /* * Allocate memory for the conn structure */ conn = makeEmptyPGconn(); if (conn == NULL) return NULL; /* * Parse the conninfo string */ if (!connectOptions1(conn, conninfo)) return conn; /* * Compute derived options */ if (!connectOptions2(conn)) return conn; /* * Connect to the database */ if (!connectDBStart(conn)) { /* Just in case we failed to set it in connectDBStart */ conn->status = CONNECTION_BAD; } return conn; } static void fillPGconn(PGconn *conn, PQconninfoOption *connOptions) { char *tmp; /* * Move option values into conn structure * * Don't put anything cute here --- intelligence should be in * connectOptions2 ... * * XXX: probably worth checking strdup() return value here... */ tmp = conninfo_getval(connOptions, "hostaddr"); conn->pghostaddr = tmp ? strdup(tmp) : NULL; tmp = conninfo_getval(connOptions, "host"); conn->pghost = tmp ? strdup(tmp) : NULL; tmp = conninfo_getval(connOptions, "port"); conn->pgport = tmp ? strdup(tmp) : NULL; tmp = conninfo_getval(connOptions, "tty"); conn->pgtty = tmp ? strdup(tmp) : NULL; tmp = conninfo_getval(connOptions, "options"); conn->pgoptions = tmp ? strdup(tmp) : NULL; tmp = conninfo_getval(connOptions, "application_name"); conn->appname = tmp ? strdup(tmp) : NULL; tmp = conninfo_getval(connOptions, "fallback_application_name"); conn->fbappname = tmp ? strdup(tmp) : NULL; tmp = conninfo_getval(connOptions, "dbname"); conn->dbName = tmp ? strdup(tmp) : NULL; tmp = conninfo_getval(connOptions, "user"); conn->pguser = tmp ? strdup(tmp) : NULL; tmp = conninfo_getval(connOptions, "password"); conn->pgpass = tmp ? strdup(tmp) : NULL; tmp = conninfo_getval(connOptions, "connect_timeout"); conn->connect_timeout = tmp ? strdup(tmp) : NULL; tmp = conninfo_getval(connOptions, "client_encoding"); conn->client_encoding_initial = tmp ? strdup(tmp) : NULL; tmp = conninfo_getval(connOptions, "keepalives"); conn->keepalives = tmp ? strdup(tmp) : NULL; tmp = conninfo_getval(connOptions, "keepalives_idle"); conn->keepalives_idle = tmp ? strdup(tmp) : NULL; tmp = conninfo_getval(connOptions, "keepalives_interval"); conn->keepalives_interval = tmp ? strdup(tmp) : NULL; tmp = conninfo_getval(connOptions, "keepalives_count"); conn->keepalives_count = tmp ? strdup(tmp) : NULL; tmp = conninfo_getval(connOptions, "sslmode"); conn->sslmode = tmp ? strdup(tmp) : NULL; tmp = conninfo_getval(connOptions, "sslkey"); conn->sslkey = tmp ? strdup(tmp) : NULL; tmp = conninfo_getval(connOptions, "sslcert"); conn->sslcert = tmp ? strdup(tmp) : NULL; tmp = conninfo_getval(connOptions, "sslrootcert"); conn->sslrootcert = tmp ? strdup(tmp) : NULL; tmp = conninfo_getval(connOptions, "sslcrl"); conn->sslcrl = tmp ? strdup(tmp) : NULL; #ifdef USE_SSL tmp = conninfo_getval(connOptions, "requiressl"); if (tmp && tmp[0] == '1') { /* here warn that the requiressl option is deprecated? */ if (conn->sslmode) free(conn->sslmode); conn->sslmode = strdup("require"); } #endif tmp = conninfo_getval(connOptions, "requirepeer"); conn->requirepeer = tmp ? strdup(tmp) : NULL; #if defined(KRB5) || defined(ENABLE_GSS) || defined(ENABLE_SSPI) tmp = conninfo_getval(connOptions, "krbsrvname"); conn->krbsrvname = tmp ? strdup(tmp) : NULL; #endif #if defined(ENABLE_GSS) && defined(ENABLE_SSPI) tmp = conninfo_getval(connOptions, "gsslib"); conn->gsslib = tmp ? strdup(tmp) : NULL; #endif tmp = conninfo_getval(connOptions, "replication"); conn->replication = tmp ? strdup(tmp) : NULL; } /* * connectOptions1 * * Internal subroutine to set up connection parameters given an already- * created PGconn and a conninfo string. Derived settings should be * processed by calling connectOptions2 next. (We split them because * PQsetdbLogin overrides defaults in between.) * * Returns true if OK, false if trouble (in which case errorMessage is set * and so is conn->status). */ static bool connectOptions1(PGconn *conn, const char *conninfo) { PQconninfoOption *connOptions; /* * Parse the conninfo string */ connOptions = conninfo_parse(conninfo, &conn->errorMessage, true); if (connOptions == NULL) { conn->status = CONNECTION_BAD; /* errorMessage is already set */ return false; } /* * Move option values into conn structure */ fillPGconn(conn, connOptions); /* * Free the option info - all is in conn now */ PQconninfoFree(connOptions); return true; } /* * connectOptions2 * * Compute derived connection options after absorbing all user-supplied info. * * Returns true if OK, false if trouble (in which case errorMessage is set * and so is conn->status). */ static bool connectOptions2(PGconn *conn) { /* * If database name was not given, default it to equal user name */ if ((conn->dbName == NULL || conn->dbName[0] == '\0') && conn->pguser != NULL) { if (conn->dbName) free(conn->dbName); conn->dbName = strdup(conn->pguser); } /* * Supply default password if none given */ if (conn->pgpass == NULL || conn->pgpass[0] == '\0') { if (conn->pgpass) free(conn->pgpass); conn->pgpass = PasswordFromFile(conn->pghost, conn->pgport, conn->dbName, conn->pguser); if (conn->pgpass == NULL) conn->pgpass = strdup(DefaultPassword); else conn->dot_pgpass_used = true; } /* * Allow unix socket specification in the host name */ if (conn->pghost && is_absolute_path(conn->pghost)) { if (conn->pgunixsocket) free(conn->pgunixsocket); conn->pgunixsocket = conn->pghost; conn->pghost = NULL; } /* * validate sslmode option */ if (conn->sslmode) { if (strcmp(conn->sslmode, "disable") != 0 && strcmp(conn->sslmode, "allow") != 0 && strcmp(conn->sslmode, "prefer") != 0 && strcmp(conn->sslmode, "require") != 0 && strcmp(conn->sslmode, "verify-ca") != 0 && strcmp(conn->sslmode, "verify-full") != 0) { conn->status = CONNECTION_BAD; printfPQExpBuffer(&conn->errorMessage, libpq_gettext("invalid sslmode value: \"%s\"\n"), conn->sslmode); return false; } #ifndef USE_SSL switch (conn->sslmode[0]) { case 'a': /* "allow" */ case 'p': /* "prefer" */ /* * warn user that an SSL connection will never be negotiated * since SSL was not compiled in? */ break; case 'r': /* "require" */ case 'v': /* "verify-ca" or "verify-full" */ conn->status = CONNECTION_BAD; printfPQExpBuffer(&conn->errorMessage, libpq_gettext("sslmode value \"%s\" invalid when SSL support is not compiled in\n"), conn->sslmode); return false; } #endif } else conn->sslmode = strdup(DefaultSSLMode); /* * Resolve special "auto" client_encoding from the locale */ if (conn->client_encoding_initial && strcmp(conn->client_encoding_initial, "auto") == 0) { free(conn->client_encoding_initial); conn->client_encoding_initial = strdup(pg_encoding_to_char(pg_get_encoding_from_locale(NULL, true))); } /* * Only if we get this far is it appropriate to try to connect. (We need a * state flag, rather than just the boolean result of this function, in * case someone tries to PQreset() the PGconn.) */ conn->options_valid = true; return true; } /* * PQconndefaults * * Parse an empty string like PQconnectdb() would do and return the * resulting connection options array, ie, all the default values that are * available from the environment etc. On error (eg out of memory), * NULL is returned. * * Using this function, an application may determine all possible options * and their current default values. * * NOTE: as of PostgreSQL 7.0, the returned array is dynamically allocated * and should be freed when no longer needed via PQconninfoFree(). (In prior * versions, the returned array was static, but that's not thread-safe.) * Pre-7.0 applications that use this function will see a small memory leak * until they are updated to call PQconninfoFree. */ PQconninfoOption * PQconndefaults(void) { PQExpBufferData errorBuf; PQconninfoOption *connOptions; initPQExpBuffer(&errorBuf); if (PQExpBufferBroken(&errorBuf)) return NULL; /* out of memory already :-( */ connOptions = conninfo_parse("", &errorBuf, true); termPQExpBuffer(&errorBuf); return connOptions; } /* ---------------- * PQsetdbLogin * * establishes a connection to a postgres backend through the postmaster * at the specified host and port. * * returns a PGconn* which is needed for all subsequent libpq calls * * if the status field of the connection returned is CONNECTION_BAD, * then only the errorMessage is likely to be useful. * ---------------- */ PGconn * PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions, const char *pgtty, const char *dbName, const char *login, const char *pwd) { PGconn *conn; /* * Allocate memory for the conn structure */ conn = makeEmptyPGconn(); if (conn == NULL) return NULL; /* * If the dbName parameter contains '=', assume it's a conninfo string. */ if (dbName && strchr(dbName, '=')) { if (!connectOptions1(conn, dbName)) return conn; } else { /* * Old-style path: first, parse an empty conninfo string in order to * set up the same defaults that PQconnectdb() would use. */ if (!connectOptions1(conn, "")) return conn; /* Insert dbName parameter value into struct */ if (dbName && dbName[0] != '\0') { if (conn->dbName) free(conn->dbName); conn->dbName = strdup(dbName); } } /* * Insert remaining parameters into struct, overriding defaults (as well * as any conflicting data from dbName taken as a conninfo). */ if (pghost && pghost[0] != '\0') { if (conn->pghost) free(conn->pghost); conn->pghost = strdup(pghost); } if (pgport && pgport[0] != '\0') { if (conn->pgport) free(conn->pgport); conn->pgport = strdup(pgport); } if (pgoptions && pgoptions[0] != '\0') { if (conn->pgoptions) free(conn->pgoptions); conn->pgoptions = strdup(pgoptions); } if (pgtty && pgtty[0] != '\0') { if (conn->pgtty) free(conn->pgtty); conn->pgtty = strdup(pgtty); } if (login && login[0] != '\0') { if (conn->pguser) free(conn->pguser); conn->pguser = strdup(login); } if (pwd && pwd[0] != '\0') { if (conn->pgpass) free(conn->pgpass); conn->pgpass = strdup(pwd); } /* * Compute derived options */ if (!connectOptions2(conn)) return conn; /* * Connect to the database */ if (connectDBStart(conn)) (void) connectDBComplete(conn); return conn; } /* ---------- * connectNoDelay - * Sets the TCP_NODELAY socket option. * Returns 1 if successful, 0 if not. * ---------- */ static int connectNoDelay(PGconn *conn) { #ifdef TCP_NODELAY int on = 1; if (setsockopt(conn->sock, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof(on)) < 0) { char sebuf[256]; appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not set socket to TCP no delay mode: %s\n"), SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); return 0; } #endif return 1; } /* ---------- * connectFailureMessage - * create a friendly error message on connection failure. * ---------- */ static void connectFailureMessage(PGconn *conn, int errorno) { char sebuf[256]; #ifdef HAVE_UNIX_SOCKETS if (IS_AF_UNIX(conn->raddr.addr.ss_family)) { char service[NI_MAXHOST]; pg_getnameinfo_all(&conn->raddr.addr, conn->raddr.salen, NULL, 0, service, sizeof(service), NI_NUMERICSERV); appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not connect to server: %s\n" "\tIs the server running locally and accepting\n" "\tconnections on Unix domain socket \"%s\"?\n"), SOCK_STRERROR(errorno, sebuf, sizeof(sebuf)), service); } else #endif /* HAVE_UNIX_SOCKETS */ { char host_addr[NI_MAXHOST]; const char *displayed_host; struct sockaddr_storage *addr = &conn->raddr.addr; /* * Optionally display the network address with the hostname. This is * useful to distinguish between IPv4 and IPv6 connections. */ if (conn->pghostaddr != NULL) strlcpy(host_addr, conn->pghostaddr, NI_MAXHOST); else if (addr->ss_family == AF_INET) { if (inet_net_ntop(AF_INET, &((struct sockaddr_in *) addr)->sin_addr.s_addr, 32, host_addr, sizeof(host_addr)) == NULL) strcpy(host_addr, "???"); } #ifdef HAVE_IPV6 else if (addr->ss_family == AF_INET6) { if (inet_net_ntop(AF_INET6, &((struct sockaddr_in6 *) addr)->sin6_addr.s6_addr, 128, host_addr, sizeof(host_addr)) == NULL) strcpy(host_addr, "???"); } #endif else strcpy(host_addr, "???"); if (conn->pghostaddr && conn->pghostaddr[0] != '\0') displayed_host = conn->pghostaddr; else if (conn->pghost && conn->pghost[0] != '\0') displayed_host = conn->pghost; else displayed_host = DefaultHost; /* * If the user did not supply an IP address using 'hostaddr', and * 'host' was missing or does not match our lookup, display the * looked-up IP address. */ if ((conn->pghostaddr == NULL) && (conn->pghost == NULL || strcmp(conn->pghost, host_addr) != 0)) appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not connect to server: %s\n" "\tIs the server running on host \"%s\" (%s) and accepting\n" "\tTCP/IP connections on port %s?\n"), SOCK_STRERROR(errorno, sebuf, sizeof(sebuf)), displayed_host, host_addr, conn->pgport); else appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not connect to server: %s\n" "\tIs the server running on host \"%s\" and accepting\n" "\tTCP/IP connections on port %s?\n"), SOCK_STRERROR(errorno, sebuf, sizeof(sebuf)), displayed_host, conn->pgport); } } /* * Should we use keepalives? Returns 1 if yes, 0 if no, and -1 if * conn->keepalives is set to a value which is not parseable as an * integer. */ static int useKeepalives(PGconn *conn) { char *ep; int val; if (conn->keepalives == NULL) return 1; val = strtol(conn->keepalives, &ep, 10); if (*ep) return -1; return val != 0 ? 1 : 0; } #ifndef WIN32 /* * Set the keepalive idle timer. */ static int setKeepalivesIdle(PGconn *conn) { int idle; if (conn->keepalives_idle == NULL) return 1; idle = atoi(conn->keepalives_idle); if (idle < 0) idle = 0; #ifdef TCP_KEEPIDLE if (setsockopt(conn->sock, IPPROTO_TCP, TCP_KEEPIDLE, (char *) &idle, sizeof(idle)) < 0) { char sebuf[256]; appendPQExpBuffer(&conn->errorMessage, libpq_gettext("setsockopt(TCP_KEEPIDLE) failed: %s\n"), SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); return 0; } #else #ifdef TCP_KEEPALIVE /* Darwin uses TCP_KEEPALIVE rather than TCP_KEEPIDLE */ if (setsockopt(conn->sock, IPPROTO_TCP, TCP_KEEPALIVE, (char *) &idle, sizeof(idle)) < 0) { char sebuf[256]; appendPQExpBuffer(&conn->errorMessage, libpq_gettext("setsockopt(TCP_KEEPALIVE) failed: %s\n"), SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); return 0; } #endif #endif return 1; } /* * Set the keepalive interval. */ static int setKeepalivesInterval(PGconn *conn) { int interval; if (conn->keepalives_interval == NULL) return 1; interval = atoi(conn->keepalives_interval); if (interval < 0) interval = 0; #ifdef TCP_KEEPINTVL if (setsockopt(conn->sock, IPPROTO_TCP, TCP_KEEPINTVL, (char *) &interval, sizeof(interval)) < 0) { char sebuf[256]; appendPQExpBuffer(&conn->errorMessage, libpq_gettext("setsockopt(TCP_KEEPINTVL) failed: %s\n"), SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); return 0; } #endif return 1; } /* * Set the count of lost keepalive packets that will trigger a connection * break. */ static int setKeepalivesCount(PGconn *conn) { int count; if (conn->keepalives_count == NULL) return 1; count = atoi(conn->keepalives_count); if (count < 0) count = 0; #ifdef TCP_KEEPCNT if (setsockopt(conn->sock, IPPROTO_TCP, TCP_KEEPCNT, (char *) &count, sizeof(count)) < 0) { char sebuf[256]; appendPQExpBuffer(&conn->errorMessage, libpq_gettext("setsockopt(TCP_KEEPCNT) failed: %s\n"), SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); return 0; } #endif return 1; } #else /* Win32 */ #ifdef SIO_KEEPALIVE_VALS /* * Enable keepalives and set the keepalive values on Win32, * where they are always set in one batch. */ static int setKeepalivesWin32(PGconn *conn) { struct tcp_keepalive ka; DWORD retsize; int idle = 0; int interval = 0; if (conn->keepalives_idle) idle = atoi(conn->keepalives_idle); if (idle <= 0) idle = 2 * 60 * 60; /* 2 hours = default */ if (conn->keepalives_interval) interval = atoi(conn->keepalives_interval); if (interval <= 0) interval = 1; /* 1 second = default */ ka.onoff = 1; ka.keepalivetime = idle * 1000; ka.keepaliveinterval = interval * 1000; if (WSAIoctl(conn->sock, SIO_KEEPALIVE_VALS, (LPVOID) &ka, sizeof(ka), NULL, 0, &retsize, NULL, NULL) != 0) { appendPQExpBuffer(&conn->errorMessage, libpq_gettext("WSAIoctl(SIO_KEEPALIVE_VALS) failed: %ui\n"), WSAGetLastError()); return 0; } return 1; } #endif /* SIO_KEEPALIVE_VALS */ #endif /* WIN32 */ /* ---------- * connectDBStart - * Begin the process of making a connection to the backend. * * Returns 1 if successful, 0 if not. * ---------- */ static int connectDBStart(PGconn *conn) { int portnum; char portstr[128]; struct addrinfo *addrs = NULL; struct addrinfo hint; const char *node; int ret; if (!conn) return 0; if (!conn->options_valid) goto connect_errReturn; /* Ensure our buffers are empty */ conn->inStart = conn->inCursor = conn->inEnd = 0; conn->outCount = 0; /* * Determine the parameters to pass to pg_getaddrinfo_all. */ /* Initialize hint structure */ MemSet(&hint, 0, sizeof(hint)); hint.ai_socktype = SOCK_STREAM; hint.ai_family = AF_UNSPEC; /* Set up port number as a string */ if (conn->pgport != NULL && conn->pgport[0] != '\0') { portnum = atoi(conn->pgport); if (portnum < 1 || portnum > 65535) { appendPQExpBuffer(&conn->errorMessage, libpq_gettext("invalid port number: \"%s\"\n"), conn->pgport); conn->options_valid = false; goto connect_errReturn; } } else portnum = DEF_PGPORT; snprintf(portstr, sizeof(portstr), "%d", portnum); if (conn->pghostaddr != NULL && conn->pghostaddr[0] != '\0') { /* Using pghostaddr avoids a hostname lookup */ node = conn->pghostaddr; hint.ai_family = AF_UNSPEC; hint.ai_flags = AI_NUMERICHOST; } else if (conn->pghost != NULL && conn->pghost[0] != '\0') { /* Using pghost, so we have to look-up the hostname */ node = conn->pghost; hint.ai_family = AF_UNSPEC; } else { #ifdef HAVE_UNIX_SOCKETS /* pghostaddr and pghost are NULL, so use Unix domain socket */ node = NULL; hint.ai_family = AF_UNIX; UNIXSOCK_PATH(portstr, portnum, conn->pgunixsocket); #else /* Without Unix sockets, default to localhost instead */ node = DefaultHost; hint.ai_family = AF_UNSPEC; #endif /* HAVE_UNIX_SOCKETS */ } /* Use pg_getaddrinfo_all() to resolve the address */ ret = pg_getaddrinfo_all(node, portstr, &hint, &addrs); if (ret || !addrs) { if (node) appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not translate host name \"%s\" to address: %s\n"), node, gai_strerror(ret)); else appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not translate Unix-domain socket path \"%s\" to address: %s\n"), portstr, gai_strerror(ret)); if (addrs) pg_freeaddrinfo_all(hint.ai_family, addrs); conn->options_valid = false; goto connect_errReturn; } #ifdef USE_SSL /* setup values based on SSL mode */ if (conn->sslmode[0] == 'd') /* "disable" */ conn->allow_ssl_try = false; else if (conn->sslmode[0] == 'a') /* "allow" */ conn->wait_ssl_try = true; #endif /* * Set up to try to connect, with protocol 3.0 as the first attempt. */ conn->addrlist = addrs; conn->addr_cur = addrs; conn->addrlist_family = hint.ai_family; conn->pversion = PG_PROTOCOL(3, 0); conn->send_appname = true; conn->status = CONNECTION_NEEDED; /* * The code for processing CONNECTION_NEEDED state is in PQconnectPoll(), * so that it can easily be re-executed if needed again during the * asynchronous startup process. However, we must run it once here, * because callers expect a success return from this routine to mean that * we are in PGRES_POLLING_WRITING connection state. */ if (PQconnectPoll(conn) == PGRES_POLLING_WRITING) return 1; connect_errReturn: if (conn->sock >= 0) { pqsecure_close(conn); closesocket(conn->sock); conn->sock = -1; } conn->status = CONNECTION_BAD; return 0; } /* * connectDBComplete * * Block and complete a connection. * * Returns 1 on success, 0 on failure. */ static int connectDBComplete(PGconn *conn) { PostgresPollingStatusType flag = PGRES_POLLING_WRITING; time_t finish_time = ((time_t) -1); if (conn == NULL || conn->status == CONNECTION_BAD) return 0; /* * Set up a time limit, if connect_timeout isn't zero. */ if (conn->connect_timeout != NULL) { int timeout = atoi(conn->connect_timeout); if (timeout > 0) { /* * Rounding could cause connection to fail; need at least 2 secs */ if (timeout < 2) timeout = 2; /* calculate the finish time based on start + timeout */ finish_time = time(NULL) + timeout; } } for (;;) { /* * Wait, if necessary. Note that the initial state (just after * PQconnectStart) is to wait for the socket to select for writing. */ switch (flag) { case PGRES_POLLING_OK: /* * Reset stored error messages since we now have a working * connection */ resetPQExpBuffer(&conn->errorMessage); return 1; /* success! */ case PGRES_POLLING_READING: if (pqWaitTimed(1, 0, conn, finish_time)) { conn->status = CONNECTION_BAD; return 0; } break; case PGRES_POLLING_WRITING: if (pqWaitTimed(0, 1, conn, finish_time)) { conn->status = CONNECTION_BAD; return 0; } break; default: /* Just in case we failed to set it in PQconnectPoll */ conn->status = CONNECTION_BAD; return 0; } /* * Now try to advance the state machine. */ flag = PQconnectPoll(conn); } } /* ---------------- * PQconnectPoll * * Poll an asynchronous connection. * * Returns a PostgresPollingStatusType. * Before calling this function, use select(2) to determine when data * has arrived.. * * You must call PQfinish whether or not this fails. * * This function and PQconnectStart are intended to allow connections to be * made without blocking the execution of your program on remote I/O. However, * there are a number of caveats: * * o If you call PQtrace, ensure that the stream object into which you trace * will not block. * o If you do not supply an IP address for the remote host (i.e. you * supply a host name instead) then PQconnectStart will block on * gethostbyname. You will be fine if using Unix sockets (i.e. by * supplying neither a host name nor a host address). * o If your backend wants to use Kerberos authentication then you must * supply both a host name and a host address, otherwise this function * may block on gethostname. * * ---------------- */ PostgresPollingStatusType PQconnectPoll(PGconn *conn) { PGresult *res; char sebuf[256]; int optval; if (conn == NULL) return PGRES_POLLING_FAILED; /* Get the new data */ switch (conn->status) { /* * We really shouldn't have been polled in these two cases, but we * can handle it. */ case CONNECTION_BAD: return PGRES_POLLING_FAILED; case CONNECTION_OK: return PGRES_POLLING_OK; /* These are reading states */ case CONNECTION_AWAITING_RESPONSE: case CONNECTION_AUTH_OK: { /* Load waiting data */ int n = pqReadData(conn); if (n < 0) goto error_return; if (n == 0) return PGRES_POLLING_READING; break; } /* These are writing states, so we just proceed. */ case CONNECTION_STARTED: case CONNECTION_MADE: break; /* We allow pqSetenvPoll to decide whether to proceed. */ case CONNECTION_SETENV: break; /* Special cases: proceed without waiting. */ case CONNECTION_SSL_STARTUP: case CONNECTION_NEEDED: break; default: appendPQExpBuffer(&conn->errorMessage, libpq_gettext( "invalid connection state, " "probably indicative of memory corruption\n" )); goto error_return; } keep_going: /* We will come back to here until there is * nothing left to do. */ switch (conn->status) { case CONNECTION_NEEDED: { /* * Try to initiate a connection to one of the addresses * returned by pg_getaddrinfo_all(). conn->addr_cur is the * next one to try. We fail when we run out of addresses. */ while (conn->addr_cur != NULL) { struct addrinfo *addr_cur = conn->addr_cur; /* Remember current address for possible error msg */ memcpy(&conn->raddr.addr, addr_cur->ai_addr, addr_cur->ai_addrlen); conn->raddr.salen = addr_cur->ai_addrlen; /* Open a socket */ conn->sock = socket(addr_cur->ai_family, SOCK_STREAM, 0); if (conn->sock < 0) { /* * ignore socket() failure if we have more addresses * to try */ if (addr_cur->ai_next != NULL) { conn->addr_cur = addr_cur->ai_next; continue; } appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not create socket: %s\n"), SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); break; } /* * Select socket options: no delay of outgoing data for * TCP sockets, nonblock mode, close-on-exec. Fail if any * of this fails. */ if (!IS_AF_UNIX(addr_cur->ai_family)) { if (!connectNoDelay(conn)) { closesocket(conn->sock); conn->sock = -1; conn->addr_cur = addr_cur->ai_next; continue; } } if (!pg_set_noblock(conn->sock)) { appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not set socket to non-blocking mode: %s\n"), SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); closesocket(conn->sock); conn->sock = -1; conn->addr_cur = addr_cur->ai_next; continue; } #ifdef F_SETFD if (fcntl(conn->sock, F_SETFD, FD_CLOEXEC) == -1) { appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not set socket to close-on-exec mode: %s\n"), SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); closesocket(conn->sock); conn->sock = -1; conn->addr_cur = addr_cur->ai_next; continue; } #endif /* F_SETFD */ if (!IS_AF_UNIX(addr_cur->ai_family)) { #ifndef WIN32 int on = 1; #endif int usekeepalives = useKeepalives(conn); int err = 0; if (usekeepalives < 0) { appendPQExpBuffer(&conn->errorMessage, libpq_gettext("keepalives parameter must be an integer\n")); err = 1; } else if (usekeepalives == 0) { /* Do nothing */ } #ifndef WIN32 else if (setsockopt(conn->sock, SOL_SOCKET, SO_KEEPALIVE, (char *) &on, sizeof(on)) < 0) { appendPQExpBuffer(&conn->errorMessage, libpq_gettext("setsockopt(SO_KEEPALIVE) failed: %s\n"), SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); err = 1; } else if (!setKeepalivesIdle(conn) || !setKeepalivesInterval(conn) || !setKeepalivesCount(conn)) err = 1; #else /* WIN32 */ #ifdef SIO_KEEPALIVE_VALS else if (!setKeepalivesWin32(conn)) err = 1; #endif /* SIO_KEEPALIVE_VALS */ #endif /* WIN32 */ if (err) { closesocket(conn->sock); conn->sock = -1; conn->addr_cur = addr_cur->ai_next; continue; } } /*---------- * We have three methods of blocking SIGPIPE during * send() calls to this socket: * * - setsockopt(sock, SO_NOSIGPIPE) * - send(sock, ..., MSG_NOSIGNAL) * - setting the signal mask to SIG_IGN during send() * * The third method requires three syscalls per send, * so we prefer either of the first two, but they are * less portable. The state is tracked in the following * members of PGconn: * * conn->sigpipe_so - we have set up SO_NOSIGPIPE * conn->sigpipe_flag - we're specifying MSG_NOSIGNAL * * If we can use SO_NOSIGPIPE, then set sigpipe_so here * and we're done. Otherwise, set sigpipe_flag so that * we will try MSG_NOSIGNAL on sends. If we get an error * with MSG_NOSIGNAL, we'll clear that flag and revert to * signal masking. *---------- */ conn->sigpipe_so = false; #ifdef MSG_NOSIGNAL conn->sigpipe_flag = true; #else conn->sigpipe_flag = false; #endif /* MSG_NOSIGNAL */ #ifdef SO_NOSIGPIPE optval = 1; if (setsockopt(conn->sock, SOL_SOCKET, SO_NOSIGPIPE, (char *) &optval, sizeof(optval)) == 0) { conn->sigpipe_so = true; conn->sigpipe_flag = false; } #endif /* SO_NOSIGPIPE */ /* * Start/make connection. This should not block, since we * are in nonblock mode. If it does, well, too bad. */ if (connect(conn->sock, addr_cur->ai_addr, addr_cur->ai_addrlen) < 0) { if (SOCK_ERRNO == EINPROGRESS || SOCK_ERRNO == EWOULDBLOCK || SOCK_ERRNO == EINTR || SOCK_ERRNO == 0) { /* * This is fine - we're in non-blocking mode, and * the connection is in progress. Tell caller to * wait for write-ready on socket. */ conn->status = CONNECTION_STARTED; return PGRES_POLLING_WRITING; } /* otherwise, trouble */ } else { /* * Hm, we're connected already --- seems the "nonblock * connection" wasn't. Advance the state machine and * go do the next stuff. */ conn->status = CONNECTION_STARTED; goto keep_going; } /* * This connection failed --- set up error report, then * close socket (do it this way in case close() affects * the value of errno...). We will ignore the connect() * failure and keep going if there are more addresses. */ connectFailureMessage(conn, SOCK_ERRNO); if (conn->sock >= 0) { closesocket(conn->sock); conn->sock = -1; } /* * Try the next address, if any. */ conn->addr_cur = addr_cur->ai_next; } /* loop over addresses */ /* * Ooops, no more addresses. An appropriate error message is * already set up, so just set the right status. */ goto error_return; } case CONNECTION_STARTED: { ACCEPT_TYPE_ARG3 optlen = sizeof(optval); /* * Write ready, since we've made it here, so the connection * has been made ... or has failed. */ /* * Now check (using getsockopt) that there is not an error * state waiting for us on the socket. */ if (getsockopt(conn->sock, SOL_SOCKET, SO_ERROR, (char *) &optval, &optlen) == -1) { appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not get socket error status: %s\n"), SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); goto error_return; } else if (optval != 0) { /* * When using a nonblocking connect, we will typically see * connect failures at this point, so provide a friendly * error message. */ connectFailureMessage(conn, optval); /* * If more addresses remain, keep trying, just as in the * case where connect() returned failure immediately. */ if (conn->addr_cur->ai_next != NULL) { if (conn->sock >= 0) { closesocket(conn->sock); conn->sock = -1; } conn->addr_cur = conn->addr_cur->ai_next; conn->status = CONNECTION_NEEDED; goto keep_going; } goto error_return; } /* Fill in the client address */ conn->laddr.salen = sizeof(conn->laddr.addr); if (getsockname(conn->sock, (struct sockaddr *) & conn->laddr.addr, &conn->laddr.salen) < 0) { appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not get client address from socket: %s\n"), SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); goto error_return; } /* * Make sure we can write before advancing to next step. */ conn->status = CONNECTION_MADE; return PGRES_POLLING_WRITING; } case CONNECTION_MADE: { char *startpacket; int packetlen; #ifdef HAVE_UNIX_SOCKETS /* * Implement requirepeer check, if requested and it's a * Unix-domain socket. */ if (conn->requirepeer && conn->requirepeer[0] && IS_AF_UNIX(conn->raddr.addr.ss_family)) { char pwdbuf[BUFSIZ]; struct passwd pass_buf; struct passwd *pass; uid_t uid; gid_t gid; errno = 0; if (getpeereid(conn->sock, &uid, &gid) != 0) { /* * Provide special error message if getpeereid is a * stub */ if (errno == ENOSYS) appendPQExpBuffer(&conn->errorMessage, libpq_gettext("requirepeer parameter is not supported on this platform\n")); else appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not get peer credentials: %s\n"), pqStrerror(errno, sebuf, sizeof(sebuf))); goto error_return; } pqGetpwuid(uid, &pass_buf, pwdbuf, sizeof(pwdbuf), &pass); if (pass == NULL) { appendPQExpBuffer(&conn->errorMessage, libpq_gettext("local user with ID %d does not exist\n"), (int) uid); goto error_return; } if (strcmp(pass->pw_name, conn->requirepeer) != 0) { appendPQExpBuffer(&conn->errorMessage, libpq_gettext("requirepeer specifies \"%s\", but actual peer user name is \"%s\"\n"), conn->requirepeer, pass->pw_name); goto error_return; } } #endif /* HAVE_UNIX_SOCKETS */ #ifdef USE_SSL /* * If SSL is enabled and we haven't already got it running, * request it instead of sending the startup message. */ if (IS_AF_UNIX(conn->raddr.addr.ss_family)) { /* Don't bother requesting SSL over a Unix socket */ conn->allow_ssl_try = false; } if (conn->allow_ssl_try && !conn->wait_ssl_try && conn->ssl == NULL) { ProtocolVersion pv; /* * Send the SSL request packet. * * Theoretically, this could block, but it really * shouldn't since we only got here if the socket is * write-ready. */ pv = htonl(NEGOTIATE_SSL_CODE); if (pqPacketSend(conn, 0, &pv, sizeof(pv)) != STATUS_OK) { appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not send SSL negotiation packet: %s\n"), SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); goto error_return; } /* Ok, wait for response */ conn->status = CONNECTION_SSL_STARTUP; return PGRES_POLLING_READING; } #endif /* USE_SSL */ /* * Build the startup packet. */ if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3) startpacket = pqBuildStartupPacket3(conn, &packetlen, EnvironmentOptions); else startpacket = pqBuildStartupPacket2(conn, &packetlen, EnvironmentOptions); if (!startpacket) { /* * will not appendbuffer here, since it's likely to also * run out of memory */ printfPQExpBuffer(&conn->errorMessage, libpq_gettext("out of memory\n")); goto error_return; } /* * Send the startup packet. * * Theoretically, this could block, but it really shouldn't * since we only got here if the socket is write-ready. */ if (pqPacketSend(conn, 0, startpacket, packetlen) != STATUS_OK) { appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not send startup packet: %s\n"), SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); free(startpacket); goto error_return; } free(startpacket); conn->status = CONNECTION_AWAITING_RESPONSE; return PGRES_POLLING_READING; } /* * Handle SSL negotiation: wait for postmaster messages and * respond as necessary. */ case CONNECTION_SSL_STARTUP: { #ifdef USE_SSL PostgresPollingStatusType pollres; /* * On first time through, get the postmaster's response to our * SSL negotiation packet. */ if (conn->ssl == NULL) { /* * We use pqReadData here since it has the logic to * distinguish no-data-yet from connection closure. Since * conn->ssl isn't set, a plain recv() will occur. */ char SSLok; int rdresult; rdresult = pqReadData(conn); if (rdresult < 0) { /* errorMessage is already filled in */ goto error_return; } if (rdresult == 0) { /* caller failed to wait for data */ return PGRES_POLLING_READING; } if (pqGetc(&SSLok, conn) < 0) { /* should not happen really */ return PGRES_POLLING_READING; } if (SSLok == 'S') { /* mark byte consumed */ conn->inStart = conn->inCursor; /* Set up global SSL state if required */ if (pqsecure_initialize(conn) != 0) goto error_return; } else if (SSLok == 'N') { /* mark byte consumed */ conn->inStart = conn->inCursor; /* OK to do without SSL? */ if (conn->sslmode[0] == 'r' || /* "require" */ conn->sslmode[0] == 'v') /* "verify-ca" or * "verify-full" */ { /* Require SSL, but server does not want it */ appendPQExpBuffer(&conn->errorMessage, libpq_gettext("server does not support SSL, but SSL was required\n")); goto error_return; } /* Otherwise, proceed with normal startup */ conn->allow_ssl_try = false; conn->status = CONNECTION_MADE; return PGRES_POLLING_WRITING; } else if (SSLok == 'E') { /* * Server failure of some sort, such as failure to * fork a backend process. We need to process and * report the error message, which might be formatted * according to either protocol 2 or protocol 3. * Rather than duplicate the code for that, we flip * into AWAITING_RESPONSE state and let the code there * deal with it. Note we have *not* consumed the "E" * byte here. */ conn->status = CONNECTION_AWAITING_RESPONSE; goto keep_going; } else { appendPQExpBuffer(&conn->errorMessage, libpq_gettext("received invalid response to SSL negotiation: %c\n"), SSLok); goto error_return; } } /* * Begin or continue the SSL negotiation process. */ pollres = pqsecure_open_client(conn); if (pollres == PGRES_POLLING_OK) { /* SSL handshake done, ready to send startup packet */ conn->status = CONNECTION_MADE; return PGRES_POLLING_WRITING; } if (pollres == PGRES_POLLING_FAILED) { /* * Failed ... if sslmode is "prefer" then do a non-SSL * retry */ if (conn->sslmode[0] == 'p' /* "prefer" */ && conn->allow_ssl_try /* redundant? */ && !conn->wait_ssl_try) /* redundant? */ { /* only retry once */ conn->allow_ssl_try = false; /* Must drop the old connection */ closesocket(conn->sock); conn->sock = -1; conn->status = CONNECTION_NEEDED; /* Discard any unread/unsent data */ conn->inStart = conn->inCursor = conn->inEnd = 0; conn->outCount = 0; goto keep_going; } } return pollres; #else /* !USE_SSL */ /* can't get here */ goto error_return; #endif /* USE_SSL */ } /* * Handle authentication exchange: wait for postmaster messages * and respond as necessary. */ case CONNECTION_AWAITING_RESPONSE: { char beresp; int msgLength; int avail; AuthRequest areq; /* * Scan the message from current point (note that if we find * the message is incomplete, we will return without advancing * inStart, and resume here next time). */ conn->inCursor = conn->inStart; /* Read type byte */ if (pqGetc(&beresp, conn)) { /* We'll come back when there is more data */ return PGRES_POLLING_READING; } /* * Validate message type: we expect only an authentication * request or an error here. Anything else probably means * it's not Postgres on the other end at all. */ if (!(beresp == 'R' || beresp == 'E')) { appendPQExpBuffer(&conn->errorMessage, libpq_gettext( "expected authentication request from " "server, but received %c\n"), beresp); goto error_return; } if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3) { /* Read message length word */ if (pqGetInt(&msgLength, 4, conn)) { /* We'll come back when there is more data */ return PGRES_POLLING_READING; } } else { /* Set phony message length to disable checks below */ msgLength = 8; } /* * Try to validate message length before using it. * Authentication requests can't be very large, although GSS * auth requests may not be that small. Errors can be a * little larger, but not huge. If we see a large apparent * length in an error, it means we're really talking to a * pre-3.0-protocol server; cope. */ if (beresp == 'R' && (msgLength < 8 || msgLength > 2000)) { appendPQExpBuffer(&conn->errorMessage, libpq_gettext( "expected authentication request from " "server, but received %c\n"), beresp); goto error_return; } if (beresp == 'E' && (msgLength < 8 || msgLength > 30000)) { /* Handle error from a pre-3.0 server */ conn->inCursor = conn->inStart + 1; /* reread data */ if (pqGets_append(&conn->errorMessage, conn)) { /* We'll come back when there is more data */ return PGRES_POLLING_READING; } /* OK, we read the message; mark data consumed */ conn->inStart = conn->inCursor; /* * The postmaster typically won't end its message with a * newline, so add one to conform to libpq conventions. */ appendPQExpBufferChar(&conn->errorMessage, '\n'); /* * If we tried to open the connection in 3.0 protocol, * fall back to 2.0 protocol. */ if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3) { conn->pversion = PG_PROTOCOL(2, 0); /* Must drop the old connection */ pqsecure_close(conn); closesocket(conn->sock); conn->sock = -1; conn->status = CONNECTION_NEEDED; /* Discard any unread/unsent data */ conn->inStart = conn->inCursor = conn->inEnd = 0; conn->outCount = 0; goto keep_going; } goto error_return; } /* * Can't process if message body isn't all here yet. * * (In protocol 2.0 case, we are assuming messages carry at * least 4 bytes of data.) */ msgLength -= 4; avail = conn->inEnd - conn->inCursor; if (avail < msgLength) { /* * Before returning, try to enlarge the input buffer if * needed to hold the whole message; see notes in * pqParseInput3. */ if (pqCheckInBufferSpace(conn->inCursor + (size_t) msgLength, conn)) goto error_return; /* We'll come back when there is more data */ return PGRES_POLLING_READING; } /* Handle errors. */ if (beresp == 'E') { if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3) { if (pqGetErrorNotice3(conn, true)) { /* We'll come back when there is more data */ return PGRES_POLLING_READING; } } else { if (pqGets_append(&conn->errorMessage, conn)) { /* We'll come back when there is more data */ return PGRES_POLLING_READING; } } /* OK, we read the message; mark data consumed */ conn->inStart = conn->inCursor; #ifdef USE_SSL /* * if sslmode is "allow" and we haven't tried an SSL * connection already, then retry with an SSL connection */ if (conn->sslmode[0] == 'a' /* "allow" */ && conn->ssl == NULL && conn->allow_ssl_try && conn->wait_ssl_try) { /* only retry once */ conn->wait_ssl_try = false; /* Must drop the old connection */ closesocket(conn->sock); conn->sock = -1; conn->status = CONNECTION_NEEDED; /* Discard any unread/unsent data */ conn->inStart = conn->inCursor = conn->inEnd = 0; conn->outCount = 0; goto keep_going; } /* * if sslmode is "prefer" and we're in an SSL connection, * then do a non-SSL retry */ if (conn->sslmode[0] == 'p' /* "prefer" */ && conn->allow_ssl_try && !conn->wait_ssl_try) /* redundant? */ { /* only retry once */ conn->allow_ssl_try = false; /* Must drop the old connection */ pqsecure_close(conn); closesocket(conn->sock); conn->sock = -1; conn->status = CONNECTION_NEEDED; /* Discard any unread/unsent data */ conn->inStart = conn->inCursor = conn->inEnd = 0; conn->outCount = 0; goto keep_going; } #endif goto error_return; } /* It is an authentication request. */ conn->auth_req_received = true; /* Get the type of request. */ if (pqGetInt((int *) &areq, 4, conn)) { /* We'll come back when there are more data */ return PGRES_POLLING_READING; } /* Get the password salt if there is one. */ if (areq == AUTH_REQ_MD5) { if (pqGetnchar(conn->md5Salt, sizeof(conn->md5Salt), conn)) { /* We'll come back when there are more data */ return PGRES_POLLING_READING; } } #if defined(ENABLE_GSS) || defined(ENABLE_SSPI) /* * Continue GSSAPI/SSPI authentication */ if (areq == AUTH_REQ_GSS_CONT) { int llen = msgLength - 4; /* * We can be called repeatedly for the same buffer. Avoid * re-allocating the buffer in this case - just re-use the * old buffer. */ if (llen != conn->ginbuf.length) { if (conn->ginbuf.value) free(conn->ginbuf.value); conn->ginbuf.length = llen; conn->ginbuf.value = malloc(llen); if (!conn->ginbuf.value) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("out of memory allocating GSSAPI buffer (%i)"), llen); goto error_return; } } if (pqGetnchar(conn->ginbuf.value, llen, conn)) { /* We'll come back when there is more data. */ return PGRES_POLLING_READING; } } #endif /* * OK, we successfully read the message; mark data consumed */ conn->inStart = conn->inCursor; /* Respond to the request if necessary. */ /* * Note that conn->pghost must be non-NULL if we are going to * avoid the Kerberos code doing a hostname look-up. */ if (pg_fe_sendauth(areq, conn) != STATUS_OK) { conn->errorMessage.len = strlen(conn->errorMessage.data); goto error_return; } conn->errorMessage.len = strlen(conn->errorMessage.data); /* * Just make sure that any data sent by pg_fe_sendauth is * flushed out. Although this theoretically could block, it * really shouldn't since we don't send large auth responses. */ if (pqFlush(conn)) goto error_return; if (areq == AUTH_REQ_OK) { /* We are done with authentication exchange */ conn->status = CONNECTION_AUTH_OK; /* * Set asyncStatus so that PQsetResult will think that * what comes back next is the result of a query. See * below. */ conn->asyncStatus = PGASYNC_BUSY; } /* Look to see if we have more data yet. */ goto keep_going; } case CONNECTION_AUTH_OK: { /* * Now we expect to hear from the backend. A ReadyForQuery * message indicates that startup is successful, but we might * also get an Error message indicating failure. (Notice * messages indicating nonfatal warnings are also allowed by * the protocol, as are ParameterStatus and BackendKeyData * messages.) Easiest way to handle this is to let * PQgetResult() read the messages. We just have to fake it * out about the state of the connection, by setting * asyncStatus = PGASYNC_BUSY (done above). */ if (PQisBusy(conn)) return PGRES_POLLING_READING; res = PQgetResult(conn); /* * NULL return indicating we have gone to IDLE state is * expected */ if (res) { if (res->resultStatus != PGRES_FATAL_ERROR) appendPQExpBuffer(&conn->errorMessage, libpq_gettext("unexpected message from server during startup\n")); else if (conn->send_appname && (conn->appname || conn->fbappname)) { /* * If we tried to send application_name, check to see * if the error is about that --- pre-9.0 servers will * reject it at this stage of the process. If so, * close the connection and retry without sending * application_name. We could possibly get a false * SQLSTATE match here and retry uselessly, but there * seems no great harm in that; we'll just get the * same error again if it's unrelated. */ const char *sqlstate; sqlstate = PQresultErrorField(res, PG_DIAG_SQLSTATE); if (sqlstate && strcmp(sqlstate, ERRCODE_APPNAME_UNKNOWN) == 0) { PQclear(res); conn->send_appname = false; /* Must drop the old connection */ pqsecure_close(conn); closesocket(conn->sock); conn->sock = -1; conn->status = CONNECTION_NEEDED; /* Discard any unread/unsent data */ conn->inStart = conn->inCursor = conn->inEnd = 0; conn->outCount = 0; goto keep_going; } } /* * if the resultStatus is FATAL, then conn->errorMessage * already has a copy of the error; needn't copy it back. * But add a newline if it's not there already, since * postmaster error messages may not have one. */ if (conn->errorMessage.len <= 0 || conn->errorMessage.data[conn->errorMessage.len - 1] != '\n') appendPQExpBufferChar(&conn->errorMessage, '\n'); PQclear(res); goto error_return; } /* We can release the address list now. */ pg_freeaddrinfo_all(conn->addrlist_family, conn->addrlist); conn->addrlist = NULL; conn->addr_cur = NULL; /* Fire up post-connection housekeeping if needed */ if (PG_PROTOCOL_MAJOR(conn->pversion) < 3) { conn->status = CONNECTION_SETENV; conn->setenv_state = SETENV_STATE_CLIENT_ENCODING_SEND; conn->next_eo = EnvironmentOptions; return PGRES_POLLING_WRITING; } /* Otherwise, we are open for business! */ conn->status = CONNECTION_OK; return PGRES_POLLING_OK; } case CONNECTION_SETENV: /* * Do post-connection housekeeping (only needed in protocol 2.0). * * We pretend that the connection is OK for the duration of these * queries. */ conn->status = CONNECTION_OK; switch (pqSetenvPoll(conn)) { case PGRES_POLLING_OK: /* Success */ break; case PGRES_POLLING_READING: /* Still going */ conn->status = CONNECTION_SETENV; return PGRES_POLLING_READING; case PGRES_POLLING_WRITING: /* Still going */ conn->status = CONNECTION_SETENV; return PGRES_POLLING_WRITING; default: goto error_return; } /* We are open for business! */ conn->status = CONNECTION_OK; return PGRES_POLLING_OK; default: appendPQExpBuffer(&conn->errorMessage, libpq_gettext("invalid connection state %d, " "probably indicative of memory corruption\n"), conn->status); goto error_return; } /* Unreachable */ error_return: dot_pg_pass_warning(conn); /* * We used to close the socket at this point, but that makes it awkward * for those above us if they wish to remove this socket from their own * records (an fd_set for example). We'll just have this socket closed * when PQfinish is called (which is compulsory even after an error, since * the connection structure must be freed). */ conn->status = CONNECTION_BAD; return PGRES_POLLING_FAILED; } /* * internal_ping * Determine if a server is running and if we can connect to it. * * The argument is a connection that's been started, but not completed. */ static PGPing internal_ping(PGconn *conn) { /* Say "no attempt" if we never got to PQconnectPoll */ if (!conn || !conn->options_valid) return PQPING_NO_ATTEMPT; /* Attempt to complete the connection */ if (conn->status != CONNECTION_BAD) (void) connectDBComplete(conn); /* Definitely OK if we succeeded */ if (conn->status != CONNECTION_BAD) return PQPING_OK; /* * Here begins the interesting part of "ping": determine the cause of the * failure in sufficient detail to decide what to return. We do not want * to report that the server is not up just because we didn't have a valid * password, for example. In fact, any sort of authentication request * implies the server is up. (We need this check since the libpq side of * things might have pulled the plug on the connection before getting an * error as such from the postmaster.) */ if (conn->auth_req_received) return PQPING_OK; /* * If we failed to get any ERROR response from the postmaster, report * PQPING_NO_RESPONSE. This result could be somewhat misleading for a * pre-7.4 server, since it won't send back a SQLSTATE, but those are long * out of support. Another corner case where the server could return a * failure without a SQLSTATE is fork failure, but NO_RESPONSE isn't * totally unreasonable for that anyway. We expect that every other * failure case in a modern server will produce a report with a SQLSTATE. * * NOTE: whenever we get around to making libpq generate SQLSTATEs for * client-side errors, we should either not store those into * last_sqlstate, or add an extra flag so we can tell client-side errors * apart from server-side ones. */ if (strlen(conn->last_sqlstate) != 5) return PQPING_NO_RESPONSE; /* * Report PQPING_REJECT if server says it's not accepting connections. (We * distinguish this case mainly for the convenience of pg_ctl.) */ if (strcmp(conn->last_sqlstate, ERRCODE_CANNOT_CONNECT_NOW) == 0) return PQPING_REJECT; /* * Any other SQLSTATE can be taken to indicate that the server is up. * Presumably it didn't like our username, password, or database name; or * perhaps it had some transient failure, but that should not be taken as * meaning "it's down". */ return PQPING_OK; } /* * makeEmptyPGconn * - create a PGconn data structure with (as yet) no interesting data */ static PGconn * makeEmptyPGconn(void) { PGconn *conn; #ifdef WIN32 /* * Make sure socket support is up and running. */ WSADATA wsaData; if (WSAStartup(MAKEWORD(1, 1), &wsaData)) return NULL; WSASetLastError(0); #endif conn = (PGconn *) malloc(sizeof(PGconn)); if (conn == NULL) { #ifdef WIN32 WSACleanup(); #endif return conn; } /* Zero all pointers and booleans */ MemSet(conn, 0, sizeof(PGconn)); conn->noticeHooks.noticeRec = defaultNoticeReceiver; conn->noticeHooks.noticeProc = defaultNoticeProcessor; conn->status = CONNECTION_BAD; conn->asyncStatus = PGASYNC_IDLE; conn->xactStatus = PQTRANS_IDLE; conn->options_valid = false; conn->nonblocking = false; conn->setenv_state = SETENV_STATE_IDLE; conn->client_encoding = PG_SQL_ASCII; conn->std_strings = false; /* unless server says differently */ conn->verbosity = PQERRORS_DEFAULT; conn->sock = -1; conn->auth_req_received = false; conn->password_needed = false; conn->dot_pgpass_used = false; #ifdef USE_SSL conn->allow_ssl_try = true; conn->wait_ssl_try = false; #endif /* * We try to send at least 8K at a time, which is the usual size of pipe * buffers on Unix systems. That way, when we are sending a large amount * of data, we avoid incurring extra kernel context swaps for partial * bufferloads. The output buffer is initially made 16K in size, and we * try to dump it after accumulating 8K. * * With the same goal of minimizing context swaps, the input buffer will * be enlarged anytime it has less than 8K free, so we initially allocate * twice that. */ conn->inBufSize = 16 * 1024; conn->inBuffer = (char *) malloc(conn->inBufSize); conn->outBufSize = 16 * 1024; conn->outBuffer = (char *) malloc(conn->outBufSize); initPQExpBuffer(&conn->errorMessage); initPQExpBuffer(&conn->workBuffer); if (conn->inBuffer == NULL || conn->outBuffer == NULL || PQExpBufferBroken(&conn->errorMessage) || PQExpBufferBroken(&conn->workBuffer)) { /* out of memory already :-( */ freePGconn(conn); conn = NULL; } return conn; } /* * freePGconn * - free an idle (closed) PGconn data structure * * NOTE: this should not overlap any functionality with closePGconn(). * Clearing/resetting of transient state belongs there; what we do here is * release data that is to be held for the life of the PGconn structure. * If a value ought to be cleared/freed during PQreset(), do it there not here. */ static void freePGconn(PGconn *conn) { int i; /* let any event procs clean up their state data */ for (i = 0; i < conn->nEvents; i++) { PGEventConnDestroy evt; evt.conn = conn; (void) conn->events[i].proc(PGEVT_CONNDESTROY, &evt, conn->events[i].passThrough); free(conn->events[i].name); } if (conn->events) free(conn->events); if (conn->pghost) free(conn->pghost); if (conn->pghostaddr) free(conn->pghostaddr); if (conn->pgport) free(conn->pgport); if (conn->pgunixsocket) free(conn->pgunixsocket); if (conn->pgtty) free(conn->pgtty); if (conn->connect_timeout) free(conn->connect_timeout); if (conn->pgoptions) free(conn->pgoptions); if (conn->appname) free(conn->appname); if (conn->fbappname) free(conn->fbappname); if (conn->dbName) free(conn->dbName); if (conn->replication) free(conn->replication); if (conn->pguser) free(conn->pguser); if (conn->pgpass) free(conn->pgpass); if (conn->keepalives) free(conn->keepalives); if (conn->keepalives_idle) free(conn->keepalives_idle); if (conn->keepalives_interval) free(conn->keepalives_interval); if (conn->keepalives_count) free(conn->keepalives_count); if (conn->sslmode) free(conn->sslmode); if (conn->sslcert) free(conn->sslcert); if (conn->sslkey) free(conn->sslkey); if (conn->sslrootcert) free(conn->sslrootcert); if (conn->sslcrl) free(conn->sslcrl); if (conn->requirepeer) free(conn->requirepeer); #if defined(KRB5) || defined(ENABLE_GSS) || defined(ENABLE_SSPI) if (conn->krbsrvname) free(conn->krbsrvname); #endif #if defined(ENABLE_GSS) && defined(ENABLE_SSPI) if (conn->gsslib) free(conn->gsslib); #endif /* Note that conn->Pfdebug is not ours to close or free */ if (conn->last_query) free(conn->last_query); if (conn->inBuffer) free(conn->inBuffer); if (conn->outBuffer) free(conn->outBuffer); termPQExpBuffer(&conn->errorMessage); termPQExpBuffer(&conn->workBuffer); free(conn); #ifdef WIN32 WSACleanup(); #endif } /* * closePGconn * - properly close a connection to the backend * * This should reset or release all transient state, but NOT the connection * parameters. On exit, the PGconn should be in condition to start a fresh * connection with the same parameters (see PQreset()). */ static void closePGconn(PGconn *conn) { PGnotify *notify; pgParameterStatus *pstatus; /* * Note that the protocol doesn't allow us to send Terminate messages * during the startup phase. */ if (conn->sock >= 0 && conn->status == CONNECTION_OK) { /* * Try to send "close connection" message to backend. Ignore any * error. */ pqPutMsgStart('X', false, conn); pqPutMsgEnd(conn); pqFlush(conn); } /* * Must reset the blocking status so a possible reconnect will work. * * Don't call PQsetnonblocking() because it will fail if it's unable to * flush the connection. */ conn->nonblocking = FALSE; /* * Close the connection, reset all transient state, flush I/O buffers. */ if (conn->sock >= 0) { pqsecure_close(conn); closesocket(conn->sock); } conn->sock = -1; conn->status = CONNECTION_BAD; /* Well, not really _bad_ - just * absent */ conn->asyncStatus = PGASYNC_IDLE; pqClearAsyncResult(conn); /* deallocate result and curTuple */ pg_freeaddrinfo_all(conn->addrlist_family, conn->addrlist); conn->addrlist = NULL; conn->addr_cur = NULL; notify = conn->notifyHead; while (notify != NULL) { PGnotify *prev = notify; notify = notify->next; free(prev); } conn->notifyHead = conn->notifyTail = NULL; pstatus = conn->pstatus; while (pstatus != NULL) { pgParameterStatus *prev = pstatus; pstatus = pstatus->next; free(prev); } conn->pstatus = NULL; if (conn->lobjfuncs) free(conn->lobjfuncs); conn->lobjfuncs = NULL; conn->inStart = conn->inCursor = conn->inEnd = 0; conn->outCount = 0; #ifdef ENABLE_GSS { OM_uint32 min_s; if (conn->gctx) gss_delete_sec_context(&min_s, &conn->gctx, GSS_C_NO_BUFFER); if (conn->gtarg_nam) gss_release_name(&min_s, &conn->gtarg_nam); if (conn->ginbuf.length) gss_release_buffer(&min_s, &conn->ginbuf); if (conn->goutbuf.length) gss_release_buffer(&min_s, &conn->goutbuf); } #endif #ifdef ENABLE_SSPI if (conn->ginbuf.length) free(conn->ginbuf.value); conn->ginbuf.length = 0; conn->ginbuf.value = NULL; if (conn->sspitarget) free(conn->sspitarget); conn->sspitarget = NULL; if (conn->sspicred) { FreeCredentialsHandle(conn->sspicred); free(conn->sspicred); conn->sspicred = NULL; } if (conn->sspictx) { DeleteSecurityContext(conn->sspictx); free(conn->sspictx); conn->sspictx = NULL; } #endif } /* * PQfinish: properly close a connection to the backend. Also frees * the PGconn data structure so it shouldn't be re-used after this. */ void PQfinish(PGconn *conn) { if (conn) { closePGconn(conn); freePGconn(conn); } } /* * PQreset: resets the connection to the backend by closing the * existing connection and creating a new one. */ void PQreset(PGconn *conn) { if (conn) { closePGconn(conn); if (connectDBStart(conn) && connectDBComplete(conn)) { /* * Notify event procs of successful reset. We treat an event proc * failure as disabling the connection ... good idea? */ int i; for (i = 0; i < conn->nEvents; i++) { PGEventConnReset evt; evt.conn = conn; if (!conn->events[i].proc(PGEVT_CONNRESET, &evt, conn->events[i].passThrough)) { conn->status = CONNECTION_BAD; printfPQExpBuffer(&conn->errorMessage, libpq_gettext("PGEventProc \"%s\" failed during PGEVT_CONNRESET event\n"), conn->events[i].name); break; } } } } } /* * PQresetStart: * resets the connection to the backend * closes the existing connection and makes a new one * Returns 1 on success, 0 on failure. */ int PQresetStart(PGconn *conn) { if (conn) { closePGconn(conn); return connectDBStart(conn); } return 0; } /* * PQresetPoll: * resets the connection to the backend * closes the existing connection and makes a new one */ PostgresPollingStatusType PQresetPoll(PGconn *conn) { if (conn) { PostgresPollingStatusType status = PQconnectPoll(conn); if (status == PGRES_POLLING_OK) { /* * Notify event procs of successful reset. We treat an event proc * failure as disabling the connection ... good idea? */ int i; for (i = 0; i < conn->nEvents; i++) { PGEventConnReset evt; evt.conn = conn; if (!conn->events[i].proc(PGEVT_CONNRESET, &evt, conn->events[i].passThrough)) { conn->status = CONNECTION_BAD; printfPQExpBuffer(&conn->errorMessage, libpq_gettext("PGEventProc \"%s\" failed during PGEVT_CONNRESET event\n"), conn->events[i].name); return PGRES_POLLING_FAILED; } } } return status; } return PGRES_POLLING_FAILED; } /* * PQcancelGet: get a PGcancel structure corresponding to a connection. * * A copy is needed to be able to cancel a running query from a different * thread. If the same structure is used all structure members would have * to be individually locked (if the entire structure was locked, it would * be impossible to cancel a synchronous query because the structure would * have to stay locked for the duration of the query). */ PGcancel * PQgetCancel(PGconn *conn) { PGcancel *cancel; if (!conn) return NULL; if (conn->sock < 0) return NULL; cancel = malloc(sizeof(PGcancel)); if (cancel == NULL) return NULL; memcpy(&cancel->raddr, &conn->raddr, sizeof(SockAddr)); cancel->be_pid = conn->be_pid; cancel->be_key = conn->be_key; return cancel; } /* PQfreeCancel: free a cancel structure */ void PQfreeCancel(PGcancel *cancel) { if (cancel) free(cancel); } /* * PQcancel and PQrequestCancel: attempt to request cancellation of the * current operation. * * The return value is TRUE if the cancel request was successfully * dispatched, FALSE if not (in which case an error message is available). * Note: successful dispatch is no guarantee that there will be any effect at * the backend. The application must read the operation result as usual. * * CAUTION: we want this routine to be safely callable from a signal handler * (for example, an application might want to call it in a SIGINT handler). * This means we cannot use any C library routine that might be non-reentrant. * malloc/free are often non-reentrant, and anything that might call them is * just as dangerous. We avoid sprintf here for that reason. Building up * error messages with strcpy/strcat is tedious but should be quite safe. * We also save/restore errno in case the signal handler support doesn't. * * internal_cancel() is an internal helper function to make code-sharing * between the two versions of the cancel function possible. */ static int internal_cancel(SockAddr *raddr, int be_pid, int be_key, char *errbuf, int errbufsize) { int save_errno = SOCK_ERRNO; int tmpsock = -1; char sebuf[256]; int maxlen; struct { uint32 packetlen; CancelRequestPacket cp; } crp; /* * We need to open a temporary connection to the postmaster. Do this with * only kernel calls. */ if ((tmpsock = socket(raddr->addr.ss_family, SOCK_STREAM, 0)) < 0) { strlcpy(errbuf, "PQcancel() -- socket() failed: ", errbufsize); goto cancel_errReturn; } retry3: if (connect(tmpsock, (struct sockaddr *) & raddr->addr, raddr->salen) < 0) { if (SOCK_ERRNO == EINTR) /* Interrupted system call - we'll just try again */ goto retry3; strlcpy(errbuf, "PQcancel() -- connect() failed: ", errbufsize); goto cancel_errReturn; } /* * We needn't set nonblocking I/O or NODELAY options here. */ /* Create and send the cancel request packet. */ crp.packetlen = htonl((uint32) sizeof(crp)); crp.cp.cancelRequestCode = (MsgType) htonl(CANCEL_REQUEST_CODE); crp.cp.backendPID = htonl(be_pid); crp.cp.cancelAuthCode = htonl(be_key); retry4: if (send(tmpsock, (char *) &crp, sizeof(crp), 0) != (int) sizeof(crp)) { if (SOCK_ERRNO == EINTR) /* Interrupted system call - we'll just try again */ goto retry4; strlcpy(errbuf, "PQcancel() -- send() failed: ", errbufsize); goto cancel_errReturn; } /* * Wait for the postmaster to close the connection, which indicates that * it's processed the request. Without this delay, we might issue another * command only to find that our cancel zaps that command instead of the * one we thought we were canceling. Note we don't actually expect this * read to obtain any data, we are just waiting for EOF to be signaled. */ retry5: if (recv(tmpsock, (char *) &crp, 1, 0) < 0) { if (SOCK_ERRNO == EINTR) /* Interrupted system call - we'll just try again */ goto retry5; /* we ignore other error conditions */ } /* All done */ closesocket(tmpsock); SOCK_ERRNO_SET(save_errno); return TRUE; cancel_errReturn: /* * Make sure we don't overflow the error buffer. Leave space for the \n at * the end, and for the terminating zero. */ maxlen = errbufsize - strlen(errbuf) - 2; if (maxlen >= 0) { strncat(errbuf, SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)), maxlen); strcat(errbuf, "\n"); } if (tmpsock >= 0) closesocket(tmpsock); SOCK_ERRNO_SET(save_errno); return FALSE; } /* * PQcancel: request query cancel * * Returns TRUE if able to send the cancel request, FALSE if not. * * On failure, an error message is stored in *errbuf, which must be of size * errbufsize (recommended size is 256 bytes). *errbuf is not changed on * success return. */ int PQcancel(PGcancel *cancel, char *errbuf, int errbufsize) { if (!cancel) { strlcpy(errbuf, "PQcancel() -- no cancel object supplied", errbufsize); return FALSE; } return internal_cancel(&cancel->raddr, cancel->be_pid, cancel->be_key, errbuf, errbufsize); } /* * PQrequestCancel: old, not thread-safe function for requesting query cancel * * Returns TRUE if able to send the cancel request, FALSE if not. * * On failure, the error message is saved in conn->errorMessage; this means * that this can't be used when there might be other active operations on * the connection object. * * NOTE: error messages will be cut off at the current size of the * error message buffer, since we dare not try to expand conn->errorMessage! */ int PQrequestCancel(PGconn *conn) { int r; /* Check we have an open connection */ if (!conn) return FALSE; if (conn->sock < 0) { strlcpy(conn->errorMessage.data, "PQrequestCancel() -- connection is not open\n", conn->errorMessage.maxlen); conn->errorMessage.len = strlen(conn->errorMessage.data); return FALSE; } r = internal_cancel(&conn->raddr, conn->be_pid, conn->be_key, conn->errorMessage.data, conn->errorMessage.maxlen); if (!r) conn->errorMessage.len = strlen(conn->errorMessage.data); return r; } /* * pqPacketSend() -- convenience routine to send a message to server. * * pack_type: the single-byte message type code. (Pass zero for startup * packets, which have no message type code.) * * buf, buf_len: contents of message. The given length includes only what * is in buf; the message type and message length fields are added here. * * RETURNS: STATUS_ERROR if the write fails, STATUS_OK otherwise. * SIDE_EFFECTS: may block. * * Note: all messages sent with this routine have a length word, whether * it's protocol 2.0 or 3.0. */ int pqPacketSend(PGconn *conn, char pack_type, const void *buf, size_t buf_len) { /* Start the message. */ if (pqPutMsgStart(pack_type, true, conn)) return STATUS_ERROR; /* Send the message body. */ if (pqPutnchar(buf, buf_len, conn)) return STATUS_ERROR; /* Finish the message. */ if (pqPutMsgEnd(conn)) return STATUS_ERROR; /* Flush to ensure backend gets it. */ if (pqFlush(conn)) return STATUS_ERROR; return STATUS_OK; } #ifdef USE_LDAP #define LDAP_URL "ldap://" #define LDAP_DEF_PORT 389 #define PGLDAP_TIMEOUT 2 #define ld_is_sp_tab(x) ((x) == ' ' || (x) == '\t') #define ld_is_nl_cr(x) ((x) == '\r' || (x) == '\n') /* * ldapServiceLookup * * Search the LDAP URL passed as first argument, treat the result as a * string of connection options that are parsed and added to the array of * options passed as second argument. * * LDAP URLs must conform to RFC 1959 without escape sequences. * ldap://host:port/dn?attributes?scope?filter?extensions * * Returns * 0 if the lookup was successful, * 1 if the connection to the LDAP server could be established but * the search was unsuccessful, * 2 if a connection could not be established, and * 3 if a fatal error occurred. * * An error message is returned in the third argument for return codes 1 and 3. */ static int ldapServiceLookup(const char *purl, PQconninfoOption *options, PQExpBuffer errorMessage) { int port = LDAP_DEF_PORT, scope, rc, msgid, size, state, oldstate, i; bool found_keyword; char *url, *hostname, *portstr, *endptr, *dn, *scopestr, *filter, *result, *p, *p1 = NULL, *optname = NULL, *optval = NULL; char *attrs[2] = {NULL, NULL}; LDAP *ld = NULL; LDAPMessage *res, *entry; struct berval **values; LDAP_TIMEVAL time = {PGLDAP_TIMEOUT, 0}; if ((url = strdup(purl)) == NULL) { printfPQExpBuffer(errorMessage, libpq_gettext("out of memory\n")); return 3; } /* * Parse URL components, check for correctness. Basically, url has '\0' * placed at component boundaries and variables are pointed at each * component. */ if (pg_strncasecmp(url, LDAP_URL, strlen(LDAP_URL)) != 0) { printfPQExpBuffer(errorMessage, libpq_gettext("invalid LDAP URL \"%s\": scheme must be ldap://\n"), purl); free(url); return 3; } /* hostname */ hostname = url + strlen(LDAP_URL); if (*hostname == '/') /* no hostname? */ hostname = DefaultHost; /* the default */ /* dn, "distinguished name" */ p = strchr(url + strlen(LDAP_URL), '/'); if (p == NULL || *(p + 1) == '\0' || *(p + 1) == '?') { printfPQExpBuffer(errorMessage, libpq_gettext( "invalid LDAP URL \"%s\": missing distinguished name\n"), purl); free(url); return 3; } *p = '\0'; /* terminate hostname */ dn = p + 1; /* attribute */ if ((p = strchr(dn, '?')) == NULL || *(p + 1) == '\0' || *(p + 1) == '?') { printfPQExpBuffer(errorMessage, libpq_gettext( "invalid LDAP URL \"%s\": must have exactly one attribute\n"), purl); free(url); return 3; } *p = '\0'; attrs[0] = p + 1; /* scope */ if ((p = strchr(attrs[0], '?')) == NULL || *(p + 1) == '\0' || *(p + 1) == '?') { printfPQExpBuffer(errorMessage, libpq_gettext("invalid LDAP URL \"%s\": must have search scope (base/one/sub)\n"), purl); free(url); return 3; } *p = '\0'; scopestr = p + 1; /* filter */ if ((p = strchr(scopestr, '?')) == NULL || *(p + 1) == '\0' || *(p + 1) == '?') { printfPQExpBuffer(errorMessage, libpq_gettext("invalid LDAP URL \"%s\": no filter\n"), purl); free(url); return 3; } *p = '\0'; filter = p + 1; if ((p = strchr(filter, '?')) != NULL) *p = '\0'; /* port number? */ if ((p1 = strchr(hostname, ':')) != NULL) { long lport; *p1 = '\0'; portstr = p1 + 1; errno = 0; lport = strtol(portstr, &endptr, 10); if (*portstr == '\0' || *endptr != '\0' || errno || lport < 0 || lport > 65535) { printfPQExpBuffer(errorMessage, libpq_gettext( "invalid LDAP URL \"%s\": invalid port number\n"), purl); free(url); return 3; } port = (int) lport; } /* Allow only one attribute */ if (strchr(attrs[0], ',') != NULL) { printfPQExpBuffer(errorMessage, libpq_gettext( "invalid LDAP URL \"%s\": must have exactly one attribute\n"), purl); free(url); return 3; } /* set scope */ if (pg_strcasecmp(scopestr, "base") == 0) scope = LDAP_SCOPE_BASE; else if (pg_strcasecmp(scopestr, "one") == 0) scope = LDAP_SCOPE_ONELEVEL; else if (pg_strcasecmp(scopestr, "sub") == 0) scope = LDAP_SCOPE_SUBTREE; else { printfPQExpBuffer(errorMessage, libpq_gettext("invalid LDAP URL \"%s\": must have search scope (base/one/sub)\n"), purl); free(url); return 3; } /* initialize LDAP structure */ if ((ld = ldap_init(hostname, port)) == NULL) { printfPQExpBuffer(errorMessage, libpq_gettext("could not create LDAP structure\n")); free(url); return 3; } /* * Initialize connection to the server. We do an explicit bind because we * want to return 2 if the bind fails. */ if ((msgid = ldap_simple_bind(ld, NULL, NULL)) == -1) { /* error in ldap_simple_bind() */ free(url); ldap_unbind(ld); return 2; } /* wait some time for the connection to succeed */ res = NULL; if ((rc = ldap_result(ld, msgid, LDAP_MSG_ALL, &time, &res)) == -1 || res == NULL) { if (res != NULL) { /* timeout */ ldap_msgfree(res); } /* error in ldap_result() */ free(url); ldap_unbind(ld); return 2; } ldap_msgfree(res); /* search */ res = NULL; if ((rc = ldap_search_st(ld, dn, scope, filter, attrs, 0, &time, &res)) != LDAP_SUCCESS) { if (res != NULL) ldap_msgfree(res); printfPQExpBuffer(errorMessage, libpq_gettext("lookup on LDAP server failed: %s\n"), ldap_err2string(rc)); ldap_unbind(ld); free(url); return 1; } /* complain if there was not exactly one result */ if ((rc = ldap_count_entries(ld, res)) != 1) { printfPQExpBuffer(errorMessage, rc ? libpq_gettext("more than one entry found on LDAP lookup\n") : libpq_gettext("no entry found on LDAP lookup\n")); ldap_msgfree(res); ldap_unbind(ld); free(url); return 1; } /* get entry */ if ((entry = ldap_first_entry(ld, res)) == NULL) { /* should never happen */ printfPQExpBuffer(errorMessage, libpq_gettext("no entry found on LDAP lookup\n")); ldap_msgfree(res); ldap_unbind(ld); free(url); return 1; } /* get values */ if ((values = ldap_get_values_len(ld, entry, attrs[0])) == NULL) { printfPQExpBuffer(errorMessage, libpq_gettext("attribute has no values on LDAP lookup\n")); ldap_msgfree(res); ldap_unbind(ld); free(url); return 1; } ldap_msgfree(res); free(url); if (values[0] == NULL) { printfPQExpBuffer(errorMessage, libpq_gettext("attribute has no values on LDAP lookup\n")); ldap_value_free_len(values); ldap_unbind(ld); return 1; } /* concatenate values into a single string with newline terminators */ size = 1; /* for the trailing null */ for (i = 0; values[i] != NULL; i++) size += values[i]->bv_len + 1; if ((result = malloc(size)) == NULL) { printfPQExpBuffer(errorMessage, libpq_gettext("out of memory\n")); ldap_value_free_len(values); ldap_unbind(ld); return 3; } p = result; for (i = 0; values[i] != NULL; i++) { memcpy(p, values[i]->bv_val, values[i]->bv_len); p += values[i]->bv_len; *(p++) = '\n'; } *p = '\0'; ldap_value_free_len(values); ldap_unbind(ld); /* parse result string */ oldstate = state = 0; for (p = result; *p != '\0'; ++p) { switch (state) { case 0: /* between entries */ if (!ld_is_sp_tab(*p) && !ld_is_nl_cr(*p)) { optname = p; state = 1; } break; case 1: /* in option name */ if (ld_is_sp_tab(*p)) { *p = '\0'; state = 2; } else if (ld_is_nl_cr(*p)) { printfPQExpBuffer(errorMessage, libpq_gettext( "missing \"=\" after \"%s\" in connection info string\n"), optname); free(result); return 3; } else if (*p == '=') { *p = '\0'; state = 3; } break; case 2: /* after option name */ if (*p == '=') { state = 3; } else if (!ld_is_sp_tab(*p)) { printfPQExpBuffer(errorMessage, libpq_gettext( "missing \"=\" after \"%s\" in connection info string\n"), optname); free(result); return 3; } break; case 3: /* before option value */ if (*p == '\'') { optval = p + 1; p1 = p + 1; state = 5; } else if (ld_is_nl_cr(*p)) { optval = optname + strlen(optname); /* empty */ state = 0; } else if (!ld_is_sp_tab(*p)) { optval = p; state = 4; } break; case 4: /* in unquoted option value */ if (ld_is_sp_tab(*p) || ld_is_nl_cr(*p)) { *p = '\0'; state = 0; } break; case 5: /* in quoted option value */ if (*p == '\'') { *p1 = '\0'; state = 0; } else if (*p == '\\') state = 6; else *(p1++) = *p; break; case 6: /* in quoted option value after escape */ *(p1++) = *p; state = 5; break; } if (state == 0 && oldstate != 0) { found_keyword = false; for (i = 0; options[i].keyword; i++) { if (strcmp(options[i].keyword, optname) == 0) { if (options[i].val == NULL) options[i].val = strdup(optval); found_keyword = true; break; } } if (!found_keyword) { printfPQExpBuffer(errorMessage, libpq_gettext("invalid connection option \"%s\"\n"), optname); free(result); return 1; } optname = NULL; optval = NULL; } oldstate = state; } free(result); if (state == 5 || state == 6) { printfPQExpBuffer(errorMessage, libpq_gettext( "unterminated quoted string in connection info string\n")); return 3; } return 0; } #endif #define MAXBUFSIZE 256 static int parseServiceInfo(PQconninfoOption *options, PQExpBuffer errorMessage) { char *service = conninfo_getval(options, "service"); char serviceFile[MAXPGPATH]; char *env; bool group_found = false; int status; struct stat stat_buf; /* * We have to special-case the environment variable PGSERVICE here, since * this is and should be called before inserting environment defaults for * other connection options. */ if (service == NULL) service = getenv("PGSERVICE"); if (service == NULL) return 0; if ((env = getenv("PGSERVICEFILE")) != NULL) strlcpy(serviceFile, env, sizeof(serviceFile)); else { char homedir[MAXPGPATH]; if (!pqGetHomeDirectory(homedir, sizeof(homedir))) { printfPQExpBuffer(errorMessage, libpq_gettext("could not get home directory to locate service definition file")); return 1; } snprintf(serviceFile, MAXPGPATH, "%s/%s", homedir, ".pg_service.conf"); errno = 0; if (stat(serviceFile, &stat_buf) != 0 && errno == ENOENT) goto next_file; } status = parseServiceFile(serviceFile, service, options, errorMessage, &group_found); if (group_found || status != 0) return status; next_file: /* * This could be used by any application so we can't use the binary * location to find our config files. */ snprintf(serviceFile, MAXPGPATH, "%s/pg_service.conf", getenv("PGSYSCONFDIR") ? getenv("PGSYSCONFDIR") : SYSCONFDIR); errno = 0; if (stat(serviceFile, &stat_buf) != 0 && errno == ENOENT) goto last_file; status = parseServiceFile(serviceFile, service, options, errorMessage, &group_found); if (status != 0) return status; last_file: if (!group_found) { printfPQExpBuffer(errorMessage, libpq_gettext("definition of service \"%s\" not found\n"), service); return 3; } return 0; } static int parseServiceFile(const char *serviceFile, const char *service, PQconninfoOption *options, PQExpBuffer errorMessage, bool *group_found) { int linenr = 0, i; FILE *f; char buf[MAXBUFSIZE], *line; f = fopen(serviceFile, "r"); if (f == NULL) { printfPQExpBuffer(errorMessage, libpq_gettext("service file \"%s\" not found\n"), serviceFile); return 1; } while ((line = fgets(buf, sizeof(buf), f)) != NULL) { linenr++; if (strlen(line) >= sizeof(buf) - 1) { fclose(f); printfPQExpBuffer(errorMessage, libpq_gettext("line %d too long in service file \"%s\"\n"), linenr, serviceFile); return 2; } /* ignore EOL at end of line */ if (strlen(line) && line[strlen(line) - 1] == '\n') line[strlen(line) - 1] = 0; /* ignore leading blanks */ while (*line && isspace((unsigned char) line[0])) line++; /* ignore comments and empty lines */ if (strlen(line) == 0 || line[0] == '#') continue; /* Check for right groupname */ if (line[0] == '[') { if (*group_found) { /* group info already read */ fclose(f); return 0; } if (strncmp(line + 1, service, strlen(service)) == 0 && line[strlen(service) + 1] == ']') *group_found = true; else *group_found = false; } else { if (*group_found) { /* * Finally, we are in the right group and can parse the line */ char *key, *val; bool found_keyword; #ifdef USE_LDAP if (strncmp(line, "ldap", 4) == 0) { int rc = ldapServiceLookup(line, options, errorMessage); /* if rc = 2, go on reading for fallback */ switch (rc) { case 0: fclose(f); return 0; case 1: case 3: fclose(f); return 3; case 2: continue; } } #endif key = line; val = strchr(line, '='); if (val == NULL) { printfPQExpBuffer(errorMessage, libpq_gettext("syntax error in service file \"%s\", line %d\n"), serviceFile, linenr); fclose(f); return 3; } *val++ = '\0'; /* * Set the parameter --- but don't override any previous * explicit setting. */ found_keyword = false; for (i = 0; options[i].keyword; i++) { if (strcmp(options[i].keyword, key) == 0) { if (options[i].val == NULL) options[i].val = strdup(val); found_keyword = true; break; } } if (!found_keyword) { printfPQExpBuffer(errorMessage, libpq_gettext("syntax error in service file \"%s\", line %d\n"), serviceFile, linenr); fclose(f); return 3; } } } } fclose(f); return 0; } /* * PQconninfoParse * * Parse a string like PQconnectdb() would do and return the * resulting connection options array. NULL is returned on failure. * The result contains only options specified directly in the string, * not any possible default values. * * If errmsg isn't NULL, *errmsg is set to NULL on success, or a malloc'd * string on failure (use PQfreemem to free it). In out-of-memory conditions * both *errmsg and the result could be NULL. * * NOTE: the returned array is dynamically allocated and should * be freed when no longer needed via PQconninfoFree(). */ PQconninfoOption * PQconninfoParse(const char *conninfo, char **errmsg) { PQExpBufferData errorBuf; PQconninfoOption *connOptions; if (errmsg) *errmsg = NULL; /* default */ initPQExpBuffer(&errorBuf); if (PQExpBufferBroken(&errorBuf)) return NULL; /* out of memory already :-( */ connOptions = conninfo_parse(conninfo, &errorBuf, false); if (connOptions == NULL && errmsg) *errmsg = errorBuf.data; else termPQExpBuffer(&errorBuf); return connOptions; } /* * Conninfo parser routine * * If successful, a malloc'd PQconninfoOption array is returned. * If not successful, NULL is returned and an error message is * left in errorMessage. * Defaults are supplied (from a service file, environment variables, etc) * for unspecified options, but only if use_defaults is TRUE. */ static PQconninfoOption * conninfo_parse(const char *conninfo, PQExpBuffer errorMessage, bool use_defaults) { char *pname; char *pval; char *buf; char *tmp; char *cp; char *cp2; PQconninfoOption *options; PQconninfoOption *option; /* Make a working copy of PQconninfoOptions */ options = malloc(sizeof(PQconninfoOptions)); if (options == NULL) { printfPQExpBuffer(errorMessage, libpq_gettext("out of memory\n")); return NULL; } memcpy(options, PQconninfoOptions, sizeof(PQconninfoOptions)); /* Need a modifiable copy of the input string */ if ((buf = strdup(conninfo)) == NULL) { printfPQExpBuffer(errorMessage, libpq_gettext("out of memory\n")); PQconninfoFree(options); return NULL; } cp = buf; while (*cp) { /* Skip blanks before the parameter name */ if (isspace((unsigned char) *cp)) { cp++; continue; } /* Get the parameter name */ pname = cp; while (*cp) { if (*cp == '=') break; if (isspace((unsigned char) *cp)) { *cp++ = '\0'; while (*cp) { if (!isspace((unsigned char) *cp)) break; cp++; } break; } cp++; } /* Check that there is a following '=' */ if (*cp != '=') { printfPQExpBuffer(errorMessage, libpq_gettext("missing \"=\" after \"%s\" in connection info string\n"), pname); PQconninfoFree(options); free(buf); return NULL; } *cp++ = '\0'; /* Skip blanks after the '=' */ while (*cp) { if (!isspace((unsigned char) *cp)) break; cp++; } /* Get the parameter value */ pval = cp; if (*cp != '\'') { cp2 = pval; while (*cp) { if (isspace((unsigned char) *cp)) { *cp++ = '\0'; break; } if (*cp == '\\') { cp++; if (*cp != '\0') *cp2++ = *cp++; } else *cp2++ = *cp++; } *cp2 = '\0'; } else { cp2 = pval; cp++; for (;;) { if (*cp == '\0') { printfPQExpBuffer(errorMessage, libpq_gettext("unterminated quoted string in connection info string\n")); PQconninfoFree(options); free(buf); return NULL; } if (*cp == '\\') { cp++; if (*cp != '\0') *cp2++ = *cp++; continue; } if (*cp == '\'') { *cp2 = '\0'; cp++; break; } *cp2++ = *cp++; } } /* * Now we have the name and the value. Search for the param record. */ for (option = options; option->keyword != NULL; option++) { if (strcmp(option->keyword, pname) == 0) break; } if (option->keyword == NULL) { printfPQExpBuffer(errorMessage, libpq_gettext("invalid connection option \"%s\"\n"), pname); PQconninfoFree(options); free(buf); return NULL; } /* * Store the value */ if (option->val) free(option->val); option->val = strdup(pval); if (!option->val) { printfPQExpBuffer(errorMessage, libpq_gettext("out of memory\n")); PQconninfoFree(options); free(buf); return NULL; } } /* Done with the modifiable input string */ free(buf); /* * Stop here if caller doesn't want defaults filled in. */ if (!use_defaults) return options; /* * If there's a service spec, use it to obtain any not-explicitly-given * parameters. */ if (parseServiceInfo(options, errorMessage)) { PQconninfoFree(options); return NULL; } /* * Get the fallback resources for parameters not specified in the conninfo * string nor the service. */ for (option = options; option->keyword != NULL; option++) { if (option->val != NULL) continue; /* Value was in conninfo or service */ /* * Try to get the environment variable fallback */ if (option->envvar != NULL) { if ((tmp = getenv(option->envvar)) != NULL) { option->val = strdup(tmp); if (!option->val) { printfPQExpBuffer(errorMessage, libpq_gettext("out of memory\n")); PQconninfoFree(options); return NULL; } continue; } } /* * No environment variable specified or this one isn't set - try * compiled in */ if (option->compiled != NULL) { option->val = strdup(option->compiled); if (!option->val) { printfPQExpBuffer(errorMessage, libpq_gettext("out of memory\n")); PQconninfoFree(options); return NULL; } continue; } /* * Special handling for user */ if (strcmp(option->keyword, "user") == 0) { option->val = pg_fe_getauthname(errorMessage); continue; } } return options; } /* * Conninfo array parser routine * * If successful, a malloc'd PQconninfoOption array is returned. * If not successful, NULL is returned and an error message is * left in errorMessage. * Defaults are supplied (from a service file, environment variables, etc) * for unspecified options, but only if use_defaults is TRUE. * * If expand_dbname is non-zero, and the value passed for keyword "dbname" * contains an "=", assume it is a conninfo string and process it, * overriding any previously processed conflicting keywords. Subsequent * keywords will take precedence, however. */ static PQconninfoOption * conninfo_array_parse(const char **keywords, const char **values, PQExpBuffer errorMessage, bool use_defaults, int expand_dbname) { char *tmp; PQconninfoOption *options; PQconninfoOption *str_options = NULL; PQconninfoOption *option; int i = 0; /* * If expand_dbname is non-zero, check keyword "dbname" to see if val is * actually a conninfo string */ while (expand_dbname && keywords[i]) { const char *pname = keywords[i]; const char *pvalue = values[i]; /* first find "dbname" if any */ if (strcmp(pname, "dbname") == 0) { /* next look for "=" in the value */ if (pvalue && strchr(pvalue, '=')) { /* * Must be a conninfo string, so parse it, but do not use * defaults here -- those get picked up later. We only want to * override for those parameters actually passed. */ str_options = conninfo_parse(pvalue, errorMessage, false); if (str_options == NULL) return NULL; } break; } ++i; } /* Make a working copy of PQconninfoOptions */ options = malloc(sizeof(PQconninfoOptions)); if (options == NULL) { printfPQExpBuffer(errorMessage, libpq_gettext("out of memory\n")); return NULL; } memcpy(options, PQconninfoOptions, sizeof(PQconninfoOptions)); i = 0; /* Parse the keywords/values arrays */ while (keywords[i]) { const char *pname = keywords[i]; const char *pvalue = values[i]; if (pvalue != NULL) { /* Search for the param record */ for (option = options; option->keyword != NULL; option++) { if (strcmp(option->keyword, pname) == 0) break; } /* Check for invalid connection option */ if (option->keyword == NULL) { printfPQExpBuffer(errorMessage, libpq_gettext("invalid connection option \"%s\"\n"), pname); PQconninfoFree(options); return NULL; } /* * If we are on the dbname parameter, and we have a parsed * conninfo string, copy those parameters across, overriding any * existing previous settings */ if (strcmp(pname, "dbname") == 0 && str_options) { PQconninfoOption *str_option; for (str_option = str_options; str_option->keyword != NULL; str_option++) { if (str_option->val != NULL) { int k; for (k = 0; options[k].keyword; k++) { if (strcmp(options[k].keyword, str_option->keyword) == 0) { if (options[k].val) free(options[k].val); options[k].val = strdup(str_option->val); break; } } } } } else { /* * Store the value, overriding previous settings */ if (option->val) free(option->val); option->val = strdup(pvalue); if (!option->val) { printfPQExpBuffer(errorMessage, libpq_gettext("out of memory\n")); PQconninfoFree(options); return NULL; } } } ++i; } PQconninfoFree(str_options); /* * Stop here if caller doesn't want defaults filled in. */ if (!use_defaults) return options; /* * If there's a service spec, use it to obtain any not-explicitly-given * parameters. */ if (parseServiceInfo(options, errorMessage)) { PQconninfoFree(options); return NULL; } /* * Get the fallback resources for parameters not specified in the conninfo * string nor the service. */ for (option = options; option->keyword != NULL; option++) { if (option->val != NULL) continue; /* Value was in conninfo or service */ /* * Try to get the environment variable fallback */ if (option->envvar != NULL) { if ((tmp = getenv(option->envvar)) != NULL) { option->val = strdup(tmp); if (!option->val) { printfPQExpBuffer(errorMessage, libpq_gettext("out of memory\n")); PQconninfoFree(options); return NULL; } continue; } } /* * No environment variable specified or this one isn't set - try * compiled in */ if (option->compiled != NULL) { option->val = strdup(option->compiled); if (!option->val) { printfPQExpBuffer(errorMessage, libpq_gettext("out of memory\n")); PQconninfoFree(options); return NULL; } continue; } /* * Special handling for user */ if (strcmp(option->keyword, "user") == 0) { option->val = pg_fe_getauthname(errorMessage); continue; } } return options; } static char * conninfo_getval(PQconninfoOption *connOptions, const char *keyword) { PQconninfoOption *option; for (option = connOptions; option->keyword != NULL; option++) { if (strcmp(option->keyword, keyword) == 0) return option->val; } return NULL; } void PQconninfoFree(PQconninfoOption *connOptions) { PQconninfoOption *option; if (connOptions == NULL) return; for (option = connOptions; option->keyword != NULL; option++) { if (option->val != NULL) free(option->val); } free(connOptions); } /* =========== accessor functions for PGconn ========= */ char * PQdb(const PGconn *conn) { if (!conn) return NULL; return conn->dbName; } char * PQuser(const PGconn *conn) { if (!conn) return NULL; return conn->pguser; } char * PQpass(const PGconn *conn) { if (!conn) return NULL; return conn->pgpass; } char * PQhost(const PGconn *conn) { if (!conn) return NULL; return conn->pghost ? conn->pghost : conn->pgunixsocket; } char * PQport(const PGconn *conn) { if (!conn) return NULL; return conn->pgport; } char * PQtty(const PGconn *conn) { if (!conn) return NULL; return conn->pgtty; } char * PQoptions(const PGconn *conn) { if (!conn) return NULL; return conn->pgoptions; } ConnStatusType PQstatus(const PGconn *conn) { if (!conn) return CONNECTION_BAD; return conn->status; } PGTransactionStatusType PQtransactionStatus(const PGconn *conn) { if (!conn || conn->status != CONNECTION_OK) return PQTRANS_UNKNOWN; if (conn->asyncStatus != PGASYNC_IDLE) return PQTRANS_ACTIVE; return conn->xactStatus; } const char * PQparameterStatus(const PGconn *conn, const char *paramName) { const pgParameterStatus *pstatus; if (!conn || !paramName) return NULL; for (pstatus = conn->pstatus; pstatus != NULL; pstatus = pstatus->next) { if (strcmp(pstatus->name, paramName) == 0) return pstatus->value; } return NULL; } int PQprotocolVersion(const PGconn *conn) { if (!conn) return 0; if (conn->status == CONNECTION_BAD) return 0; return PG_PROTOCOL_MAJOR(conn->pversion); } int PQserverVersion(const PGconn *conn) { if (!conn) return 0; if (conn->status == CONNECTION_BAD) return 0; return conn->sversion; } char * PQerrorMessage(const PGconn *conn) { if (!conn) return libpq_gettext("connection pointer is NULL\n"); return conn->errorMessage.data; } int PQsocket(const PGconn *conn) { if (!conn) return -1; return conn->sock; } int PQbackendPID(const PGconn *conn) { if (!conn || conn->status != CONNECTION_OK) return 0; return conn->be_pid; } int PQconnectionNeedsPassword(const PGconn *conn) { if (!conn) return false; if (conn->password_needed && (conn->pgpass == NULL || conn->pgpass[0] == '\0')) return true; else return false; } int PQconnectionUsedPassword(const PGconn *conn) { if (!conn) return false; if (conn->password_needed) return true; else return false; } int PQclientEncoding(const PGconn *conn) { if (!conn || conn->status != CONNECTION_OK) return -1; return conn->client_encoding; } int PQsetClientEncoding(PGconn *conn, const char *encoding) { char qbuf[128]; static const char query[] = "set client_encoding to '%s'"; PGresult *res; int status; if (!conn || conn->status != CONNECTION_OK) return -1; if (!encoding) return -1; /* Resolve special "auto" value from the locale */ if (strcmp(encoding, "auto") == 0) encoding = pg_encoding_to_char(pg_get_encoding_from_locale(NULL, true)); /* check query buffer overflow */ if (sizeof(qbuf) < (sizeof(query) + strlen(encoding))) return -1; /* ok, now send a query */ sprintf(qbuf, query, encoding); res = PQexec(conn, qbuf); if (res == NULL) return -1; if (res->resultStatus != PGRES_COMMAND_OK) status = -1; else { /* * In protocol 2 we have to assume the setting will stick, and adjust * our state immediately. In protocol 3 and up we can rely on the * backend to report the parameter value, and we'll change state at * that time. */ if (PG_PROTOCOL_MAJOR(conn->pversion) < 3) pqSaveParameterStatus(conn, "client_encoding", encoding); status = 0; /* everything is ok */ } PQclear(res); return status; } PGVerbosity PQsetErrorVerbosity(PGconn *conn, PGVerbosity verbosity) { PGVerbosity old; if (!conn) return PQERRORS_DEFAULT; old = conn->verbosity; conn->verbosity = verbosity; return old; } void PQtrace(PGconn *conn, FILE *debug_port) { if (conn == NULL) return; PQuntrace(conn); conn->Pfdebug = debug_port; } void PQuntrace(PGconn *conn) { if (conn == NULL) return; if (conn->Pfdebug) { fflush(conn->Pfdebug); conn->Pfdebug = NULL; } } PQnoticeReceiver PQsetNoticeReceiver(PGconn *conn, PQnoticeReceiver proc, void *arg) { PQnoticeReceiver old; if (conn == NULL) return NULL; old = conn->noticeHooks.noticeRec; if (proc) { conn->noticeHooks.noticeRec = proc; conn->noticeHooks.noticeRecArg = arg; } return old; } PQnoticeProcessor PQsetNoticeProcessor(PGconn *conn, PQnoticeProcessor proc, void *arg) { PQnoticeProcessor old; if (conn == NULL) return NULL; old = conn->noticeHooks.noticeProc; if (proc) { conn->noticeHooks.noticeProc = proc; conn->noticeHooks.noticeProcArg = arg; } return old; } /* * The default notice message receiver just gets the standard notice text * and sends it to the notice processor. This two-level setup exists * mostly for backwards compatibility; perhaps we should deprecate use of * PQsetNoticeProcessor? */ static void defaultNoticeReceiver(void *arg, const PGresult *res) { (void) arg; /* not used */ if (res->noticeHooks.noticeProc != NULL) (*res->noticeHooks.noticeProc) (res->noticeHooks.noticeProcArg, PQresultErrorMessage(res)); } /* * The default notice message processor just prints the * message on stderr. Applications can override this if they * want the messages to go elsewhere (a window, for example). * Note that simply discarding notices is probably a bad idea. */ static void defaultNoticeProcessor(void *arg, const char *message) { (void) arg; /* not used */ /* Note: we expect the supplied string to end with a newline already. */ fprintf(stderr, "%s", message); } /* * returns a pointer to the next token or NULL if the current * token doesn't match */ static char * pwdfMatchesString(char *buf, char *token) { char *tbuf, *ttok; bool bslash = false; if (buf == NULL || token == NULL) return NULL; tbuf = buf; ttok = token; if (tbuf[0] == '*' && tbuf[1] == ':') return tbuf + 2; while (*tbuf != 0) { if (*tbuf == '\\' && !bslash) { tbuf++; bslash = true; } if (*tbuf == ':' && *ttok == 0 && !bslash) return tbuf + 1; bslash = false; if (*ttok == 0) return NULL; if (*tbuf == *ttok) { tbuf++; ttok++; } else return NULL; } return NULL; } /* Get a password from the password file. Return value is malloc'd. */ static char * PasswordFromFile(char *hostname, char *port, char *dbname, char *username) { FILE *fp; char pgpassfile[MAXPGPATH]; struct stat stat_buf; #define LINELEN NAMEDATALEN*5 char buf[LINELEN]; if (dbname == NULL || strlen(dbname) == 0) return NULL; if (username == NULL || strlen(username) == 0) return NULL; /* 'localhost' matches pghost of '' or the default socket directory */ if (hostname == NULL) hostname = DefaultHost; else if (is_absolute_path(hostname)) /* * We should probably use canonicalize_path(), but then we have to * bring path.c into libpq, and it doesn't seem worth it. */ if (strcmp(hostname, DEFAULT_PGSOCKET_DIR) == 0) hostname = DefaultHost; if (port == NULL) port = DEF_PGPORT_STR; if (!getPgPassFilename(pgpassfile)) return NULL; /* If password file cannot be opened, ignore it. */ if (stat(pgpassfile, &stat_buf) != 0) return NULL; #ifndef WIN32 if (!S_ISREG(stat_buf.st_mode)) { fprintf(stderr, libpq_gettext("WARNING: password file \"%s\" is not a plain file\n"), pgpassfile); return NULL; } /* If password file is insecure, alert the user and ignore it. */ if (stat_buf.st_mode & (S_IRWXG | S_IRWXO)) { fprintf(stderr, libpq_gettext("WARNING: password file \"%s\" has group or world access; permissions should be u=rw (0600) or less\n"), pgpassfile); return NULL; } #else /* * On Win32, the directory is protected, so we don't have to check the * file. */ #endif fp = fopen(pgpassfile, "r"); if (fp == NULL) return NULL; while (!feof(fp) && !ferror(fp)) { char *t = buf, *ret; int len; if (fgets(buf, sizeof(buf), fp) == NULL) break; len = strlen(buf); if (len == 0) continue; /* Remove trailing newline */ if (buf[len - 1] == '\n') buf[len - 1] = 0; if ((t = pwdfMatchesString(t, hostname)) == NULL || (t = pwdfMatchesString(t, port)) == NULL || (t = pwdfMatchesString(t, dbname)) == NULL || (t = pwdfMatchesString(t, username)) == NULL) continue; ret = strdup(t); fclose(fp); return ret; } fclose(fp); return NULL; #undef LINELEN } static bool getPgPassFilename(char *pgpassfile) { char *passfile_env; if ((passfile_env = getenv("PGPASSFILE")) != NULL) /* use the literal path from the environment, if set */ strlcpy(pgpassfile, passfile_env, MAXPGPATH); else { char homedir[MAXPGPATH]; if (!pqGetHomeDirectory(homedir, sizeof(homedir))) return false; snprintf(pgpassfile, MAXPGPATH, "%s/%s", homedir, PGPASSFILE); } return true; } /* * If the connection failed, we should mention if * we got the password from .pgpass in case that * password is wrong. */ static void dot_pg_pass_warning(PGconn *conn) { /* If it was 'invalid authorization', add .pgpass mention */ if (conn->dot_pgpass_used && conn->password_needed && conn->result && /* only works with >= 9.0 servers */ strcmp(PQresultErrorField(conn->result, PG_DIAG_SQLSTATE), ERRCODE_INVALID_PASSWORD) == 0) { char pgpassfile[MAXPGPATH]; if (!getPgPassFilename(pgpassfile)) return; appendPQExpBuffer(&conn->errorMessage, libpq_gettext("password retrieved from file \"%s\"\n"), pgpassfile); } } /* * Obtain user's home directory, return in given buffer * * On Unix, this actually returns the user's home directory. On Windows * it returns the PostgreSQL-specific application data folder. * * This is essentially the same as get_home_path(), but we don't use that * because we don't want to pull path.c into libpq (it pollutes application * namespace) */ bool pqGetHomeDirectory(char *buf, int bufsize) { #ifndef WIN32 char pwdbuf[BUFSIZ]; struct passwd pwdstr; struct passwd *pwd = NULL; if (pqGetpwuid(geteuid(), &pwdstr, pwdbuf, sizeof(pwdbuf), &pwd) != 0) return false; strlcpy(buf, pwd->pw_dir, bufsize); return true; #else char tmppath[MAX_PATH]; ZeroMemory(tmppath, sizeof(tmppath)); if (SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, tmppath) != S_OK) return false; snprintf(buf, bufsize, "%s/postgresql", tmppath); return true; #endif } /* * To keep the API consistent, the locking stubs are always provided, even * if they are not required. */ static void default_threadlock(int acquire) { #ifdef ENABLE_THREAD_SAFETY #ifndef WIN32 static pthread_mutex_t singlethread_lock = PTHREAD_MUTEX_INITIALIZER; #else static pthread_mutex_t singlethread_lock = NULL; static long mutex_initlock = 0; if (singlethread_lock == NULL) { while (InterlockedExchange(&mutex_initlock, 1) == 1) /* loop, another thread own the lock */ ; if (singlethread_lock == NULL) { if (pthread_mutex_init(&singlethread_lock, NULL)) PGTHREAD_ERROR("failed to initialize mutex"); } InterlockedExchange(&mutex_initlock, 0); } #endif if (acquire) { if (pthread_mutex_lock(&singlethread_lock)) PGTHREAD_ERROR("failed to lock mutex"); } else { if (pthread_mutex_unlock(&singlethread_lock)) PGTHREAD_ERROR("failed to unlock mutex"); } #endif } pgthreadlock_t PQregisterThreadLock(pgthreadlock_t newhandler) { pgthreadlock_t prev = pg_g_threadlock; if (newhandler) pg_g_threadlock = newhandler; else pg_g_threadlock = default_threadlock; return prev; } RPostgreSQL/src/libpq/win32.c0000644000176000001440000001347512124517222015443 0ustar ripleyusers/* * src/interfaces/libpq/win32.c * * * FILE * win32.c * * DESCRIPTION * Win32 support functions. * * Contains table and functions for looking up win32 socket error * descriptions. But will/may contain other win32 helper functions * for libpq. * * The error constants are taken from the Frambak Bakfram LGSOCKET * library guys who in turn took them from the Winsock FAQ. * * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * */ /* Make stuff compile faster by excluding not used stuff */ #define VC_EXTRALEAN #ifndef __MINGW32__ #define NOGDI #endif #define NOCRYPT #include "postgres_fe.h" #include "win32.h" /* Declared here to avoid pulling in all includes, which causes name collissions */ #ifdef ENABLE_NLS extern char * libpq_gettext(const char *msgid) __attribute__((format_arg(1))); #else #define libpq_gettext(x) (x) #endif static struct WSErrorEntry { DWORD error; const char *description; } WSErrors[] = { { 0, "No error" }, { WSAEINTR, "Interrupted system call" }, { WSAEBADF, "Bad file number" }, { WSAEACCES, "Permission denied" }, { WSAEFAULT, "Bad address" }, { WSAEINVAL, "Invalid argument" }, { WSAEMFILE, "Too many open sockets" }, { WSAEWOULDBLOCK, "Operation would block" }, { WSAEINPROGRESS, "Operation now in progress" }, { WSAEALREADY, "Operation already in progress" }, { WSAENOTSOCK, "Socket operation on non-socket" }, { WSAEDESTADDRREQ, "Destination address required" }, { WSAEMSGSIZE, "Message too long" }, { WSAEPROTOTYPE, "Protocol wrong type for socket" }, { WSAENOPROTOOPT, "Bad protocol option" }, { WSAEPROTONOSUPPORT, "Protocol not supported" }, { WSAESOCKTNOSUPPORT, "Socket type not supported" }, { WSAEOPNOTSUPP, "Operation not supported on socket" }, { WSAEPFNOSUPPORT, "Protocol family not supported" }, { WSAEAFNOSUPPORT, "Address family not supported" }, { WSAEADDRINUSE, "Address already in use" }, { WSAEADDRNOTAVAIL, "Cannot assign requested address" }, { WSAENETDOWN, "Network is down" }, { WSAENETUNREACH, "Network is unreachable" }, { WSAENETRESET, "Net connection reset" }, { WSAECONNABORTED, "Software caused connection abort" }, { WSAECONNRESET, "Connection reset by peer" }, { WSAENOBUFS, "No buffer space available" }, { WSAEISCONN, "Socket is already connected" }, { WSAENOTCONN, "Socket is not connected" }, { WSAESHUTDOWN, "Cannot send after socket shutdown" }, { WSAETOOMANYREFS, "Too many references, cannot splice" }, { WSAETIMEDOUT, "Connection timed out" }, { WSAECONNREFUSED, "Connection refused" }, { WSAELOOP, "Too many levels of symbolic links" }, { WSAENAMETOOLONG, "File name too long" }, { WSAEHOSTDOWN, "Host is down" }, { WSAEHOSTUNREACH, "No route to host" }, { WSAENOTEMPTY, "Directory not empty" }, { WSAEPROCLIM, "Too many processes" }, { WSAEUSERS, "Too many users" }, { WSAEDQUOT, "Disc quota exceeded" }, { WSAESTALE, "Stale NFS file handle" }, { WSAEREMOTE, "Too many levels of remote in path" }, { WSASYSNOTREADY, "Network system is unavailable" }, { WSAVERNOTSUPPORTED, "Winsock version out of range" }, { WSANOTINITIALISED, "WSAStartup not yet called" }, { WSAEDISCON, "Graceful shutdown in progress" }, { WSAHOST_NOT_FOUND, "Host not found" }, { WSATRY_AGAIN, "NA Host not found / SERVFAIL" }, { WSANO_RECOVERY, "Non recoverable FORMERR||REFUSED||NOTIMP" }, { WSANO_DATA, "No host data of that type was found" }, { 0, 0 } /* End of table */ }; /* * Returns 0 if not found, linear but who cares, at this moment * we're already in pain :) */ static int LookupWSErrorMessage(DWORD err, char *dest) { struct WSErrorEntry *e; for (e = WSErrors; e->description; e++) { if (e->error == err) { strcpy(dest, e->description); return 1; } } return 0; } struct MessageDLL { const char *dll_name; void *handle; int loaded; /* BOOL */ } dlls[] = { { "netmsg.dll", 0, 0 }, { "winsock.dll", 0, 0 }, { "wsock32.dll", 0, 0 }, { "ws2_32.dll", 0, 0 }, { "wsock32n.dll", 0, 0 }, { "mswsock.dll", 0, 0 }, { "ws2help.dll", 0, 0 }, { "ws2thk.dll", 0, 0 }, { 0, 0, 1 } /* Last one, no dll, always loaded */ }; #define DLLS_SIZE (sizeof(dlls)/sizeof(struct MessageDLL)) /* * Returns a description of the socket error by first trying * to find it in the lookup table, and if that fails, tries * to load any of the winsock dlls to find that message. * The DLL thing works from Nt4 (spX ?) up, but some special * versions of winsock might have this aswell (seen on Win98 SE * special install) / Magnus Naeslund (mag@fbab.net) * */ const char * winsock_strerror(int err, char *strerrbuf, size_t buflen) { unsigned long flags; int offs, i; int success = LookupWSErrorMessage(err, strerrbuf); for (i = 0; !success && i < DLLS_SIZE; i++) { if (!dlls[i].loaded) { dlls[i].loaded = 1; /* Only load once */ dlls[i].handle = (void *) LoadLibraryEx( dlls[i].dll_name, 0, LOAD_LIBRARY_AS_DATAFILE); } if (dlls[i].dll_name && !dlls[i].handle) continue; /* Didn't load */ flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | (dlls[i].handle ? FORMAT_MESSAGE_FROM_HMODULE : 0); success = 0 != FormatMessage( flags, dlls[i].handle, err, MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), strerrbuf, buflen - 64, 0 ); } if (!success) sprintf(strerrbuf, libpq_gettext("Unknown socket error (0x%08X/%i)"), err, err); else { strerrbuf[buflen - 1] = '\0'; offs = strlen(strerrbuf); if (offs > (int) buflen - 64) offs = buflen - 64; sprintf(strerrbuf + offs, " (0x%08X/%i)", err, err); } return strerrbuf; } RPostgreSQL/src/libpq/Makefile.port.darwin0000644000176000001440000000046611663173071020246 0ustar ripleyusersAROPT = crs DLSUFFIX = .so ifdef PGXS BE_DLLLIBS = -bundle_loader $(bindir)/postgres else BE_DLLLIBS = -bundle_loader $(top_builddir)/src/backend/postgres endif # Rule for building a shared library from a single .o file %.so: %.o $(CC) $(CFLAGS) $(LDFLAGS) $(LDFLAGS_SL) -bundle $(BE_DLLLIBS) -o $@ $< RPostgreSQL/src/libpq/pg_config.h.win0000644000176000001440000006457511663173071017253 0ustar ripleyusers/* src/include/pg_config.h. Generated from pg_config.h.in by configure. */ /* src/include/pg_config.h.in. Generated from configure.in by autoheader. */ /* Define to the type of arg 1 of 'accept' */ #define ACCEPT_TYPE_ARG1 SOCKET /* Define to the type of arg 2 of 'accept' */ #define ACCEPT_TYPE_ARG2 struct sockaddr * /* Define to the type of arg 3 of 'accept' */ #define ACCEPT_TYPE_ARG3 int /* Define to the return type of 'accept' */ #define ACCEPT_TYPE_RETURN SOCKET /* Define if building universal (internal helper macro) */ /* #undef AC_APPLE_UNIVERSAL_BUILD */ /* The normal alignment of `double', in bytes. */ #define ALIGNOF_DOUBLE 8 /* The normal alignment of `int', in bytes. */ #define ALIGNOF_INT 4 /* The normal alignment of `long', in bytes. */ #define ALIGNOF_LONG 4 /* The normal alignment of `long long int', in bytes. */ #define ALIGNOF_LONG_LONG_INT 8 /* The normal alignment of `short', in bytes. */ #define ALIGNOF_SHORT 2 /* Size of a disk block --- this also limits the size of a tuple. You can set it bigger if you need bigger tuples (although TOAST should reduce the need to have large tuples, since fields can be spread across multiple tuples). BLCKSZ must be a power of 2. The maximum possible value of BLCKSZ is currently 2^15 (32768). This is determined by the 15-bit widths of the lp_off and lp_len fields in ItemIdData (see include/storage/itemid.h). Changing BLCKSZ requires an initdb. */ #define BLCKSZ 8192 /* Define to the default TCP port number on which the server listens and to which clients will try to connect. This can be overridden at run-time, but it's convenient if your clients have the right default compiled in. (--with-pgport=PORTNUM) */ #define DEF_PGPORT 5432 /* Define to the default TCP port number as a string constant. */ #define DEF_PGPORT_STR "5432" /* Define to 1 to enable DTrace support. (--enable-dtrace) */ /* #undef ENABLE_DTRACE */ /* Define to build with GSSAPI support. (--with-gssapi) */ /* #undef ENABLE_GSS */ /* Define to 1 if you want National Language Support. (--enable-nls) */ /* #undef ENABLE_NLS */ /* Define to 1 to build client libraries as thread-safe code. (--enable-thread-safety) */ #define ENABLE_THREAD_SAFETY 1 /* float4 values are passed by value if 'true', by reference if 'false' */ #define FLOAT4PASSBYVAL true /* float8, int8, and related values are passed by value if 'true', by reference if 'false' */ #define FLOAT8PASSBYVAL true /* Define to 1 if getpwuid_r() takes a 5th argument. */ /* #undef GETPWUID_R_5ARG */ /* Define to 1 if gettimeofday() takes only 1 argument. */ /* #undef GETTIMEOFDAY_1ARG */ #ifdef GETTIMEOFDAY_1ARG # define gettimeofday(a,b) gettimeofday(a) #endif /* Define to 1 if you have the `append_history' function. */ /* #undef HAVE_APPEND_HISTORY */ /* Define to 1 if you have the `atexit' function. */ #define HAVE_ATEXIT 1 /* Define to 1 if you have the `cbrt' function. */ #define HAVE_CBRT 1 /* Define to 1 if you have the `class' function. */ /* #undef HAVE_CLASS */ /* Define to 1 if you have the `crypt' function. */ /* #undef HAVE_CRYPT */ /* Define to 1 if you have the header file. */ /* #undef HAVE_CRYPT_H */ /* Define to 1 if you have the declaration of `fdatasync', and to 0 if you don't. */ #define HAVE_DECL_FDATASYNC 0 /* Define to 1 if you have the declaration of `F_FULLFSYNC', and to 0 if you don't. */ #define HAVE_DECL_F_FULLFSYNC 0 /* Define to 1 if you have the declaration of `posix_fadvise', and to 0 if you don't. */ #define HAVE_DECL_POSIX_FADVISE 0 /* Define to 1 if you have the declaration of `snprintf', and to 0 if you don't. */ #define HAVE_DECL_SNPRINTF 1 /* Define to 1 if you have the declaration of `strlcat', and to 0 if you don't. */ #define HAVE_DECL_STRLCAT 0 /* Define to 1 if you have the declaration of `strlcpy', and to 0 if you don't. */ #define HAVE_DECL_STRLCPY 0 /* Define to 1 if you have the declaration of `sys_siglist', and to 0 if you don't. */ #define HAVE_DECL_SYS_SIGLIST 0 /* Define to 1 if you have the declaration of `vsnprintf', and to 0 if you don't. */ #define HAVE_DECL_VSNPRINTF 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_DLD_H */ /* Define to 1 if you have the `dlopen' function. */ /* #undef HAVE_DLOPEN */ /* Define to 1 if you have the header file. */ /* #undef HAVE_EDITLINE_HISTORY_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_EDITLINE_READLINE_H */ /* Define to 1 if you have the `erand48' function. */ /* #undef HAVE_ERAND48 */ /* Define to 1 if you have the `ERR_set_mark' function. */ /* #undef HAVE_ERR_SET_MARK */ /* Define to 1 if you have the `fcvt' function. */ #define HAVE_FCVT 1 /* Define to 1 if you have the `fdatasync' function. */ /* #undef HAVE_FDATASYNC */ /* Define to 1 if you have the `fpclass' function. */ /* #undef HAVE_FPCLASS */ /* Define to 1 if you have the `fp_class' function. */ /* #undef HAVE_FP_CLASS */ /* Define to 1 if you have the `fp_class_d' function. */ /* #undef HAVE_FP_CLASS_D */ /* Define to 1 if you have the header file. */ /* #undef HAVE_FP_CLASS_H */ /* Define to 1 if fseeko (and presumably ftello) exists and is declared. */ #define HAVE_FSEEKO 1 /* Define to 1 if your compiler understands __func__. */ #define HAVE_FUNCNAME__FUNC 1 /* Define to 1 if your compiler understands __FUNCTION__. */ /* #undef HAVE_FUNCNAME__FUNCTION */ /* Define to 1 if you have the `getaddrinfo' function. */ /* #undef HAVE_GETADDRINFO */ /* Define to 1 if you have the `gethostbyname_r' function. */ /* #undef HAVE_GETHOSTBYNAME_R */ /* Define to 1 if you have the `getifaddrs' function. */ /* #undef HAVE_GETIFADDRS */ /* Define to 1 if you have the `getopt' function. */ #define HAVE_GETOPT 1 /* Define to 1 if you have the header file. */ #define HAVE_GETOPT_H 1 /* Define to 1 if you have the `getopt_long' function. */ #define HAVE_GETOPT_LONG 1 /* Define to 1 if you have the `getpeereid' function. */ #define HAVE_GETPEEREID 1 /* Define to 1 if you have the `getpeerucred' function. */ /* #undef HAVE_GETPEERUCRED */ /* Define to 1 if you have the `getpwuid_r' function. */ /* #undef HAVE_GETPWUID_R */ /* Define to 1 if you have the `getrlimit' function. */ /* #undef HAVE_GETRLIMIT */ /* Define to 1 if you have the `getrusage' function. */ /* #undef HAVE_GETRUSAGE */ /* Define to 1 if you have the `gettimeofday' function. */ #define HAVE_GETTIMEOFDAY 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_GSSAPI_GSSAPI_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_GSSAPI_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_HISTORY_H */ /* Define to 1 if you have the `history_truncate_file' function. */ /* #undef HAVE_HISTORY_TRUNCATE_FILE */ /* Define to 1 if you have the header file. */ /* #undef HAVE_IEEEFP_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_IFADDRS_H */ /* Define to 1 if you have the `inet_aton' function. */ /* #undef HAVE_INET_ATON */ /* Define to 1 if the system has the type `int64'. */ /* #undef HAVE_INT64 */ /* Define to 1 if the system has the type `int8'. */ /* #undef HAVE_INT8 */ /* Define to 1 if the system has the type `intptr_t'. */ #define HAVE_INTPTR_T 1 /* Define to 1 if you have the header file. */ #define HAVE_INTTYPES_H 1 /* Define to 1 if you have the global variable 'int opterr'. */ #define HAVE_INT_OPTERR 1 /* Define to 1 if you have the global variable 'int optreset'. */ #define HAVE_INT_OPTRESET 1 /* Define to 1 if you have the global variable 'int timezone'. */ #define HAVE_INT_TIMEZONE /**/ /* Define to 1 if you have support for IPv6. */ #define HAVE_IPV6 1 /* Define to 1 if you have isinf(). */ #define HAVE_ISINF 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_KERNEL_IMAGE_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_KERNEL_OS_H */ /* Define to 1 if `e_data' is member of `krb5_error'. */ /* #undef HAVE_KRB5_ERROR_E_DATA */ /* Define to 1 if `text.data' is member of `krb5_error'. */ /* #undef HAVE_KRB5_ERROR_TEXT_DATA */ /* Define to 1 if you have krb5_free_unparsed_name */ /* #undef HAVE_KRB5_FREE_UNPARSED_NAME */ /* Define to 1 if `client' is member of `krb5_ticket'. */ /* #undef HAVE_KRB5_TICKET_CLIENT */ /* Define to 1 if `enc_part2' is member of `krb5_ticket'. */ /* #undef HAVE_KRB5_TICKET_ENC_PART2 */ /* Define to 1 if you have the header file. */ /* #undef HAVE_LANGINFO_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_LDAP_H */ /* Define to 1 if you have the `crypto' library (-lcrypto). */ /* #undef HAVE_LIBCRYPTO */ /* Define to 1 if you have the `eay32' library (-leay32). */ /* #undef HAVE_LIBEAY32 */ /* Define to 1 if you have the `ldap' library (-lldap). */ /* #undef HAVE_LIBLDAP */ /* Define to 1 if you have the `ldap_r' library (-lldap_r). */ /* #undef HAVE_LIBLDAP_R */ /* Define to 1 if you have the `m' library (-lm). */ #define HAVE_LIBM 1 /* Define to 1 if you have the `pam' library (-lpam). */ /* #undef HAVE_LIBPAM */ /* Define if you have a function readline library */ /* #undef HAVE_LIBREADLINE */ /* Define to 1 if you have the `selinux' library (-lselinux). */ /* #undef HAVE_LIBSELINUX */ /* Define to 1 if you have the `ssl' library (-lssl). */ /* #undef HAVE_LIBSSL */ /* Define to 1 if you have the `ssleay32' library (-lssleay32). */ /* #undef HAVE_LIBSSLEAY32 */ /* Define to 1 if you have the `wldap32' library (-lwldap32). */ /* #undef HAVE_LIBWLDAP32 */ /* Define to 1 if you have the `xml2' library (-lxml2). */ /* #undef HAVE_LIBXML2 */ /* Define to 1 if you have the `xslt' library (-lxslt). */ /* #undef HAVE_LIBXSLT */ /* Define to 1 if you have the `z' library (-lz). */ /* #undef HAVE_LIBZ */ /* Define to 1 if constants of type 'long long int' should have the suffix LL. */ #define HAVE_LL_CONSTANTS 1 /* Define to 1 if the system has the type `locale_t'. */ /* #undef HAVE_LOCALE_T */ /* Define to 1 if `long int' works and is 64 bits. */ /* #undef HAVE_LONG_INT_64 */ /* Define to 1 if the system has the type `long long int'. */ #define HAVE_LONG_LONG_INT 1 /* Define to 1 if `long long int' works and is 64 bits. */ #define HAVE_LONG_LONG_INT_64 1 /* Define to 1 if you have the `memmove' function. */ #define HAVE_MEMMOVE 1 /* Define to 1 if you have the header file. */ #define HAVE_MEMORY_H 1 /* Define to 1 if the system has the type `MINIDUMP_TYPE'. */ #define HAVE_MINIDUMP_TYPE 1 /* Define to 1 if you have the header file. */ #define HAVE_NETINET_IN_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_NETINET_TCP_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_NET_IF_H */ /* Define to 1 if you have the `on_exit' function. */ /* #undef HAVE_ON_EXIT */ /* Define to 1 if you have the header file. */ /* #undef HAVE_OSSP_UUID_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_PAM_PAM_APPL_H */ /* Define to 1 if you have the `poll' function. */ /* #undef HAVE_POLL */ /* Define to 1 if you have the header file. */ /* #undef HAVE_POLL_H */ /* Define to 1 if you have the `posix_fadvise' function. */ /* #undef HAVE_POSIX_FADVISE */ /* Define to 1 if you have the POSIX signal interface. */ /* #undef HAVE_POSIX_SIGNALS */ /* Define to 1 if you have the `pstat' function. */ /* #undef HAVE_PSTAT */ /* Define to 1 if the PS_STRINGS thing exists. */ /* #undef HAVE_PS_STRINGS */ /* Define if you have POSIX threads libraries and header files. */ /* #undef HAVE_PTHREAD */ /* Define to 1 if you have the header file. */ #define HAVE_PWD_H 1 /* Define to 1 if you have the `random' function. */ /* #undef HAVE_RANDOM */ /* Define to 1 if you have the header file. */ /* #undef HAVE_READLINE_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_READLINE_HISTORY_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_READLINE_READLINE_H */ /* Define to 1 if you have the `readlink' function. */ /* #undef HAVE_READLINK */ /* Define to 1 if you have the `rint' function. */ #define HAVE_RINT 1 /* Define to 1 if you have the global variable 'rl_completion_append_character'. */ /* #undef HAVE_RL_COMPLETION_APPEND_CHARACTER */ /* Define to 1 if you have the `rl_completion_matches' function. */ /* #undef HAVE_RL_COMPLETION_MATCHES */ /* Define to 1 if you have the `rl_filename_completion_function' function. */ /* #undef HAVE_RL_FILENAME_COMPLETION_FUNCTION */ /* Define to 1 if you have the `scandir' function. */ /* #undef HAVE_SCANDIR */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SECURITY_PAM_APPL_H */ /* Define to 1 if you have the `setproctitle' function. */ /* #undef HAVE_SETPROCTITLE */ /* Define to 1 if you have the `setsid' function. */ /* #undef HAVE_SETSID */ /* Define to 1 if you have the `sigprocmask' function. */ /* #undef HAVE_SIGPROCMASK */ /* Define to 1 if you have sigsetjmp(). */ /* #undef HAVE_SIGSETJMP */ /* Define to 1 if the system has the type `sig_atomic_t'. */ #define HAVE_SIG_ATOMIC_T 1 /* Define to 1 if you have the `snprintf' function. */ /* #undef HAVE_SNPRINTF */ /* Define to 1 if you have spinlocks. */ #define HAVE_SPINLOCKS 1 /* Define to 1 if you have the `srandom' function. */ /* #undef HAVE_SRANDOM */ /* Define to 1 if you have the header file. */ #define HAVE_STDINT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDLIB_H 1 /* Define to 1 if you have the `strdup' function. */ #define HAVE_STRDUP 1 /* Define to 1 if you have the `strerror' function. */ #define HAVE_STRERROR 1 /* Define to 1 if you have the `strerror_r' function. */ /* #undef HAVE_STRERROR_R */ /* Define to 1 if cpp supports the ANSI # stringizing operator. */ #define HAVE_STRINGIZE 1 /* Define to 1 if you have the header file. */ #define HAVE_STRINGS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRING_H 1 /* Define to 1 if you have the `strlcat' function. */ /* #undef HAVE_STRLCAT */ /* Define to 1 if you have the `strlcpy' function. */ /* #undef HAVE_STRLCPY */ /* Define to 1 if you have the `strtol' function. */ #define HAVE_STRTOL 1 /* Define to 1 if you have the `strtoll' function. */ #define HAVE_STRTOLL 1 /* Define to 1 if you have the `strtoq' function. */ /* #undef HAVE_STRTOQ */ /* Define to 1 if you have the `strtoul' function. */ #define HAVE_STRTOUL 1 /* Define to 1 if you have the `strtoull' function. */ #define HAVE_STRTOULL 1 /* Define to 1 if you have the `strtouq' function. */ /* #undef HAVE_STRTOUQ */ /* Define to 1 if the system has the type `struct addrinfo'. */ #define HAVE_STRUCT_ADDRINFO 1 /* Define to 1 if the system has the type `struct cmsgcred'. */ /* #undef HAVE_STRUCT_CMSGCRED */ /* Define to 1 if the system has the type `struct option'. */ #define HAVE_STRUCT_OPTION 1 /* Define to 1 if `sa_len' is member of `struct sockaddr'. */ /* #undef HAVE_STRUCT_SOCKADDR_SA_LEN */ /* Define to 1 if the system has the type `struct sockaddr_storage'. */ #define HAVE_STRUCT_SOCKADDR_STORAGE 1 /* Define to 1 if `ss_family' is member of `struct sockaddr_storage'. */ #define HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY 1 /* Define to 1 if `ss_len' is member of `struct sockaddr_storage'. */ /* #undef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN */ /* Define to 1 if `__ss_family' is member of `struct sockaddr_storage'. */ /* #undef HAVE_STRUCT_SOCKADDR_STORAGE___SS_FAMILY */ /* Define to 1 if `__ss_len' is member of `struct sockaddr_storage'. */ /* #undef HAVE_STRUCT_SOCKADDR_STORAGE___SS_LEN */ /* Define to 1 if the system has the type `struct sockaddr_un'. */ /* #undef HAVE_STRUCT_SOCKADDR_UN */ /* Define to 1 if `tm_zone' is member of `struct tm'. */ /* #undef HAVE_STRUCT_TM_TM_ZONE */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SUPPORTDEFS_H */ /* Define to 1 if you have the `symlink' function. */ #define HAVE_SYMLINK 1 /* Define to 1 if you have the `sysconf' function. */ /* #undef HAVE_SYSCONF */ /* Define to 1 if you have the syslog interface. */ /* #undef HAVE_SYSLOG */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_IOCTL_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_IPC_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_POLL_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_PSTAT_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_RESOURCE_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_SELECT_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_SEM_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_SHM_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_SOCKET_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_SOCKIO_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_STAT_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_TAS_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_TIME_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_UCRED_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_UN_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_TERMIOS_H */ /* Define to 1 if your `struct tm' has `tm_zone'. Deprecated, use `HAVE_STRUCT_TM_TM_ZONE' instead. */ /* #undef HAVE_TM_ZONE */ /* Define to 1 if you have the `towlower' function. */ #define HAVE_TOWLOWER 1 /* Define to 1 if you have the external array `tzname'. */ #define HAVE_TZNAME 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_UCRED_H */ /* Define to 1 if the system has the type `uint64'. */ /* #undef HAVE_UINT64 */ /* Define to 1 if the system has the type `uint8'. */ /* #undef HAVE_UINT8 */ /* Define to 1 if the system has the type `uintptr_t'. */ #define HAVE_UINTPTR_T 1 /* Define to 1 if the system has the type `union semun'. */ /* #undef HAVE_UNION_SEMUN */ /* Define to 1 if you have the header file. */ #define HAVE_UNISTD_H 1 /* Define to 1 if you have unix sockets. */ /* #undef HAVE_UNIX_SOCKETS */ /* Define to 1 if you have the `unsetenv' function. */ #define HAVE_UNSETENV 1 /* Define to 1 if you have the `utime' function. */ #define HAVE_UTIME 1 /* Define to 1 if you have the `utimes' function. */ /* #undef HAVE_UTIMES */ /* Define to 1 if you have the header file. */ #define HAVE_UTIME_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_UUID_H */ /* Define to 1 if you have the `vsnprintf' function. */ /* #undef HAVE_VSNPRINTF */ /* Define to 1 if you have the `waitpid' function. */ /* #undef HAVE_WAITPID */ /* Define to 1 if you have the header file. */ #define HAVE_WCHAR_H 1 /* Define to 1 if you have the `wcstombs' function. */ #define HAVE_WCSTOMBS 1 /* Define to 1 if you have the `wcstombs_l' function. */ /* #undef HAVE_WCSTOMBS_L */ /* Define to 1 if you have the header file. */ #define HAVE_WCTYPE_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_WINLDAP_H */ /* Define to the appropriate snprintf format for 64-bit ints. */ #define INT64_FORMAT "%lld" /* Define to build with Kerberos 5 support. (--with-krb5) */ /* #undef KRB5 */ /* Define to 1 if `locale_t' requires . */ /* #undef LOCALE_T_IN_XLOCALE */ /* Define as the maximum alignment requirement of any C data type. */ #define MAXIMUM_ALIGNOF 8 /* Define bytes to use libc memset(). */ #define MEMSET_LOOP_LIMIT 1024 /* Define to the address where bug reports for this package should be sent. */ #define PACKAGE_BUGREPORT "pgsql-bugs@postgresql.org" /* Define to the full name of this package. */ #define PACKAGE_NAME "PostgreSQL" /* Define to the full name and version of this package. */ #define PACKAGE_STRING "PostgreSQL 9.1.1" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "postgresql" /* Define to the version of this package. */ #define PACKAGE_VERSION "9.1.1" /* Define to the name of the default PostgreSQL service principal in Kerberos. (--with-krb-srvnam=NAME) */ #define PG_KRB_SRVNAM "postgres" /* PostgreSQL major version as a string */ #define PG_MAJORVERSION "9.1" /* PostgreSQL version as a string */ #define PG_VERSION "9.1.1" /* PostgreSQL version as a number */ #define PG_VERSION_NUM 90101 /* A string containing the version number, platform, and C compiler */ #define PG_VERSION_STR "PostgreSQL 9.1.1 on x86_64-w64-mingw32, compiled by x86_64-w64-mingw32-gcc.exe (GCC) 4.5.2 20100917 (prerelease), 64-bit" /* Define to 1 to allow profiling output to be saved separately for each process. */ /* #undef PROFILE_PID_DIR */ /* Define to the necessary symbol if this constant uses a non-standard name on your system. */ /* #undef PTHREAD_CREATE_JOINABLE */ /* RELSEG_SIZE is the maximum number of blocks allowed in one disk file. Thus, the maximum size of a single file is RELSEG_SIZE * BLCKSZ; relations bigger than that are divided into multiple files. RELSEG_SIZE * BLCKSZ must be less than your OS' limit on file size. This is often 2 GB or 4GB in a 32-bit operating system, unless you have large file support enabled. By default, we make the limit 1 GB to avoid any possible integer-overflow problems within the OS. A limit smaller than necessary only means we divide a large relation into more chunks than necessary, so it seems best to err in the direction of a small limit. A power-of-2 value is recommended to save a few cycles in md.c, but is not absolutely required. Changing RELSEG_SIZE requires an initdb. */ #define RELSEG_SIZE 131072 /* The size of `long', as computed by sizeof. */ #define SIZEOF_LONG 4 /* The size of `off_t', as computed by sizeof. */ #define SIZEOF_OFF_T 4 /* The size of `size_t', as computed by sizeof. */ #define SIZEOF_SIZE_T 8 /* The size of `void *', as computed by sizeof. */ #define SIZEOF_VOID_P 8 /* Define to 1 if you have the ANSI C header files. */ #define STDC_HEADERS 1 /* Define to 1 if strerror_r() returns a int. */ /* #undef STRERROR_R_INT */ /* Define to 1 if your declares `struct tm'. */ /* #undef TM_IN_SYS_TIME */ /* Define to the appropriate snprintf format for unsigned 64-bit ints. */ #define UINT64_FORMAT "%llu" /* Define to 1 to build with assertion checks. (--enable-cassert) */ /* #undef USE_ASSERT_CHECKING */ /* Define to 1 to build with Bonjour support. (--with-bonjour) */ /* #undef USE_BONJOUR */ /* Define to 1 if you want float4 values to be passed by value. (--enable-float4-byval) */ #define USE_FLOAT4_BYVAL 1 /* Define to 1 if you want float8, int8, etc values to be passed by value. (--enable-float8-byval) */ #define USE_FLOAT8_BYVAL 1 /* Define to 1 if "static inline" works without unwanted warnings from compilations where static inline functions are defined but not called. */ #define USE_INLINE 1 /* Define to 1 if you want 64-bit integer timestamp and interval support. (--enable-integer-datetimes) */ #define USE_INTEGER_DATETIMES 1 /* Define to 1 to build with LDAP support. (--with-ldap) */ /* #undef USE_LDAP */ /* Define to 1 to build with XML support. (--with-libxml) */ /* #undef USE_LIBXML */ /* Define to 1 to use XSLT support when building contrib/xml2. (--with-libxslt) */ /* #undef USE_LIBXSLT */ /* Define to select named POSIX semaphores. */ /* #undef USE_NAMED_POSIX_SEMAPHORES */ /* Define to 1 to build with PAM support. (--with-pam) */ /* #undef USE_PAM */ /* Use replacement snprintf() functions. */ #define USE_REPL_SNPRINTF 1 /* Define to build with (Open)SSL support. (--with-openssl) */ /* #undef USE_SSL */ /* Define to select SysV-style semaphores. */ /* #undef USE_SYSV_SEMAPHORES */ /* Define to select SysV-style shared memory. */ /* #undef USE_SYSV_SHARED_MEMORY */ /* Define to select unnamed POSIX semaphores. */ /* #undef USE_UNNAMED_POSIX_SEMAPHORES */ /* Define to select Win32-style semaphores. */ #define USE_WIN32_SEMAPHORES 1 /* Define to select Win32-style shared memory. */ #define USE_WIN32_SHARED_MEMORY 1 /* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel). */ #if defined AC_APPLE_UNIVERSAL_BUILD # if defined __BIG_ENDIAN__ # define WORDS_BIGENDIAN 1 # endif #else # ifndef WORDS_BIGENDIAN /* # undef WORDS_BIGENDIAN */ # endif #endif /* Size of a WAL file block. This need have no particular relation to BLCKSZ. XLOG_BLCKSZ must be a power of 2, and if your system supports O_DIRECT I/O, XLOG_BLCKSZ must be a multiple of the alignment requirement for direct-I/O buffers, else direct I/O may fail. Changing XLOG_BLCKSZ requires an initdb. */ #define XLOG_BLCKSZ 8192 /* XLOG_SEG_SIZE is the size of a single WAL file. This must be a power of 2 and larger than XLOG_BLCKSZ (preferably, a great deal larger than XLOG_BLCKSZ). Changing XLOG_SEG_SIZE requires an initdb. */ #define XLOG_SEG_SIZE (16 * 1024 * 1024) /* Number of bits in a file offset, on hosts where this is settable. */ /* #undef _FILE_OFFSET_BITS */ /* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */ /* #undef _LARGEFILE_SOURCE */ /* Define for large files, on AIX-style hosts. */ /* #undef _LARGE_FILES */ /* Define to empty if `const' does not conform to ANSI C. */ /* #undef const */ /* Define to `__inline__' or `__inline' if that's what the C compiler calls it, or to nothing if 'inline' is not supported under any name. */ #ifndef __cplusplus /* #undef inline */ #endif /* Define to the type of a signed integer type wide enough to hold a pointer, if such a type exists, and if the system does not define it. */ /* #undef intptr_t */ /* Define to empty if the C compiler does not understand signed types. */ /* #undef signed */ /* Define to the type of an unsigned integer type wide enough to hold a pointer, if such a type exists, and if the system does not define it. */ /* #undef uintptr_t */ /* Define to empty if the keyword `volatile' does not work. Warning: valid code using `volatile' can become incorrect without. Disable with care. */ /* #undef volatile */ RPostgreSQL/src/libpq/md5.c0000644000176000001440000002411512124517222015157 0ustar ripleyusers/* * md5.c * * Implements the MD5 Message-Digest Algorithm as specified in * RFC 1321. This implementation is a simple one, in that it * needs every input byte to be buffered before doing any * calculations. I do not expect this file to be used for * general purpose MD5'ing of large amounts of data, only for * generating hashed passwords from limited input. * * Sverre H. Huseby * * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION * src/backend/libpq/md5.c */ /* This is intended to be used in both frontend and backend, so use c.h */ #include "c.h" #include "libpq/md5.h" /* * PRIVATE FUNCTIONS */ /* * The returned array is allocated using malloc. the caller should free it * when it is no longer needed. */ static uint8 * createPaddedCopyWithLength(uint8 *b, uint32 *l) { uint8 *ret; uint32 q; uint32 len, newLen448; uint32 len_high, len_low; /* 64-bit value split into 32-bit sections */ len = ((b == NULL) ? 0 : *l); newLen448 = len + 64 - (len % 64) - 8; if (newLen448 <= len) newLen448 += 64; *l = newLen448 + 8; if ((ret = (uint8 *) malloc(sizeof(uint8) * *l)) == NULL) return NULL; if (b != NULL) memcpy(ret, b, sizeof(uint8) * len); /* pad */ ret[len] = 0x80; for (q = len + 1; q < newLen448; q++) ret[q] = 0x00; /* append length as a 64 bit bitcount */ len_low = len; /* split into two 32-bit values */ /* we only look at the bottom 32-bits */ len_high = len >> 29; len_low <<= 3; q = newLen448; ret[q++] = (len_low & 0xff); len_low >>= 8; ret[q++] = (len_low & 0xff); len_low >>= 8; ret[q++] = (len_low & 0xff); len_low >>= 8; ret[q++] = (len_low & 0xff); ret[q++] = (len_high & 0xff); len_high >>= 8; ret[q++] = (len_high & 0xff); len_high >>= 8; ret[q++] = (len_high & 0xff); len_high >>= 8; ret[q] = (len_high & 0xff); return ret; } #define F(x, y, z) (((x) & (y)) | (~(x) & (z))) #define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) #define H(x, y, z) ((x) ^ (y) ^ (z)) #define I(x, y, z) ((y) ^ ((x) | ~(z))) #define ROT_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) static void doTheRounds(uint32 X[16], uint32 state[4]) { uint32 a, b, c, d; a = state[0]; b = state[1]; c = state[2]; d = state[3]; /* round 1 */ a = b + ROT_LEFT((a + F(b, c, d) + X[0] + 0xd76aa478), 7); /* 1 */ d = a + ROT_LEFT((d + F(a, b, c) + X[1] + 0xe8c7b756), 12); /* 2 */ c = d + ROT_LEFT((c + F(d, a, b) + X[2] + 0x242070db), 17); /* 3 */ b = c + ROT_LEFT((b + F(c, d, a) + X[3] + 0xc1bdceee), 22); /* 4 */ a = b + ROT_LEFT((a + F(b, c, d) + X[4] + 0xf57c0faf), 7); /* 5 */ d = a + ROT_LEFT((d + F(a, b, c) + X[5] + 0x4787c62a), 12); /* 6 */ c = d + ROT_LEFT((c + F(d, a, b) + X[6] + 0xa8304613), 17); /* 7 */ b = c + ROT_LEFT((b + F(c, d, a) + X[7] + 0xfd469501), 22); /* 8 */ a = b + ROT_LEFT((a + F(b, c, d) + X[8] + 0x698098d8), 7); /* 9 */ d = a + ROT_LEFT((d + F(a, b, c) + X[9] + 0x8b44f7af), 12); /* 10 */ c = d + ROT_LEFT((c + F(d, a, b) + X[10] + 0xffff5bb1), 17); /* 11 */ b = c + ROT_LEFT((b + F(c, d, a) + X[11] + 0x895cd7be), 22); /* 12 */ a = b + ROT_LEFT((a + F(b, c, d) + X[12] + 0x6b901122), 7); /* 13 */ d = a + ROT_LEFT((d + F(a, b, c) + X[13] + 0xfd987193), 12); /* 14 */ c = d + ROT_LEFT((c + F(d, a, b) + X[14] + 0xa679438e), 17); /* 15 */ b = c + ROT_LEFT((b + F(c, d, a) + X[15] + 0x49b40821), 22); /* 16 */ /* round 2 */ a = b + ROT_LEFT((a + G(b, c, d) + X[1] + 0xf61e2562), 5); /* 17 */ d = a + ROT_LEFT((d + G(a, b, c) + X[6] + 0xc040b340), 9); /* 18 */ c = d + ROT_LEFT((c + G(d, a, b) + X[11] + 0x265e5a51), 14); /* 19 */ b = c + ROT_LEFT((b + G(c, d, a) + X[0] + 0xe9b6c7aa), 20); /* 20 */ a = b + ROT_LEFT((a + G(b, c, d) + X[5] + 0xd62f105d), 5); /* 21 */ d = a + ROT_LEFT((d + G(a, b, c) + X[10] + 0x02441453), 9); /* 22 */ c = d + ROT_LEFT((c + G(d, a, b) + X[15] + 0xd8a1e681), 14); /* 23 */ b = c + ROT_LEFT((b + G(c, d, a) + X[4] + 0xe7d3fbc8), 20); /* 24 */ a = b + ROT_LEFT((a + G(b, c, d) + X[9] + 0x21e1cde6), 5); /* 25 */ d = a + ROT_LEFT((d + G(a, b, c) + X[14] + 0xc33707d6), 9); /* 26 */ c = d + ROT_LEFT((c + G(d, a, b) + X[3] + 0xf4d50d87), 14); /* 27 */ b = c + ROT_LEFT((b + G(c, d, a) + X[8] + 0x455a14ed), 20); /* 28 */ a = b + ROT_LEFT((a + G(b, c, d) + X[13] + 0xa9e3e905), 5); /* 29 */ d = a + ROT_LEFT((d + G(a, b, c) + X[2] + 0xfcefa3f8), 9); /* 30 */ c = d + ROT_LEFT((c + G(d, a, b) + X[7] + 0x676f02d9), 14); /* 31 */ b = c + ROT_LEFT((b + G(c, d, a) + X[12] + 0x8d2a4c8a), 20); /* 32 */ /* round 3 */ a = b + ROT_LEFT((a + H(b, c, d) + X[5] + 0xfffa3942), 4); /* 33 */ d = a + ROT_LEFT((d + H(a, b, c) + X[8] + 0x8771f681), 11); /* 34 */ c = d + ROT_LEFT((c + H(d, a, b) + X[11] + 0x6d9d6122), 16); /* 35 */ b = c + ROT_LEFT((b + H(c, d, a) + X[14] + 0xfde5380c), 23); /* 36 */ a = b + ROT_LEFT((a + H(b, c, d) + X[1] + 0xa4beea44), 4); /* 37 */ d = a + ROT_LEFT((d + H(a, b, c) + X[4] + 0x4bdecfa9), 11); /* 38 */ c = d + ROT_LEFT((c + H(d, a, b) + X[7] + 0xf6bb4b60), 16); /* 39 */ b = c + ROT_LEFT((b + H(c, d, a) + X[10] + 0xbebfbc70), 23); /* 40 */ a = b + ROT_LEFT((a + H(b, c, d) + X[13] + 0x289b7ec6), 4); /* 41 */ d = a + ROT_LEFT((d + H(a, b, c) + X[0] + 0xeaa127fa), 11); /* 42 */ c = d + ROT_LEFT((c + H(d, a, b) + X[3] + 0xd4ef3085), 16); /* 43 */ b = c + ROT_LEFT((b + H(c, d, a) + X[6] + 0x04881d05), 23); /* 44 */ a = b + ROT_LEFT((a + H(b, c, d) + X[9] + 0xd9d4d039), 4); /* 45 */ d = a + ROT_LEFT((d + H(a, b, c) + X[12] + 0xe6db99e5), 11); /* 46 */ c = d + ROT_LEFT((c + H(d, a, b) + X[15] + 0x1fa27cf8), 16); /* 47 */ b = c + ROT_LEFT((b + H(c, d, a) + X[2] + 0xc4ac5665), 23); /* 48 */ /* round 4 */ a = b + ROT_LEFT((a + I(b, c, d) + X[0] + 0xf4292244), 6); /* 49 */ d = a + ROT_LEFT((d + I(a, b, c) + X[7] + 0x432aff97), 10); /* 50 */ c = d + ROT_LEFT((c + I(d, a, b) + X[14] + 0xab9423a7), 15); /* 51 */ b = c + ROT_LEFT((b + I(c, d, a) + X[5] + 0xfc93a039), 21); /* 52 */ a = b + ROT_LEFT((a + I(b, c, d) + X[12] + 0x655b59c3), 6); /* 53 */ d = a + ROT_LEFT((d + I(a, b, c) + X[3] + 0x8f0ccc92), 10); /* 54 */ c = d + ROT_LEFT((c + I(d, a, b) + X[10] + 0xffeff47d), 15); /* 55 */ b = c + ROT_LEFT((b + I(c, d, a) + X[1] + 0x85845dd1), 21); /* 56 */ a = b + ROT_LEFT((a + I(b, c, d) + X[8] + 0x6fa87e4f), 6); /* 57 */ d = a + ROT_LEFT((d + I(a, b, c) + X[15] + 0xfe2ce6e0), 10); /* 58 */ c = d + ROT_LEFT((c + I(d, a, b) + X[6] + 0xa3014314), 15); /* 59 */ b = c + ROT_LEFT((b + I(c, d, a) + X[13] + 0x4e0811a1), 21); /* 60 */ a = b + ROT_LEFT((a + I(b, c, d) + X[4] + 0xf7537e82), 6); /* 61 */ d = a + ROT_LEFT((d + I(a, b, c) + X[11] + 0xbd3af235), 10); /* 62 */ c = d + ROT_LEFT((c + I(d, a, b) + X[2] + 0x2ad7d2bb), 15); /* 63 */ b = c + ROT_LEFT((b + I(c, d, a) + X[9] + 0xeb86d391), 21); /* 64 */ state[0] += a; state[1] += b; state[2] += c; state[3] += d; } static int calculateDigestFromBuffer(uint8 *b, uint32 len, uint8 sum[16]) { register uint32 i, j, k, newI; uint32 l; uint8 *input; register uint32 *wbp; uint32 workBuff[16], state[4]; l = len; state[0] = 0x67452301; state[1] = 0xEFCDAB89; state[2] = 0x98BADCFE; state[3] = 0x10325476; if ((input = createPaddedCopyWithLength(b, &l)) == NULL) return 0; for (i = 0;;) { if ((newI = i + 16 * 4) > l) break; k = i + 3; for (j = 0; j < 16; j++) { wbp = (workBuff + j); *wbp = input[k--]; *wbp <<= 8; *wbp |= input[k--]; *wbp <<= 8; *wbp |= input[k--]; *wbp <<= 8; *wbp |= input[k]; k += 7; } doTheRounds(workBuff, state); i = newI; } free(input); j = 0; for (i = 0; i < 4; i++) { k = state[i]; sum[j++] = (k & 0xff); k >>= 8; sum[j++] = (k & 0xff); k >>= 8; sum[j++] = (k & 0xff); k >>= 8; sum[j++] = (k & 0xff); } return 1; } static void bytesToHex(uint8 b[16], char *s) { static const char *hex = "0123456789abcdef"; int q, w; for (q = 0, w = 0; q < 16; q++) { s[w++] = hex[(b[q] >> 4) & 0x0F]; s[w++] = hex[b[q] & 0x0F]; } s[w] = '\0'; } /* * PUBLIC FUNCTIONS */ /* * pg_md5_hash * * Calculates the MD5 sum of the bytes in a buffer. * * SYNOPSIS #include "md5.h" * int pg_md5_hash(const void *buff, size_t len, char *hexsum) * * INPUT buff the buffer containing the bytes that you want * the MD5 sum of. * len number of bytes in the buffer. * * OUTPUT hexsum the MD5 sum as a '\0'-terminated string of * hexadecimal digits. an MD5 sum is 16 bytes long. * each byte is represented by two heaxadecimal * characters. you thus need to provide an array * of 33 characters, including the trailing '\0'. * * RETURNS false on failure (out of memory for internal buffers) or * true on success. * * STANDARDS MD5 is described in RFC 1321. * * AUTHOR Sverre H. Huseby * */ bool pg_md5_hash(const void *buff, size_t len, char *hexsum) { uint8 sum[16]; if (!calculateDigestFromBuffer((uint8 *) buff, len, sum)) return false; bytesToHex(sum, hexsum); return true; } bool pg_md5_binary(const void *buff, size_t len, void *outbuf) { if (!calculateDigestFromBuffer((uint8 *) buff, len, outbuf)) return false; return true; } /* * Computes MD5 checksum of "passwd" (a null-terminated string) followed * by "salt" (which need not be null-terminated). * * Output format is "md5" followed by a 32-hex-digit MD5 checksum. * Hence, the output buffer "buf" must be at least 36 bytes long. * * Returns TRUE if okay, FALSE on error (out of memory). */ bool pg_md5_encrypt(const char *passwd, const char *salt, size_t salt_len, char *buf) { size_t passwd_len = strlen(passwd); /* +1 here is just to avoid risk of unportable malloc(0) */ char *crypt_buf = malloc(passwd_len + salt_len + 1); bool ret; if (!crypt_buf) return false; /* * Place salt at the end because it may be known by users trying to crack * the MD5 output. */ memcpy(crypt_buf, passwd, passwd_len); memcpy(crypt_buf + passwd_len, salt, salt_len); strcpy(buf, "md5"); ret = pg_md5_hash(crypt_buf, passwd_len + salt_len, buf + 3); free(crypt_buf); return ret; } RPostgreSQL/src/libpq/COPYRIGHT0000644000176000001440000000225011660061757015630 0ustar ripleyusersPostgreSQL Database Management System (formerly known as Postgres, then as Postgres95) Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group Portions Copyright (c) 1994, The Regents of the University of California Permission to use, copy, modify, and distribute this software and its documentation for any purpose, without fee, and without a written agreement is hereby granted, provided that the above copyright notice and this paragraph and the following two paragraphs appear in all copies. IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. RPostgreSQL/src/RS-PostgreSQL.h0000644000176000001440000001320612124517222015714 0ustar ripleyusers#ifndef _RS_POSTGRESQL_H # define _RS_POSTGRESQL_H 1 /* * RS-PostgreSQL.h * * $Id: RS-PostgreSQL.h 189 2011-10-01 13:16:39Z dirk.eddelbuettel $ * * This package was developed as a part of Summer of Code program organized by Google. * Thanks to David A. James & Saikat DebRoy, the authors of RMySQL package. * Code from RMySQL package was reused with the permission from the authors. * Also Thanks to my GSoC mentor Dirk Eddelbuettel for helping me in the development. * * Processed with * indent --verbose -br -brs -i4 -nut -ppi 4 --line-length120 --comment-line-length120 --leave-preprocessor-space -npcs * */ # ifdef _cplusplus extern "C" { # endif # include "libpq-fe.h" # include # include "RS-DBI.h" /* Note that the default number of maximum connections to the PostgreSQL server is typically 100 * connections, but may be less if your kernel settings will not support it (as determined during initdb) * Refer to: http://www.postgresql.org/docs/8.2/interactive/runtime-config-resource.html for details */ typedef struct st_sdbi_conParams { char *user; char *password; char *host; char *dbname; char *port; char *tty; char *options; } RS_PostgreSQL_conParams; RS_PostgreSQL_conParams *RS_PostgreSQL_allocConParams(void); void RS_PostgreSQL_freeConParams(RS_PostgreSQL_conParams * conParams); /* The following functions are the S/R entry points into the C implementation * (i.e., these are the only ones visible from R/S) we use the prefix * "RS_PostgreSQL" in function names to denote this. * These functions are built on top of the underlying RS_DBI manager, * connection, and resultsets structures and functions (see RS-DBI.h). * * Note: A handle is just an R/S object (see RS-DBI.h for details), i.e., * Mgr_Handle, Con_Handle, Res_Handle, Db_Handle are s_object * (integer vectors, to be precise). */ /* dbManager */ Mgr_Handle *RS_PostgreSQL_init(s_object * config_params, s_object * reload); s_object *RS_PostgreSQL_close(Mgr_Handle * mgrHandle); /* dbConnection */ Con_Handle *RS_PostgreSQL_newConnection(Mgr_Handle * mgrHandle, s_object * con_params); Con_Handle *RS_PostgreSQL_cloneConnection(Con_Handle * conHandle); s_object *RS_PostgreSQL_closeConnection(Con_Handle * conHandle); s_object *RS_PostgreSQL_getException(Con_Handle * conHandle); /* err No, Msg */ /* dbResultSet */ Res_Handle *RS_PostgreSQL_exec(Con_Handle * conHandle, s_object * statement); s_object *RS_PostgreSQL_fetch(Res_Handle * rsHandle, s_object * max_rec); s_object *RS_PostgreSQL_closeResultSet(Res_Handle * rsHandle); s_object *RS_PostgreSQL_copyin(Con_Handle * conHandle, s_object * filename); s_object *RS_PostgreSQL_validHandle(Db_Handle * handle); /* boolean */ RS_DBI_fields *RS_PostgreSQL_createDataMappings(Res_Handle * resHandle); /* the following funs return named lists with meta-data for * the manager, connections, and result sets, respectively. */ s_object *RS_PostgreSQL_managerInfo(Mgr_Handle * mgrHandle); s_object *RS_PostgreSQL_connectionInfo(Con_Handle * conHandle); s_object *RS_PostgreSQL_resultSetInfo(Res_Handle * rsHandle); /* OID"S mapping taken from pg_type.h */ # define BOOLOID 16 # define BYTEAOID 17 # define CHAROID 18 # define NAMEOID 19 # define INT8OID 20 # define INT2OID 21 # define INT2VECTOROID 22 # define INT4OID 23 # define REGPROCOID 24 # define TEXTOID 25 # define OIDOID 26 # define TIDOID 27 # define XIDOID 28 # define CIDOID 29 # define OIDVECTOROID 30 # define PG_TYPE_RELTYPE_OID 71 # define PG_ATTRIBUTE_RELTYPE_OID 75 # define PG_PROC_RELTYPE_OID 81 # define PG_CLASS_RELTYPE_OID 83 # define XMLOID 142 # define POINTOID 600 # define LSEGOID 601 # define PATHOID 602 # define BOXOID 603 # define POLYGONOID 604 # define LINEOID 628 # define FLOAT4OID 700 # define FLOAT8OID 701 # define ABSTIMEOID 702 # define RELTIMEOID 703 # define TINTERVALOID 704 # define UNKNOWNOID 705 # define CIRCLEOID 718 # define CASHOID 790 # define MACADDROID 829 # define INETOID 869 # define CIDROID 650 # define INT4ARRAYOID 1007 # define FLOAT4ARRAYOID 1021 # define ACLITEMOID 1033 # define CSTRINGARRAYOID 1263 # define BPCHAROID 1042 # define VARCHAROID 1043 # define DATEOID 1082 # define TIMEOID 1083 # define TIMESTAMPOID 1114 # define TIMESTAMPTZOID 1184 # define INTERVALOID 1186 # define TIMETZOID 1266 # define BITOID 1560 # define VARBITOID 1562 # define NUMERICOID 1700 # define REFCURSOROID 1790 # define REGPROCEDUREOID 2202 # define REGOPEROID 2203 # define REGOPERATOROID 2204 # define REGCLASSOID 2205 # define REGTYPEOID 2206 # define REGTYPEARRAYOID 2211 # define TSVECTOROID 3614 # define GTSVECTOROID 3642 # define TSQUERYOID 3615 # define REGCONFIGOID 3734 # define REGDICTIONARYOID 3769 # define RECORDOID 2249 # define CSTRINGOID 2275 # define ANYOID 2276 # define ANYARRAYOID 2277 # define VOIDOID 2278 # define TRIGGEROID 2279 # define LANGUAGE_HANDLEROID 2280 # define INTERNALOID 2281 # define OPAQUEOID 2282 # define ANYELEMENTOID 2283 # define ANYNONARRAYOID 2776 # define ANYENUMOID 3500 s_object *RS_PostgreSQL_typeNames(s_object * typeIds); extern const struct data_types RS_dataTypeTable[]; # ifdef _cplusplus } # endif #endif /* _RS_PostgreSQL_H */ RPostgreSQL/src/Makevars.win0000644000176000001440000000031011711132675015504 0ustar ripleyusersPKG_CPPFLAGS=-I./libpq PKG_LIBS=libpq/libpq.a -lshfolder -lwsock32 -lws2_32 -lsecur32 .PHONY: all all: $(SHLIB) $(SHLIB): libpq/libpq.a export CC libpq/libpq.a: (cd libpq; make -f Makefile.win) RPostgreSQL/src/RS-PostgreSQL.c0000644000176000001440000014005412124517222015711 0ustar ripleyusers/* * RS-PostgreSQL.c * * $Id: RS-PostgreSQL.c 245 2012-12-19 13:06:53Z tomoakin@kenroku.kanazawa-u.ac.jp $ * * This package was developed as a part of Summer of Code program organized by Google. * Thanks to David A. James & Saikat DebRoy, the authors of RMySQL package. * Code from RMySQL package was reused with the permission from the authors. * Also Thanks to my GSoC mentor Dirk Eddelbuettel for helping me in the development. * * Source Processed with: * indent -br -i4 -nut --line-length120 --comment-line-length120 --leave-preprocessor-space -npcs RS-PostgreSQL.c * */ #include #include "RS-PostgreSQL.h" struct data_types RS_PostgreSQL_dataTypes[] = { {"BIGINT", 20}, /* ALSO KNOWN AS INT8 */ {"DECIMAL", 1700}, /* ALSO KNOWN AS NUMERIC */ {"FLOAT8", 701}, /* DOUBLE PRECISION */ {"FLOAT", 700}, /* ALSO CALLED FLOAT4 (SINGLE PRECISION) */ {"INTEGER", 23}, /* ALSO KNOWN AS INT4 */ {"SMALLINT", 21}, /* ALSO KNOWN AS INT2 */ {"MONEY", 790}, /* MONEY (8 bytes) */ {"CHAR", 1042}, /* FIXED LENGTH STRING-BLANK PADDED */ {"VARCHAR", 1043}, /* VARIABLE LENGTH STRING WITH SPECIFIED LIMIT */ {"TEXT", 25}, /* VARIABLE LENGTH STRING */ {"DATE", 1082}, {"TIME", 1083}, {"TIMESTAMP", 1114}, {"TIMESTAMPTZOID", 1184}, {"INTERVAL", 1186}, {"TIMETZOID", 1266}, {"BOOL", 16}, /* BOOLEAN */ {"BYTEA", 17}, /* USED FOR STORING RAW DATA */ {"OID", 26}, {"NULL", 2278}, {(char *) 0, -1} }; #ifndef USING_R # error("the function RS_DBI_invokeBeginGroup() has not been implemented in S") # error("the function RS_DBI_invokeEndGroup() has not been implemented in S") # error("the function RS_DBI_invokeNewRecord() has not been implemented in S") #endif /* R and S DataBase Interface to PostgreSQL * * C function library which can be used to run SQL queries * from inside of S4, Splus5.x, or R. * This Driver hooks R/S and PostgreSQL and implements the * the proposed RS-DBI generic database interface. * * For details refer * On R, * "R extensions" manual * On PostgreSQL, * "PostgreSQL 8.3.1 documentation" */ Mgr_Handle * RS_PostgreSQL_init(s_object * config_params, s_object * reload) { S_EVALUATOR /* Currently we can specify the defaults for 2 parameters, max num of * connections, and max of records per fetch (this can be over-ridden * explicitly in the S call to fetch). */ Mgr_Handle * mgrHandle; Sint fetch_default_rec, force_reload, max_con; const char *drvName = "PostgreSQL"; max_con = INT_EL(config_params, 0); fetch_default_rec = INT_EL(config_params, 1); force_reload = LGL_EL(reload, 0); mgrHandle = RS_DBI_allocManager(drvName, max_con, fetch_default_rec, force_reload); return mgrHandle; } s_object * RS_PostgreSQL_closeManager(Mgr_Handle * mgrHandle) { S_EVALUATOR RS_DBI_manager * mgr; s_object *status; mgr = RS_DBI_getManager(mgrHandle); if (mgr->num_con) { RS_DBI_errorMessage("There are opened connections -- close them first", RS_DBI_ERROR); } RS_DBI_freeManager(mgrHandle); MEM_PROTECT(status = NEW_LOGICAL((Sint) 1)); LGL_EL(status, 0) = TRUE; MEM_UNPROTECT(1); return status; } /* open a connection with the same parameters used for in * conHandle */ Con_Handle * RS_PostgreSQL_cloneConnection(Con_Handle * conHandle) { S_EVALUATOR Mgr_Handle * mgrHandle; RS_DBI_connection *con; RS_PostgreSQL_conParams *conParams; s_object *con_params; /* get connection params used to open existing connection */ con = RS_DBI_getConnection(conHandle); conParams = con->conParams; mgrHandle = RS_DBI_asMgrHandle(MGR_ID(conHandle)); /* Connection parameters need to be put into a 8-element character * vector to be passed to the RS_PostgreSQL_newConnection() function. */ MEM_PROTECT(con_params = NEW_CHARACTER((Sint) 7)); SET_CHR_EL(con_params, 0, C_S_CPY(conParams->user)); SET_CHR_EL(con_params, 1, C_S_CPY(conParams->password)); SET_CHR_EL(con_params, 2, C_S_CPY(conParams->host)); SET_CHR_EL(con_params, 3, C_S_CPY(conParams->dbname)); SET_CHR_EL(con_params, 4, C_S_CPY(conParams->port)); SET_CHR_EL(con_params, 5, C_S_CPY(conParams->tty)); SET_CHR_EL(con_params, 6, C_S_CPY(conParams->options)); MEM_UNPROTECT(1); return RS_PostgreSQL_newConnection(mgrHandle, con_params); } RS_PostgreSQL_conParams * RS_postgresql_allocConParams(void) { RS_PostgreSQL_conParams *conParams; conParams = (RS_PostgreSQL_conParams *) malloc(sizeof(RS_PostgreSQL_conParams)); if (!conParams) { RS_DBI_errorMessage("could not malloc space for connection params", RS_DBI_ERROR); } return conParams; } void RS_PostgreSQL_freeConParams(RS_PostgreSQL_conParams * conParams) { if (conParams->host) { free(conParams->host); } if (conParams->dbname) { free(conParams->dbname); } if (conParams->user) { free(conParams->user); } if (conParams->password) { free(conParams->password); } if (conParams->port) { free(conParams->port); } if (conParams->tty) { free(conParams->tty); } if (conParams->options) { free(conParams->options); } free(conParams); return; } Con_Handle * RS_PostgreSQL_newConnection(Mgr_Handle * mgrHandle, s_object * con_params) { S_EVALUATOR RS_DBI_connection * con; RS_PostgreSQL_conParams *conParams; Con_Handle *conHandle; PGconn *my_connection; char *user = NULL, *password = NULL, *host = NULL, *dbname = NULL, *port = NULL, *tty = NULL, *options = NULL; if (!is_validHandle(mgrHandle, MGR_HANDLE_TYPE)) { RS_DBI_errorMessage("invalid PostgreSQLManager", RS_DBI_ERROR); } #define IS_EMPTY(s1) !strcmp((s1), "") if (!IS_EMPTY(CHR_EL(con_params, 0))) { user = (char *) CHR_EL(con_params, 0); } if (!IS_EMPTY(CHR_EL(con_params, 1))) { password = (char *) CHR_EL(con_params, 1); } if (!IS_EMPTY(CHR_EL(con_params, 2))) { host = (char *) CHR_EL(con_params, 2); } if (!IS_EMPTY(CHR_EL(con_params, 3))) { dbname = (char *) CHR_EL(con_params, 3); } if (!IS_EMPTY(CHR_EL(con_params, 4))) { port = (char *) CHR_EL(con_params, 4); } if (!IS_EMPTY(CHR_EL(con_params, 5))) { tty = (char *) CHR_EL(con_params, 5); } if (!IS_EMPTY(CHR_EL(con_params, 6))) { options = (char *) CHR_EL(con_params, 6); } my_connection = PQsetdbLogin(host, port, options, tty, dbname, user, password); if (PQstatus(my_connection) != CONNECTION_OK) { char buf[1000]; sprintf(buf, "could not connect %s@%s on dbname \"%s\"\n", PQuser(my_connection), host?host:"local", PQdb(my_connection)); RS_DBI_errorMessage(buf, RS_DBI_ERROR); } conParams = RS_postgresql_allocConParams(); /* save actual connection parameters */ conParams->user = RS_DBI_copyString(PQuser(my_connection)); conParams->password = RS_DBI_copyString(PQpass(my_connection)); { const char *tmphost = PQhost(my_connection); if (tmphost) { conParams->host = RS_DBI_copyString(tmphost); } else { conParams->host = RS_DBI_copyString(""); } } conParams->dbname = RS_DBI_copyString(PQdb(my_connection)); conParams->port = RS_DBI_copyString(PQport(my_connection)); conParams->tty = RS_DBI_copyString(PQtty(my_connection)); conParams->options = RS_DBI_copyString(PQoptions(my_connection)); PROTECT(conHandle = RS_DBI_allocConnection(mgrHandle, (Sint) 1)); /* The second argument (1) specifies the number of result sets allocated */ con = RS_DBI_getConnection(conHandle); if (!con) { PQfinish(my_connection); RS_PostgreSQL_freeConParams(conParams); conParams = (RS_PostgreSQL_conParams *) NULL; RS_DBI_errorMessage("could not alloc space for connection object", RS_DBI_ERROR); } con->drvConnection = (void *) my_connection; con->conParams = (void *) conParams; UNPROTECT(1); return conHandle; } s_object * RS_PostgreSQL_closeConnection(Con_Handle * conHandle) { S_EVALUATOR RS_DBI_connection * con; PGconn *my_connection; s_object *status; con = RS_DBI_getConnection(conHandle); if (con->num_res > 0) { RS_DBI_errorMessage("close the pending result sets before closing this connection", RS_DBI_ERROR); } /* make sure we first free the conParams and postgresql connection from * the RS-RBI connection object. */ if (con->conParams) { RS_PostgreSQL_freeConParams(con->conParams); con->conParams = (RS_PostgreSQL_conParams *) NULL; } my_connection = (PGconn *) con->drvConnection; PQfinish(my_connection); con->drvConnection = (void *) NULL; RS_DBI_freeConnection(conHandle); MEM_PROTECT(status = NEW_LOGICAL((Sint) 1)); LGL_EL(status, 0) = TRUE; MEM_UNPROTECT(1); return status; } /* Execute (currently) one sql statement (INSERT, DELETE, SELECT, etc.), * set coercion type mappings between the server internal data types and * S classes. Returns an S handle to a resultSet object. */ Res_Handle * RS_PostgreSQL_exec(Con_Handle * conHandle, s_object * statement) { S_EVALUATOR RS_DBI_connection * con; Res_Handle *rsHandle; RS_DBI_resultSet *result; PGconn *my_connection; PGresult *my_result; Sint res_id, is_select=0; char *dyn_statement; con = RS_DBI_getConnection(conHandle); my_connection = (PGconn *) con->drvConnection; dyn_statement = RS_DBI_copyString(CHR_EL(statement, 0)); /* Do we have a pending resultSet in the current connection? * PostgreSQL only allows one resultSet per connection. */ if (con->num_res > 0) { res_id = (Sint) con->resultSetIds[0]; /* recall, PostgreSQL has only 1 res */ rsHandle = RS_DBI_asResHandle(MGR_ID(conHandle), CON_ID(conHandle), res_id); result = RS_DBI_getResultSet(rsHandle); if (result->completed == 0) { free(dyn_statement); RS_DBI_errorMessage("connection with pending rows, close resultSet before continuing", RS_DBI_ERROR); } else { RS_PostgreSQL_closeResultSet(rsHandle); } } /* Here is where we actually run the query */ /* Example: PGresult *PQexec(PGconn *conn, const char *command); */ my_result = PQexec(my_connection, dyn_statement); if (my_result == NULL) { char *errMsg; const char *omsg; size_t len; omsg = PQerrorMessage(my_connection); len = strlen(omsg); free(dyn_statement); errMsg = malloc(len + 80); /* 80 should be larger than the length of "could not ..."*/ snprintf(errMsg, len + 80, "could not run statement: %s", omsg); RS_DBI_errorMessage(errMsg, RS_DBI_ERROR); free(errMsg); } /* ExecStatusType PQresultStatus(const PGresult *res); */ if (PQresultStatus(my_result) == PGRES_TUPLES_OK) { is_select = (Sint) TRUE; } if (PQresultStatus(my_result) == PGRES_COMMAND_OK) { is_select = (Sint) FALSE; } /* char *PQresultErrorMessage(const PGresult *res); */ if (strcmp(PQresultErrorMessage(my_result), "") != 0) { free(dyn_statement); char *errResultMsg; const char *omsg; size_t len; omsg = PQerrorMessage(my_connection); len = strlen(omsg); errResultMsg = malloc(len + 80); /* 80 should be larger than the length of "could not ..."*/ snprintf(errResultMsg, len + 80, "could not Retrieve the result : %s", omsg); RS_DBI_errorMessage(errResultMsg, RS_DBI_ERROR); free(errResultMsg); /* Frees the storage associated with a PGresult. * void PQclear(PGresult *res); */ PQclear(my_result); } /* we now create the wrapper and copy values */ PROTECT(rsHandle = RS_DBI_allocResultSet(conHandle)); result = RS_DBI_getResultSet(rsHandle); result->statement = RS_DBI_copyString(dyn_statement); result->drvResultSet = (void *) my_result; result->rowCount = (Sint) 0; result->isSelect = is_select; /* Returns the number of rows affected by the SQL command. * char *PQcmdTuples(PGresult *res); */ if (!is_select) { result->rowsAffected = (Sint) atoi(PQcmdTuples(my_result)); result->completed = 1; } else { result->rowsAffected = (Sint) - 1; result->completed = 0; } if (is_select) { result->fields = RS_PostgreSQL_createDataMappings(rsHandle); } free(dyn_statement); UNPROTECT(1); return rsHandle; } RS_DBI_fields * RS_PostgreSQL_createDataMappings(Res_Handle * rsHandle) { PGresult *my_result; RS_DBI_connection *con; RS_DBI_resultSet *result; RS_DBI_fields *flds; int j, num_fields, internal_type; char errMsg[128]; result = RS_DBI_getResultSet(rsHandle); my_result = (PGresult *) result->drvResultSet; con = RS_DBI_getConnection(rsHandle); num_fields = PQnfields(my_result); PROTECT(flds = RS_DBI_allocFields(num_fields)); char buff[1000]; /* Buffer to hold the sql query to check whether the given column is nullable */ PGconn *conn; PGresult *res; conn = (PGconn *) con->drvConnection; for (j = 0; j < num_fields; j++) { flds->name[j] = RS_DBI_copyString(PQfname(my_result, j)); flds->type[j] = (int) PQftype(my_result, j); flds->length[j] = (Sint) PQfsize(my_result, j); /* NOTE: PQfmod is -1 incase of no information */ flds->precision[j] = (Sint) PQfmod(my_result, j); flds->scale[j] = (Sint) - 1; /* PQftablecol returns the column number (within its table) of * the column making up the specified query result column.Zero * is returned if the column number is out of range, or if the * specified column is not a simple reference to a table * column, or when using pre-3.0 protocol. So * "if(PQftablecol(my_result,j) !=0)" checks whether the * particular colomn in the result set is column of table or * not. Or else there is no meaning in checking whether a * column is nullable or not if it does not belong to the * table. */ flds->nullOk[j] = (Sint) INT_MIN; /* This should translate to NA in R */ if (PQftablecol(my_result, j) != 0) { /* Code to find whether a row can be nullable or not */ /* we might better just store the table id and column number for lazy evaluation at dbColumnInfo call*/ /* although the database structure can change, we are not in transaction anyway and there is no guarantee in current code */ snprintf(buff, 1000, "select attnotnull from pg_attribute where attrelid=%d and attnum='%d'", PQftable(my_result, j), PQftablecol(my_result, j)); res = PQexec(conn, buff); if (res && (PQntuples(res) > 0)){ const char * attnotnull = PQgetvalue(res, 0, 0); if(strcmp(attnotnull, "f") == 0) { flds->nullOk[j] = (Sint) 1; /* nollOK is TRUE when attnotnull is f*/ } if(strcmp(attnotnull, "t") == 0) { flds->nullOk[j] = (Sint) 0; /* nollOK is FALSE when attnotnull is t*/ } } PQclear(res); } internal_type = (int) PQftype(my_result, j); switch (internal_type) { case BOOLOID: flds->Sclass[j] = LOGICAL_TYPE; break; case BPCHAROID: flds->Sclass[j] = CHARACTER_TYPE; flds->isVarLength[j] = (Sint) 0; break; case VARCHAROID: case TEXTOID: case BYTEAOID: case NAMEOID: case MACADDROID: case INETOID: flds->Sclass[j] = CHARACTER_TYPE; flds->isVarLength[j] = (Sint) 1; break; case INT2OID: case INT4OID: case OIDOID: flds->Sclass[j] = INTEGER_TYPE; break; case INT8OID: if (sizeof(Sint) >= 8) { flds->Sclass[j] = INTEGER_TYPE; } else { flds->Sclass[j] = NUMERIC_TYPE; } break; case NUMERICOID: case FLOAT8OID: case FLOAT4OID: flds->Sclass[j] = NUMERIC_TYPE; break; case DATEOID: case TIMEOID: case TIMETZOID: case TIMESTAMPOID: case TIMESTAMPTZOID: case INTERVALOID: flds->Sclass[j] = CHARACTER_TYPE; /*flds->isVarLength[j] = (Sint) 1; */ break; default: flds->Sclass[j] = CHARACTER_TYPE; flds->isVarLength[j] = (Sint) 1; snprintf(buff, 1000, "select typname, typcategory from pg_type where oid = %d", internal_type); res = PQexec(conn, buff); if (res){ char * typename; char * typecat; int ntuples; ntuples = PQntuples(res); if(ntuples == 1){ typename = PQgetvalue(res, 0, 0); typecat = PQgetvalue(res, 0, 1); if(*typecat == 'E'){ /* This is enum, ok */ }else if(*typecat == 'A'){ /*This is array, ok */ }else{ snprintf(errMsg, 128, "unrecognized PostgreSQL field type %s (id:%d) in column %d", typename, internal_type, j); RS_DBI_errorMessage(errMsg, RS_DBI_WARNING); } }else{ snprintf(errMsg, 128, "oid: %d, ntuples: %d", internal_type, ntuples); RS_DBI_errorMessage(errMsg, RS_DBI_WARNING); } PQclear(res); }else{ snprintf(errMsg, 128, "unrecognized PostgreSQL field type %d in column %d", internal_type, j); RS_DBI_errorMessage(errMsg, RS_DBI_WARNING); } break; } } UNPROTECT(1); return flds; } s_object * /* output is a named list */ RS_PostgreSQL_fetch(s_object * rsHandle, s_object * max_rec) { S_EVALUATOR RS_DBI_manager * mgr; RS_DBI_resultSet *result; RS_DBI_fields *flds; PGresult *my_result; s_object *output, *s_tmp; int i, j, null_item, expand; Sint completed; Stype *fld_Sclass; Sint num_rec; int num_fields; int num_rows; /*num_rows added to count number of rows */ int k; /* This takes care of pointer to the required row */ result = RS_DBI_getResultSet(rsHandle); flds = result->fields; if (result->isSelect != 1) { RS_DBI_errorMessage("resultSet does not correspond to a SELECT statement", RS_DBI_ERROR); } if (!flds) { RS_DBI_errorMessage("corrupt resultSet, missing fieldDescription", RS_DBI_ERROR); } num_rec = INT_EL(max_rec, 0); expand = (num_rec < 0); /* dyn expand output to accommodate all rows */ if (expand || num_rec == 0) { mgr = RS_DBI_getManager(rsHandle); /* num_rec contains "default num of records per fetch" */ num_rec = mgr->fetch_default_rec; } num_fields = flds->num_fields; MEM_PROTECT(output = NEW_LIST((Sint) num_fields)); RS_DBI_allocOutput(output, flds, num_rec, 0); fld_Sclass = flds->Sclass; /* actual fetching.... */ my_result = (PGresult *) result->drvResultSet; num_rows = PQntuples(my_result); k = result->rowCount; /* ADDED */ completed = (Sint) 0; for (i = 0;; i++, k++) { if (k >= num_rows) { completed = 1; break; } if (i == num_rec) { /* exhausted the allocated space */ if (expand) { /* do we extend or return the records fetched so far */ num_rec = 2 * num_rec; RS_DBI_allocOutput(output, flds, num_rec, expand); } else break; /* okay, no more fetching for now */ } /* PQgetlength (Returns the actual length of a field value in bytes) is used instead of lens * Syntax: int PQgetlength(const PGresult *res, int row_number, int column_number); */ if (i == num_rows) { /* we finish or encounter an error */ RS_DBI_connection *con; con = RS_DBI_getConnection(rsHandle); if (strcmp(PQerrorMessage((PGconn *) con->drvConnection), "") == 0) { completed = 1; } else { completed = -1; } break; } for (j = 0; j < num_fields; j++) { /* Testing a field for a null value ... * Syntax: int PQgetisnull(const PGresult *res, int row_number, int column_number); * This function returns 1 if the field is null and 0 if it contains a non-null value. */ null_item = PQgetisnull(my_result, k, j); switch ((int) fld_Sclass[j]) { case LOGICAL_TYPE: if (null_item) { NA_SET(&(LST_INT_EL(output, j, i)), LOGICAL_TYPE); } else if (strcmp(PQgetvalue(my_result, k, j), "f") == 0) { LST_LGL_EL(output, j, i) = (Sint) 0; /* FALSE */ } else if (strcmp(PQgetvalue(my_result, k, j), "t") == 0) { LST_LGL_EL(output, j, i) = (Sint) 1; /* TRUE */ } break; case INTEGER_TYPE: if (null_item) { NA_SET(&(LST_INT_EL(output, j, i)), INTEGER_TYPE); } else { LST_INT_EL(output, j, i) = (Sint) atol(PQgetvalue(my_result, k, j)); /* NOTE: changed */ } break; case CHARACTER_TYPE: if (null_item) { SET_LST_CHR_EL(output, j, i, NA_STRING); } else { SET_LST_CHR_EL(output, j, i, C_S_CPY(PQgetvalue(my_result, k, j))); } break; case NUMERIC_TYPE: if (null_item) { NA_SET(&(LST_NUM_EL(output, j, i)), NUMERIC_TYPE); } else { LST_NUM_EL(output, j, i) = (double) atof(PQgetvalue(my_result, k, j)); } break; default: if (null_item) { SET_LST_CHR_EL(output, j, i, NA_STRING); } else { char warn[64]; snprintf(warn, 64, "unrecognized field type %d in column %d", (int) fld_Sclass[j], (int) j); RS_DBI_errorMessage(warn, RS_DBI_WARNING); SET_LST_CHR_EL(output, j, i, C_S_CPY(PQgetvalue(my_result, k, j))); /* NOTE: changed */ } break; } } } /* actual number of records fetched */ if (i < num_rec) { num_rec = i; /* adjust the length of each of the members in the output_list */ for (j = 0; j < num_fields; j++) { s_tmp = LST_EL(output, j); MEM_PROTECT(SET_LENGTH(s_tmp, num_rec)); SET_ELEMENT(output, j, s_tmp); MEM_UNPROTECT(1); } } if (completed < 0) { RS_DBI_errorMessage("error while fetching rows", RS_DBI_WARNING); } result->rowCount += num_rec; result->completed = (int) completed; MEM_UNPROTECT(1); return output; } /* return a 2-elem list with the last exception number and * exception message on a given connection. */ s_object * RS_PostgreSQL_getException(s_object * conHandle) { S_EVALUATOR PGconn * my_connection; s_object *output; RS_DBI_connection *con; Sint n = 2; char *exDesc[] = { "errorNum", "errorMsg" }; Stype exType[] = { INTEGER_TYPE, CHARACTER_TYPE }; Sint exLen[] = { 1, 1 }; con = RS_DBI_getConnection(conHandle); if (!con->drvConnection) { RS_DBI_errorMessage("internal error: corrupt connection handle", RS_DBI_ERROR); } PROTECT(output = RS_DBI_createNamedList(exDesc, exType, exLen, n)); my_connection = (PGconn *) con->drvConnection; LST_INT_EL(output, 0, 0) = 0; /* PQerrorMessage: Returns the error message most recently generated by an * operation on the connection. * char *PQerrorMessage(const PGconn *conn); */ if (strcmp(PQerrorMessage(my_connection), "") == 0) { SET_LST_CHR_EL(output, 1, 0, C_S_CPY("OK")); } else { SET_LST_CHR_EL(output, 1, 0, C_S_CPY(PQerrorMessage(my_connection))); } UNPROTECT(1); return output; } s_object * RS_PostgreSQL_closeResultSet(s_object * resHandle) { S_EVALUATOR RS_DBI_resultSet * result; PGresult *my_result; s_object *status; result = RS_DBI_getResultSet(resHandle); my_result = (PGresult *) result->drvResultSet; PQclear(my_result); /* need to NULL drvResultSet, otherwise can't free the rsHandle */ result->drvResultSet = (void *) NULL; RS_DBI_freeResultSet(resHandle); MEM_PROTECT(status = NEW_LOGICAL((Sint) 1)); LGL_EL(status, 0) = TRUE; MEM_UNPROTECT(1); return status; } s_object * RS_PostgreSQL_managerInfo(Mgr_Handle * mgrHandle) { S_EVALUATOR RS_DBI_manager * mgr; s_object *output; Sint i, num_con, max_con, *cons, ncon; Sint j, n = 7; char *mgrDesc[] = { "drvName", "connectionIds", "fetch_default_rec", "managerId", "length", "num_con", "counter" /*, "clientVersion" */ }; Stype mgrType[] = { CHARACTER_TYPE, INTEGER_TYPE, INTEGER_TYPE, INTEGER_TYPE, INTEGER_TYPE, INTEGER_TYPE, INTEGER_TYPE /*, CHARACTER_TYPE */ }; Sint mgrLen[] = { 1, 1, 1, 1, 1, 1, 1 /*, 1 */ }; mgr = RS_DBI_getManager(mgrHandle); if (!mgr) { RS_DBI_errorMessage("driver not loaded yet", RS_DBI_ERROR); } num_con = (Sint) mgr->num_con; max_con = (Sint) mgr->length; mgrLen[1] = num_con; PROTECT(output = RS_DBI_createNamedList(mgrDesc, mgrType, mgrLen, n)); j = (Sint) 0; if (mgr->drvName) { SET_LST_CHR_EL(output, j++, 0, C_S_CPY(mgr->drvName)); } else { SET_LST_CHR_EL(output, j++, 0, C_S_CPY("")); } cons = (Sint *) S_alloc((long) max_con, (int) sizeof(Sint)); ncon = RS_DBI_listEntries(mgr->connectionIds, mgr->length, cons); if (ncon != num_con) { RS_DBI_errorMessage("internal error: corrupt RS_DBI connection table", RS_DBI_ERROR); } for (i = 0; i < num_con; i++) { LST_INT_EL(output, j, i) = cons[i]; } j++; LST_INT_EL(output, j++, 0) = mgr->fetch_default_rec; LST_INT_EL(output, j++, 0) = mgr->managerId; LST_INT_EL(output, j++, 0) = mgr->length; LST_INT_EL(output, j++, 0) = mgr->num_con; LST_INT_EL(output, j++, 0) = mgr->counter; UNPROTECT(1); return output; } s_object * RS_PostgreSQL_connectionInfo(Con_Handle * conHandle) { S_EVALUATOR PGconn * my_con; RS_PostgreSQL_conParams *conParams; RS_DBI_connection *con; s_object *output; Sint i, n = 8, *res, nres; int sv, major, minor_revision, minor, revision_num; char *conDesc[] = { "host", "port", "user", "dbname", "serverVersion", "protocolVersion", "backendPId", "rsId" }; Stype conType[] = { CHARACTER_TYPE, CHARACTER_TYPE, CHARACTER_TYPE, CHARACTER_TYPE, CHARACTER_TYPE, INTEGER_TYPE, INTEGER_TYPE, INTEGER_TYPE }; Sint conLen[] = { 1, 1, 1, 1, 1, 1, 1, -1 }; con = RS_DBI_getConnection(conHandle); conLen[7] = con->num_res; PROTECT(output = RS_DBI_createNamedList(conDesc, conType, conLen, n)); conParams = (RS_PostgreSQL_conParams *) con->conParams; SET_LST_CHR_EL(output, 0, 0, C_S_CPY(conParams->host)); SET_LST_CHR_EL(output, 1, 0, C_S_CPY(conParams->port)); SET_LST_CHR_EL(output, 2, 0, C_S_CPY(conParams->user)); SET_LST_CHR_EL(output, 3, 0, C_S_CPY(conParams->dbname)); my_con = (PGconn *) con->drvConnection; sv = PQserverVersion(my_con); major = sv / 10000; minor_revision = sv % 10000; minor = minor_revision / 100; revision_num = minor_revision % 100; { char buf1[50]; sprintf(buf1, "%d.%d.%d", major, minor, revision_num); SET_LST_CHR_EL(output, 4, 0, C_S_CPY(buf1)); } LST_INT_EL(output, 5, 0) = (Sint) PQprotocolVersion(my_con); LST_INT_EL(output, 6, 0) = (Sint) PQbackendPID(my_con); res = (Sint *) S_alloc((long) con->length, (int) sizeof(Sint)); nres = RS_DBI_listEntries(con->resultSetIds, con->length, res); if (nres != con->num_res) { RS_DBI_errorMessage("internal error: corrupt RS_DBI resultSet table", RS_DBI_ERROR); } for (i = 0; i < con->num_res; i++) { LST_INT_EL(output, 7, i) = (Sint) res[i]; } UNPROTECT(1); return output; } s_object * RS_PostgreSQL_resultSetInfo(Res_Handle * rsHandle) { S_EVALUATOR RS_DBI_resultSet * result; s_object *output, *flds; Sint n = 6; char *rsDesc[] = { "statement", "isSelect", "rowsAffected", "rowCount", "completed", "fieldDescription" }; Stype rsType[] = { CHARACTER_TYPE, INTEGER_TYPE, INTEGER_TYPE, INTEGER_TYPE, INTEGER_TYPE, LIST_TYPE }; Sint rsLen[] = { 1, 1, 1, 1, 1, 1 }; result = RS_DBI_getResultSet(rsHandle); if (result->fields) { PROTECT(flds = RS_DBI_getFieldDescriptions(result->fields)); } else { PROTECT(flds = S_NULL_ENTRY); } PROTECT(output = RS_DBI_createNamedList(rsDesc, rsType, rsLen, n)); SET_LST_CHR_EL(output, 0, 0, C_S_CPY(result->statement)); LST_INT_EL(output, 1, 0) = result->isSelect; LST_INT_EL(output, 2, 0) = result->rowsAffected; LST_INT_EL(output, 3, 0) = result->rowCount; LST_INT_EL(output, 4, 0) = result->completed; if (flds != S_NULL_ENTRY) { SET_ELEMENT(LST_EL(output, 5), (Sint) 0, flds); } UNPROTECT(2); return output; } s_object * RS_PostgreSQL_typeNames(s_object * type) { s_object *typeNames; Sint n, *typeCodes; int i; n = LENGTH(type); typeCodes = INTEGER_DATA(type); MEM_PROTECT(typeNames = NEW_CHARACTER(n)); for (i = 0; i < n; i++) { SET_CHR_EL(typeNames, i, C_S_CPY(RS_DBI_getTypeName(typeCodes[i], RS_PostgreSQL_dataTypes))); } MEM_UNPROTECT(1); return typeNames; } /* * RS_PostgreSQL_dbApply. * * R/S: dbApply(rs, INDEX, FUN, group.begin, group.end, end, ...) * * This first implementation of R's dbApply() * extracts rows from an open result set rs and applies functions * to those rows of each group. This is how it works: it keeps tracks of * the values of the field pointed by "group" and it identifies events: * BEGIN_GROUP (just read the first row of a different group), * NEW_RECORD (every record fetched generates this event), * and END_GROUP (just finished with the current group). At these points * we invoke the R functions group.end() and group.begin() in the * environment() of dbApply * [should it be the environment where dbApply was called from (i.e., * dbApply's parent's * frame)?] * Except for the very first group, the order of invocation is * end.group() followed by begin.group() * * NOTE: We're thinking of groups as commonly defined in awk scripts * (but also in SAP's ABAP/4) were rows are assumed to be sorted by * the "group" fields and we detect a different (new) group when any of * the "group" fields changes. Our implementation does not require * the result set to be sorted by group, but for performance-sake, * it better be. * * TODO: 1. Notify the reason for exiting (normal, exhausted maxBatches, etc.) * 2. Allow INDEX to be a list, as in tapply(). * 3. Handle NA's (SQL NULL's) in the INDEX and/or data fields. * Currently they are ignored, thus effectively causing a * new BEGIN_GROUP event. * 4. Re-write fetch() in terms of events (END_OF_DATA, * EXHAUST_DATAFRAME, DB_ERROR, etc.) * 5. Create a table of R callback functions indexed by events, * then a handle_event() could conveniently handle all the events. */ s_object *expand_list(s_object * old, Sint new_len); void add_group(s_object * group_names, s_object * data, Stype * fld_Sclass, Sint group, Sint ngroup, Sint i); unsigned int check_groupEvents(s_object * data, Stype fld_Sclass[], Sint row, Sint col); /* The following are the masks for the events/states we recognize as we * bring rows from the result set/cursor */ #define NEVER 0 #define BEGIN 1 /* prior to reading 1st row from the resultset */ #define END 2 /* after reading last row from the result set */ #define BEGIN_GROUP 4 /* just read in 1'st row for a different group */ #define END_GROUP 8 /* just read the last row of the current group */ #define NEW_RECORD 16 /* uninteresting */ #define PARTIAL_GROUP 32 /* too much data (>max_rex) partial buffer */ /* the following are non-grouping events (e.g., db errors, memory) */ #define EXHAUSTED_DF 64 /* exhausted the allocated data.frame */ #define EXHAUSTED_OUT 128 /* exhausted the allocated output list */ #define END_OF_DATA 256 /* end of data from the result set */ #define DBMS_ERROR 512 /* error in remote dbms */ /* beginGroupFun takes only one arg: the name of the current group */ s_object * RS_DBI_invokeBeginGroup(s_object * callObj, /* should be initialized */ const char *group_name, /* one string */ s_object * rho) { S_EVALUATOR s_object * s_group_name; /* make a copy of the argument */ MEM_PROTECT(s_group_name = NEW_CHARACTER((Sint) 1)); SET_CHR_EL(s_group_name, 0, C_S_CPY(group_name)); /* and stick into call object */ SETCADR(callObj, s_group_name); EVAL_IN_FRAME(callObj, rho); MEM_UNPROTECT(1); return S_NULL_ENTRY; } s_object * RS_DBI_invokeNewRecord(s_object * callObj, /* should be initialized already */ s_object * new_record, /* a 1-row data.frame */ s_object * rho) { S_EVALUATOR s_object * df; /* make a copy of the argument */ MEM_PROTECT(df = COPY_ALL(new_record)); /* and stick it into the call object */ SETCADR(callObj, df); EVAL_IN_FRAME(callObj, rho); MEM_UNPROTECT(1); return S_NULL_ENTRY; } /* endGroupFun takes two args: a data.frame and the group name */ s_object * RS_DBI_invokeEndGroup(s_object * callObj, s_object * data, const char *group_name, s_object * rho) { S_EVALUATOR s_object * s_x, *s_group_name, *val; /* make copies of the arguments */ MEM_PROTECT(callObj = duplicate(callObj)); MEM_PROTECT(s_x = COPY_ALL(data)); MEM_PROTECT(s_group_name = NEW_CHARACTER((Sint) 1)); SET_CHR_EL(s_group_name, 0, C_S_CPY(group_name)); /* stick copies of args into the call object */ SETCADR(callObj, s_x); SETCADDR(callObj, s_group_name); SETCADDDR(callObj, R_DotsSymbol); val = EVAL_IN_FRAME(callObj, rho); MEM_UNPROTECT(3); return val; } s_object * /* output is a named list */ RS_PostgreSQL_dbApply(s_object * rsHandle, /* resultset handle */ s_object * s_group_field, /* this is a 0-based field number */ s_object * s_funs, /* a 5-elem list with handler funs */ s_object * rho, /* the env where to run funs */ s_object * s_batch_size, /* alloc these many rows */ s_object * s_max_rec) { /* max rows per group */ S_EVALUATOR RS_DBI_resultSet * result; RS_DBI_fields *flds; PGresult *my_result; /* POSTGRESQL_ROW row; NOTE: REMOVED ths.... because it is MySQL specific */ int row_counter = -1; /* NOTE: added this.... to maintain a counter for the rows */ int row_max; /* NOTE: added this.... fetch the maximum number of rows in the resultset */ s_object *data, *cur_rec, *out_list, *group_names, *val; /* unsigned long *lens = (unsigned long *)0; NOTE: not being used */ Stype *fld_Sclass; Sint i, j, null_item, expand, completed; /* *fld_nullOk not used */ Sint num_rec, num_groups; int num_fields; Sint max_rec = INT_EL(s_max_rec, 0); /* max rec per group */ Sint ngroup = 0, group_field = INT_EL(s_group_field, 0); long total_records; Sint pushed_back = FALSE; unsigned int event = NEVER; int np = 0; /* keeps track of MEM_PROTECT()'s */ s_object *beginGroupCall, *beginGroupFun = LST_EL(s_funs, 2); s_object *endGroupCall, *endGroupFun = LST_EL(s_funs, 3); s_object *newRecordCall, *newRecordFun = LST_EL(s_funs, 4); int invoke_beginGroup = (GET_LENGTH(beginGroupFun) > 0); int invoke_endGroup = (GET_LENGTH(endGroupFun) > 0); int invoke_newRecord = (GET_LENGTH(newRecordFun) > 0); /* row = NULL; NOTE: REMOVED ths.... because it is MySQL specific */ beginGroupCall = R_NilValue; /* -Wall */ if (invoke_beginGroup) { MEM_PROTECT(beginGroupCall = lang2(beginGroupFun, R_NilValue)); ++np; } endGroupCall = R_NilValue; /* -Wall */ if (invoke_endGroup) { /* TODO: append list(...) to the call object */ MEM_PROTECT(endGroupCall = lang4(endGroupFun, R_NilValue, R_NilValue, R_NilValue)); ++np; } newRecordCall = R_NilValue; /* -Wall */ if (invoke_newRecord) { MEM_PROTECT(newRecordCall = lang2(newRecordFun, R_NilValue)); ++np; } result = RS_DBI_getResultSet(rsHandle); flds = result->fields; if (!flds) { RS_DBI_errorMessage("corrupt resultSet, missing fieldDescription", RS_DBI_ERROR); } num_fields = flds->num_fields; fld_Sclass = flds->Sclass; /* fld_nullOk = flds->nullOk; * set but not used*/ MEM_PROTECT(data = NEW_LIST((Sint) num_fields)); /* buffer records */ MEM_PROTECT(cur_rec = NEW_LIST((Sint) num_fields)); /* current record */ np += 2; RS_DBI_allocOutput(cur_rec, flds, (Sint) 1, 1); RS_DBI_makeDataFrame(cur_rec); num_rec = INT_EL(s_batch_size, 0); /* this is num of rec per group! */ max_rec = INT_EL(s_max_rec, 0); /* max rec **per group** */ num_groups = num_rec; MEM_PROTECT(out_list = NEW_LIST(num_groups)); MEM_PROTECT(group_names = NEW_CHARACTER(num_groups)); np += 2; /* set conversion for group names */ if (result->rowCount == 0) { event = BEGIN; /* here we could invoke the begin function */ } /* actual fetching.... */ my_result = (PGresult *) result->drvResultSet; completed = (Sint) 0; row_max = PQntuples(my_result); total_records = 0; expand = 0; /* expand or init each data vector? */ i = 0; /* index into row number **within** groups */ while (1) { if (i == 0 || i == num_rec) { /* BEGIN, EXTEND_DATA, BEGIN_GROUP */ /* reset num_rec upon a new group, double it if needs to expand */ num_rec = (i == 0) ? INT_EL(s_batch_size, 0) : 2 * num_rec; if (i < max_rec) { RS_DBI_allocOutput(data, flds, num_rec, expand++); } else { break; /* ok, no more fetching for now (pending group?) */ } } if (!pushed_back) { /* row = postgresql_fetch_row(my_result); Removed.... MYSQL specific */ ++row_counter; } if (row_counter == row_max) { /*finish *//*NOTE:Changed */ completed = (Sint) 1; /* TODO: error handling has to be done */ break; /* NOTE: Removed unsigned int err_no; RS_DBI_connection *con; con = RS_DBI_getConnection(rsHandle); err_no = postgresql_errno((POSTGRESQL *) con->drvConnection); completed = (Sint) (err_no ? -1 : 1); break; */ } if (!pushed_back) { /* recompute fields lengths? */ /* lens = postgresql_fetch_lengths(my_result); NOTE: NOT required *//* lengths for each field */ ++total_records; } else { pushed_back = FALSE; } /* coerce each entry row[j] to an R/S type according to its Sclass. * TODO: converter functions are badly needed. */ for (j = 0; j < num_fields; j++) { /* null_item = (row[j] == NULL); NOTE: REMOVED */ null_item = PQgetisnull(my_result, row_counter, j); switch ((int) fld_Sclass[j]) { case INTEGER_TYPE: if (null_item) NA_SET(&(LST_INT_EL(data, j, i)), INTEGER_TYPE); else LST_INT_EL(data, j, i) = atol(PQgetvalue(my_result, row_counter, j)); /* NOTE: changed */ LST_INT_EL(cur_rec, j, 0) = LST_INT_EL(data, j, i); break; case CHARACTER_TYPE: /* BUG: I need to verify that a TEXT field (which is stored as * a BLOB by PostgreSQL!) is indeed char and not a true * Binary obj (PostgreSQL does not truly distinguish them). This * test is very gross. */ if (null_item) { #ifdef USING_R SET_LST_CHR_EL(data, j, i, NA_STRING); #else NA_CHR_SET(LST_CHR_EL(data, j, i)); #endif } else { if ((size_t) PQfsize(my_result, j) != strlen(PQgetvalue(my_result, row_counter, j))) { /* NOTE: changed */ char warn[128]; snprintf(warn, 128, "internal error: row %ld field %ld truncated", (long) i, (long) j); RS_DBI_errorMessage(warn, RS_DBI_WARNING); } SET_LST_CHR_EL(data, j, i, C_S_CPY(PQgetvalue(my_result, row_counter, j))); /* NOTE: changed */ } SET_LST_CHR_EL(cur_rec, j, 0, C_S_CPY(LST_CHR_EL(data, j, i))); break; case NUMERIC_TYPE: if (null_item) { NA_SET(&(LST_NUM_EL(data, j, i)), NUMERIC_TYPE); } else { LST_NUM_EL(data, j, i) = (double) atof(PQgetvalue(my_result, row_counter, j)); /* NOTE: changed */ } LST_NUM_EL(cur_rec, j, 0) = LST_NUM_EL(data, j, i); break; default: /* error, but we'll try the field as character (!) */ if (null_item) { SET_LST_CHR_EL(data, j, i, NA_STRING); } else { char warn[64]; snprintf(warn, 64, "unrecognized field type %d in column %d", (int) fld_Sclass[j], (int) j); RS_DBI_errorMessage(warn, RS_DBI_WARNING); SET_LST_CHR_EL(data, j, i, C_S_CPY(PQgetvalue(my_result, row_counter, j))); } SET_LST_CHR_EL(cur_rec, j, 0, C_S_CPY(LST_CHR_EL(data, j, i))); break; } } /* We just finished processing the new record, now we check * for some events (in addition to NEW_RECORD, of course). */ event = check_groupEvents(data, fld_Sclass, i, group_field); if (BEGIN_GROUP & event) { if (ngroup == num_groups) { /* exhausted output list? */ num_groups = 2 * num_groups; MEM_PROTECT(SET_LENGTH(out_list, num_groups)); MEM_PROTECT(SET_LENGTH(group_names, num_groups)); np += 2; } if (invoke_beginGroup) { RS_DBI_invokeBeginGroup(beginGroupCall, CHR_EL(group_names, ngroup), rho); } } if (invoke_newRecord) { RS_DBI_invokeNewRecord(newRecordCall, cur_rec, rho); } if (END_GROUP & event) { add_group(group_names, data, fld_Sclass, group_field, ngroup, i - 1); RS_DBI_allocOutput(data, flds, i, expand++); RS_DBI_makeDataFrame(data); val = RS_DBI_invokeEndGroup(endGroupCall, data, CHR_EL(group_names, ngroup), rho); SET_ELEMENT(out_list, ngroup, val); /* set length of data to zero to force initialization * for next group */ RS_DBI_allocOutput(data, flds, (Sint) 0, (Sint) 1); i = 0; /* flush */ ++ngroup; pushed_back = TRUE; continue; } i++; } /* we fetched all the rows we needed/could; compute actual number of * records fetched. * TODO: What should we return in the case of partial groups??? */ if (completed < 0) { RS_DBI_errorMessage("error while fetching rows", RS_DBI_WARNING); } else if (completed) { event = (END_GROUP | END); } else { event = PARTIAL_GROUP; } /* wrap up last group */ if ((END_GROUP & event) || (PARTIAL_GROUP & event)) { add_group(group_names, data, fld_Sclass, group_field, ngroup, i - i); if (i < num_rec) { RS_DBI_allocOutput(data, flds, i, expand++); RS_DBI_makeDataFrame(data); } if (invoke_endGroup) { val = RS_DBI_invokeEndGroup(endGroupCall, data, CHR_EL(group_names, ngroup), rho); SET_ELEMENT(out_list, ngroup++, val); } if (PARTIAL_GROUP & event) { char buf[512]; (void) strcpy(buf, "exhausted the pre-allocated storage. The last "); (void) strcat(buf, "output group was computed with partial data. "); (void) strcat(buf, "The remaining data were left un-read in the "); (void) strcat(buf, "result set."); RS_DBI_errorMessage(buf, RS_DBI_WARNING); } } /* set the correct length of output list */ if (GET_LENGTH(out_list) != ngroup) { MEM_PROTECT(SET_LENGTH(out_list, ngroup)); MEM_PROTECT(SET_LENGTH(group_names, ngroup)); np += 2; } result->rowCount += total_records; result->completed = (int) completed; SET_NAMES(out_list, group_names); /* do I need to PROTECT? */ MEM_UNPROTECT(np); return out_list; } unsigned int check_groupEvents(s_object * data, Stype fld_Sclass[], Sint irow, Sint jcol) { if (irow == 0) { /* Begin */ return (BEGIN | BEGIN_GROUP); } switch (fld_Sclass[jcol]) { case LOGICAL_TYPE: if (LST_LGL_EL(data, jcol, irow) != LST_LGL_EL(data, jcol, irow - 1)) { return (END_GROUP | BEGIN_GROUP); } break; case INTEGER_TYPE: if (LST_INT_EL(data, jcol, irow) != LST_INT_EL(data, jcol, irow - 1)) { return (END_GROUP | BEGIN_GROUP); } break; case NUMERIC_TYPE: if (LST_NUM_EL(data, jcol, irow) != LST_NUM_EL(data, jcol, irow - 1)) { return (END_GROUP | BEGIN_GROUP); } break; case CHARACTER_TYPE: if (strcmp(LST_CHR_EL(data, jcol, irow), LST_CHR_EL(data, jcol, irow - 1))) { return (END_GROUP | BEGIN_GROUP); } break; default: PROBLEM "un-regongnized R/S data type %d", fld_Sclass[jcol] ERROR; break; } return NEW_RECORD; } /* append current group (as character) to the vector of group names */ void add_group(s_object * group_names, s_object * data, Stype * fld_Sclass, Sint group_field, Sint ngroup, Sint i) { char buff[1024]; switch ((int) fld_Sclass[group_field]) { case LOGICAL_TYPE: (void) sprintf(buff, "%ld", (long) LST_LGL_EL(data, group_field, i)); break; case INTEGER_TYPE: (void) sprintf(buff, "%ld", (long) LST_INT_EL(data, group_field, i)); break; case NUMERIC_TYPE: (void) sprintf(buff, "%f", (double) LST_NUM_EL(data, group_field, i)); break; case CHARACTER_TYPE: strcpy(buff, LST_CHR_EL(data, group_field, i)); break; default: RS_DBI_errorMessage("unrecognized R/S type for group", RS_DBI_ERROR); break; } SET_CHR_EL(group_names, ngroup, C_S_CPY(buff)); return; } RPostgreSQL/src/RS-pgsql-pqexec.c0000644000176000001440000000621412124517222016316 0ustar ripleyusers/* * RS-PostgreSQL.c * * $Id: RS-pgsql-pqexec.c 190 2011-10-01 14:27:35Z dirk.eddelbuettel $ * * This package was developed as a part of Summer of Code program organized by Google. * Thanks to David A. James & Saikat DebRoy, the authors of RMySQL package. * Code from RMySQL package was reused with the permission from the authors. * Also Thanks to my GSoC mentor Dirk Eddelbuettel for helping me in the development. * * Source Processed with: * indent -br -i4 -nut --line-length120 --comment-line-length120 --leave-preprocessor-space -npcs RS-PostgreSQL.c * */ #include #include "RS-PostgreSQL.h" /* R and S DataBase Interface to PostgreSQL * * C function library which can be used to run SQL queries * from inside of S4, Splus5.x, or R. * This Driver hooks R/S and PostgreSQL and implements the * the proposed RS-DBI generic database interface. * * For details refer * On R, * "R extensions" manual * On PostgreSQL, * "PostgreSQL 8.3.1 documentation" */ /* Execute (currently) one sql statement (INSERT, DELETE, SELECT, etc.), * set coercion type mappings between the server internal data types and * S classes. Don't drag the return value. */ SEXP RS_PostgreSQL_pqexec(Con_Handle * conHandle, s_object * statement) { S_EVALUATOR RS_DBI_connection * con; SEXP retval; PGconn *my_connection; PGresult *my_result; Sint is_select=0; char *dyn_statement; con = RS_DBI_getConnection(conHandle); my_connection = (PGconn *) con->drvConnection; dyn_statement = RS_DBI_copyString(CHR_EL(statement, 0)); /* Here is where we actually run the query */ /* Example: PGresult *PQexec(PGconn *conn, const char *command); */ my_result = PQexec(my_connection, dyn_statement); if (my_result == NULL) { char *errMsg; const char *omsg; size_t len; omsg = PQerrorMessage(my_connection); len = strlen(omsg); free(dyn_statement); errMsg = malloc(len + 80); /* 80 should be larger than the length of "could not ..."*/ snprintf(errMsg, len + 80, "could not run statement: %s", omsg); RS_DBI_errorMessage(errMsg, RS_DBI_ERROR); free(errMsg); } if (PQresultStatus(my_result) == PGRES_TUPLES_OK) { is_select = (Sint) TRUE; } if (PQresultStatus(my_result) == PGRES_COMMAND_OK) { is_select = (Sint) FALSE; } if (strcmp(PQresultErrorMessage(my_result), "") != 0) { free(dyn_statement); char *errResultMsg; const char *omsg; size_t len; omsg = PQerrorMessage(my_connection); len = strlen(omsg); errResultMsg = malloc(len + 80); /* 80 should be larger than the length of "could not ..."*/ snprintf(errResultMsg, len + 80, "could not Retrieve the result : %s", omsg); RS_DBI_errorMessage(errResultMsg, RS_DBI_ERROR); free(errResultMsg); /* Frees the storage associated with a PGresult. * void PQclear(PGresult *res); */ PQclear(my_result); } free(dyn_statement); PROTECT(retval = allocVector(LGLSXP, 1)); LOGICAL(retval)[0] = is_select; UNPROTECT(1); return retval; } RPostgreSQL/src/S4R.h0000644000176000001440000001775412124517222014013 0ustar ripleyusers/* $Id: S4R.h 189 2011-10-01 13:16:39Z dirk.eddelbuettel $ * * S4 (Splus5+) and R portability macros. * * This file provides additional macros to the ones in Rdefines.h (in R) * and S4/Splus5 S.h (see Appendix A of the green book) to * allow portability between R > 1.0.0, S4, and Splus5+ at the C source * level. In addition to the macros in Rdefines.h and Appendix A, * we have macros to do x[[i][j] and x[[i]][j] <- val inside C functions, * macros to test for primitive data types, plus macros to test and * set NA's portably. * TODO: Macros to build and eval functions portably? * * Processed with * indent --verbose -br -brs -i4 -nut -ppi 4 --line-length120 --comment-line-length120 --leave-preprocessor-space -npcs * */ #ifndef S4R_H # define S4R_H # ifdef __cplusplus extern "C" { # endif /* * If using SPLUS, you *need* to define the macro USING_SPLUS=[5|6] * (probably in the compiler command line) to trigger the right * sequence of definitions (we can no longer simply rely on S.h --- * we may need to avoid S.h altogether!) * * Some of these come from MASS, some from packages developed under * the Omega project, and some from RS-DBI itself. * */ # ifdef USING_SPLUS # if USING_SPLUS == 6 # define S_COMPATIBILITY 10 /* changing to the "new" API may be too */ # include "S_engine.h" /* time-consuming. */ # else # include "S.h" # endif # else /* not Splus, is it S4 or R? */ # include "S.h" # if (defined(S_VERSION)) # define USING_S4 /* do we really need S4 any more? */ # else # define USING_R # endif # endif /* Some of these come from MASS, some from packages developed under * the Omega project, and some from RS-DBI itself. */ # ifdef USING_R # include "R.h" # include "Rversion.h" # if defined(R_VERSION) && R_VERSION >= R_Version(1,2,0) # define USE_RINTERNALS 1 /* buggy Rdefines.h in 1.2.0/1.2.1 */ # include "Rdefines.h" # ifdef SET_ELEMENT /* workaround for bug in Rdefines.h */ # undef SET_ELEMENT # define SET_ELEMENT(x,i,val) SET_VECTOR_ELT((x),(i),(val)) # endif /* SET_ELEMENT */ # else # include "Rdefines.h" # endif # define singl double # define charPtr SEXP * # define CHAR_DEREF(x) CHAR(x) # define C_S_CPY(p) COPY_TO_USER_STRING(p) /* cpy C string to R */ # define MEM_PROTECT(x) PROTECT(x) # define MEM_UNPROTECT(n) UNPROTECT(n) # define MEM_UNPROTECT_PTR(x) UNPROTECT_PTR(x) # elif (defined(USING_S4) || defined(USING_SPLUS)) # define singl float # define Sint long # define charPtr char ** # define CHAR_DEREF(x) x # define C_S_CPY(p) c_s_cpy((p), S_evaluator) /* cpy C string to S */ # define RAW_DATA(p) (RAW_POINTER(p)) /* missing in S4 S.h */ # define MEM_PROTECT(x) (x) /**/ # define MEM_UNPROTECT(n) /**/ # define MEM_UNPROTECT_PTR(x) /**/ # endif /* The following are macros defined in the Green Book, but missing * in Rdefines.h. The semantics are as close to S4's as possible (?). */ # ifdef USING_R # define COPY(x) duplicate(x) # define COPY_ALL(x) duplicate(x) # define EVAL_IN_FRAME(expr,n) eval(expr,n) # define GET_FROM_FRAME(name,n) findVar(install(name),n) # define ASSIGN_IN_FRAME(name,obj,n) defineVar(install(name),COPY(obj),n) # endif /* data types common to R and S4 */ # ifdef USING_R # define Stype SEXPTYPE # define LOGICAL_TYPE LGLSXP # define INTEGER_TYPE INTSXP # define NUMERIC_TYPE REALSXP # define SINGLE_TYPE REALSXP # define REAL_TYPE REALSXP # define CHARACTER_TYPE STRSXP # define STRING_TYPE STRSXP # define COMPLEX_TYPE CPLXSXP # define LIST_TYPE VECSXP # else # define Stype int # define LOGICAL_TYPE LGL # define INTEGER_TYPE INT # define NUMERIC_TYPE DOUBLE # define SINGLE_TYPE REAL # define REAL_TYPE REAL # define CHARACTER_TYPE CHAR # define STRING_TYPE CHAR # define COMPLEX_TYPE COMPLEX # define LIST_TYPE LIST # define RAW_TYPE RAW # endif # ifdef USING_R # undef INTEGER_DATA # define INTEGER_DATA(x) (INTEGER(x)) # undef S_NULL_ENTRY # define S_NULL_ENTRY R_NilValue # else # define S_NULL_ENTRY NULL_ENTRY # endif /* We simplify one- and two-level access to object and list * (mostly built on top of jmc's macros) * * NOTE: Recall that list element vectors should *not* be set * directly, but only thru SET_ELEMENT (Green book, Appendix A), e.g., * LIST_POINTER(x)[i] = NEW_CHARACTER(100); BAD!! * LST_EL(x,i) = NEW_CHARACTER(100); BAD!! * SET_ELEMENT(x, i, NEW_CHARACTER(100)); Okay * * It's okay to directly set the i'th element of the j'th list element: * LST_CHR_EL(x,i,j) = C_S_CPY(str); Okay (but not in R-1.2.1) * * For R >= 1.2.0 define * SET_LST_CHR_EL(x,i,j,val) */ /* x[i] */ # define LGL_EL(x,i) LOGICAL_POINTER((x))[(i)] # define INT_EL(x,i) INTEGER_POINTER((x))[(i)] # define SGL_EL(x,i) SINGLE_POINTER((x))[(i)] # define FLT_EL(x,i) SGL_EL((x),(i)) # define NUM_EL(x,i) NUMERIC_POINTER((x))[(i)] # define DBL_EL(x,i) NUM_EL((x),(i)) # define RAW_EL(x,i) RAW_POINTER((x))[(i)] # if defined(R_VERSION) && R_VERSION >= R_Version(1,2,0) # define LST_EL(x,i) VECTOR_ELT((x),(i)) # define CHR_EL(x,i) CHAR_DEREF(STRING_ELT((x),(i))) # define SET_CHR_EL(x,i,val) SET_STRING_ELT((x),(i), (val)) # else /* the following are valid for S4/Splus5 and R < 1.2.0 */ # define LST_EL(x,i) LIST_POINTER((x))[(i)] # define CHR_EL(x,i) CHAR_DEREF(CHARACTER_POINTER((x))[(i)]) # define SET_CHR_EL(x,i,val) (CHR_EL(x,i)=val) # endif /* x[[i]][j] -- can be also assigned if x[[i]] is a numeric type */ # define LST_CHR_EL(x,i,j) CHR_EL(LST_EL((x),(i)), (j)) # define LST_LGL_EL(x,i,j) LGL_EL(LST_EL((x),(i)), (j)) # define LST_INT_EL(x,i,j) INT_EL(LST_EL((x),(i)), (j)) # define LST_SGL_EL(x,i,j) SGL_EL(LST_EL((x),(i)), (j)) # define LST_FLT_EL(x,i,j) LST_SGL_EL((x),(i),(j)) # define LST_NUM_EL(x,i,j) NUM_EL(LST_EL((x),(i)), (j)) # define LST_DBL_EL(x,i,j) LST_NUM_EL((x),(i),(j)) # define LST_RAW_EL(x,i,j) RAW_EL(LST_EL((x),(i)), (j)) # define LST_LST_EL(x,i,j) LST_EL(LST_EL((x),(i)), (j)) /* x[[i]][j] -- for the case when x[[i]] is a character type */ # if defined(R_VERSION) && R_VERSION >= R_Version(1,2,0) # define SET_LST_CHR_EL(x,i,j,val) SET_STRING_ELT(LST_EL(x,i), j, val) # else # define SET_LST_CHR_EL(x,i,j,val) (CHR_EL(LST_EL(x,i),j)=val) # endif /* setting and querying NA's -- in the case of R, we need to * use our own RS_na_set and RS_is_na functions (these need work!) */ # ifdef USING_R # define NA_SET(p,t) RS_na_set((p),(t)) # define NA_CHR_SET(p) SET_CHR_EL(p, 0, NA_STRING) # define IS_NA(p,t) RS_is_na((p),(t)) # else # define NA_SET(p,t) na_set((p),(t)) # define NA_CHR_SET(p) (p) = C_S_CPY(NA_STRING) # define IS_NA(p,t) is_na((p), (t)) # endif /* SET_ROWNAMES() and SET_CLASS_NAME() don't exist in S4 */ # ifdef USING_R # define SET_ROWNAMES(df,n) setAttrib(df, R_RowNamesSymbol, n) # define GET_CLASS_NAME(x) GET_CLASS(x) # define SET_CLASS_NAME(x,n) SET_CLASS(x, n) # else # define SET_ROWNAMES(df,n) error("un-implemented macro SET_ROWNAMES") # define SET_CLASS_NAME(x,n) error("un-implemented macro SET_CLASS_NAME") # endif /* end of RS-DBI macros */ # ifdef __cplusplus } # endif #endif /* S4R_H */ RPostgreSQL/src/Makevars.in0000644000176000001440000000012611677605030015323 0ustar ripleyusersPKG_CPPFLAGS=@PKG_CPPFLAGS@ PKG_LIBS=@PKG_LIBS@ R_OS_TYPE=@R_OS_TYPE@ @ENABLE_LIBPQ@ RPostgreSQL/NAMESPACE0000644000176000001440000000415011677047676013673 0ustar ripleyusers import(methods) import(DBI) useDynLib(RPostgreSQL) ## Classes exportClasses( dbObjectId, PostgreSQLObject, PostgreSQLDriver, PostgreSQLConnection, PostgreSQLResult ) ## Methods/Generics exportMethods( coerce, dbApply, dbCallProc, dbClearResult, dbColumnInfo, dbCommit, dbConnect, dbDataType, dbDisconnect, # dbEscapeStrings, dbExistsTable, dbGetException, dbGetInfo, dbGetQuery, dbGetRowCount, dbGetRowsAffected, dbGetStatement, dbHasCompleted, dbListConnections, dbListFields, dbListResults, dbListTables, # dbMoreResults, # dbNextResult, dbReadTable, dbRemoveTable, dbRollback, dbSendQuery, dbUnloadDriver, dbWriteTable, fetch, format, initialize, isSQLKeyword, make.db.names, show, SQLKeywords, summary ) ## regular functions (most of these will be made private) export( PostgreSQL, postgresqlBuildTableDefinition, isPostgresqlIdCurrent, .PostgreSQLKeywords, postgresqlInitDriver, postgresqlCloseDriver, postgresqlDescribeDriver, postgresqlDriverInfo, postgresqlNewConnection, postgresqlCloneConnection, postgresqlDescribeConnection, postgresqlConnectionInfo, postgresqlCloseConnection, postgresqlExecStatement, postgresqlpqExec, postgresqlCopyIn, postgresqlCopyInDataframe, postgresqlgetResult, postgresqlQuickSQL, postgresqlDBApply, postgresqlFetch, postgresqlResultInfo, postgresqlDescribeResult, postgresqlDescribeFields, postgresqlCloseResult, postgresqlImportFile, postgresqlReadTable, postgresqlWriteTable, postgresqlEscapeStrings, postgresqlDataType, postgresqlQuoteId, postgresqlTableRef ) ## constants #export( # CLIENT_LONG_PASSWORD, # CLIENT_FOUND_ROWS, # CLIENT_LONG_FLAG, # CLIENT_CONNECT_WITH_DB, # CLIENT_NO_SCHEMA, # CLIENT_COMPRESS, # CLIENT_ODBC, # CLIENT_LOCAL_FILES, # CLIENT_IGNORE_SPACE, # CLIENT_PROTOCOL_41, # CLIENT_INTERACTIVE, # CLIENT_SSL, # CLIENT_IGNORE_SIGPIPE, # CLIENT_TRANSACTIONS, # CLIENT_RESERVED, # CLIENT_SECURE_CONNECTION, # CLIENT_MULTI_STATEMENTS, # CLIENT_MULTI_RESULTS #) RPostgreSQL/ChangeLog0000644000176000001440000004111712124517166014212 0ustar ripleyusers2013-03-27 Tomoaki NISHIYAMA Document synchronization and testoutputs. * man/postgresqlSupport.Rd 2013-03-27 Tomoaki NISHIYAMA Change notation of LICENSE in DESCRIPTION upon request from CRAN * LICENSE * inst/NEWS * inst/ANNOUNCEMENTS * inst/TODO 2013-03-27 Tomoaki NISHIYAMA Use system libpq library when available on OS X (darwin) * src/configure.in * src/configure 2012-12-06 Tomoaki NISHIYAMA Test implementation of SQL with parameters. * R/PostgreSQLSupport.R * src/RS-pgsql-pqexecparams.c * tests/dbGetQueryParams.R 2012-10-04 Tomoaki NISHIYAMA Bug fix for GC related errro as reported as issue 42. * src/RS-DBI.c * src/RS-PostgreSQL.c * tests/dbColumnInfo.R 2012-09-18 Tomoaki NISHIYAMA Keep consistency of const modifier to const char* * src/RS-DBI.c 2012-09-18 Tomoaki NISHIYAMA Suppress message when $R_OS_TYPE is unset * configure * configure.in 2012-04-06 Tomoaki NISHIYAMA For issue 39: use a single equal sign (=) in test string comparison * configure * configure.in 2012-03-28 Tomoaki NISHIYAMA Avoid connection cloning. Ensure that BEGIN transaction is meaningfull * R/PostgreSQLSupport.R * tests/openSendQuery.R * tests/dbTransactionTests.R * tests/openSendQuery.R * man/dbCommit-methods.Rd 2012-02-27 Tomoaki NISHIYAMA Suppress dbColumnInfo Segmentation fault. RS_DBI_getTypeName() return "UNKNOWN" instead of NULL pointer. * src/RS-DBI.h * src/RS-DBI.c * tests/unknowntypes.R 2012-01-10 Tomoaki NISHIYAMA Windows support for r-devel. Make libpq.a with ar directly from $(OBJ) not via dll. Thus, install.libs.R is no more required. * ChangeLog * DESCRIPTION * src/Makevars.win * src/install.libs.R: delete * src/libpq/Makefile.global.win64 * src/libpq/Makefile.win * src/libpq/Makefile.shlib 2011-12-31 Tomoaki NISHIYAMA Move conditionals from Makevars.in to configure.in and configure so that the GNU extension is not used. * ChangeLog * DESCRIPTION * configure * configure.in * src/Makevars.in 2011-12-29 Tomoaki NISHIYAMA Prepare for release. As the last update makes many incompatibilities, the version number is large update. Remove dbBeginTransaction which is not defined in DBI. * ChangeLog * DESCRIPTION * NAMESPACE * R/PostgreSQL.R * inst/NEWS * man/dbCommit-methods.Rd 2011-12-03 Tomoaki NISHIYAMA Remove exported names that are not defined in DBI and may conflict other packages. Remove safe.write, which is not used anymore. Don't use make.db.names, which prevents using natural names. Move dbBuildTableDefinition to postgresqlBuildTableDefinition. Move isIdCurrent to isPostgresqlIdCurrent row.names be integer rather than charactor for sqldf compatibility. * NAMESPACE * R/PostgreSQL.R * R/PostgreSQLSupport.R * R/dbObjectId.R * man/safe.write.Rd * man/dbBuildTableDefinition.Rd * man/postgresqlBuildTableDefinition.Rd * man/make.db.names-methods.Rd * man/dbObjectId-class.Rd * man/isIdCurrent.Rd * man/isPostgresqlIdCurrent.Rd * man/postgresqlSupport.Rd 2011-12-02 Tomoaki NISHIYAMA Add clean: target to clean the libpq subdir on darwin * src/Makevars.in 2011-11-24 Tomoaki NISHIYAMA Use internal libpq for Mac OS X without PostgreSQL installation * config.guess * config.sub * configure * configure.in * install-sh * Makevars.in * src/libpq/netdb.h * src/libpq/pwd.h 2011-11-22 Tomoaki NISHIYAMA Restructuring libpq directory so that the dynamic library for Mac OS X / darwin can be made with make -f Makefile.darwin in that directory. Move windows specific include files to wininclude/ so that they do not interfere darwin. Configuration dependent files are separated as *.win and *.darwin and that should be copied at the first step of make. This is not enabled in OS X, though. * ChangeLog * src/Makevars.win * src/libpq * src/libpq/getaddrinfo.c: MinGW-w64 compatibility * src/libpq/pg_config_os.h.win: MinGW-w64 compatibility 2011-11-16 Tomoaki NISHIYAMA add LICENSE file * ChangeLog * inst/NEWS: Change the release date. * LICENSE 2011-11-15 Tomoaki NISHIYAMA Edit DESCRIPTION for LICENSE format, Copyright notice, and requirements for installation. * DESCRIPTION 2011-11-14 Tomoaki NISHIYAMA Remove make 3.80 dependency, so that the library can be compiled with Rtools214 without newer MinGW/MSYS installation. * ChangeLog * src/libpq/.gitignore: remove * src/libpq/Makefile.global.win32: remove recursion support * src/libpq/Makefile.global.win64: remove recursion support * src/libpq/Makefile.shlib: remove '| $(SHLIB_PREREQS)' 2011-11-12 Tomoaki NISHIYAMA Bundle libpq source for compilation on windows. * libpq/: src/interfaces/libpq from postgresql-9.1.1 configured on MinGW-w64 environment with some additional files required and Makefile edited to remove reference to other paths. Makefile.global.win32 is from postgesql-9.1.1 configured on MinGW 32-bit envionment. * configure.win: not depending on PG_HOME on windows. * src/Makevars.win: depend on libpq/ * src/install.libs.R: derived from R-2.14.0/src/library/tools/R copy libpq/libpq.dll to the destination same as RPostgreSQL.dll. 2011-10-03 Tomoaki NISHIYAMA Use try() not to abort on error to write spacial/kanji characters. For control characters use print again, but not for kanji special latin characters as umlaut. * ChangeLog * DESCRIPTION: Change maintainer name & address * tests/dbWriteTabletypes.R: use try() 2011-10-02 Tomoaki NISHIYAMA Avoid using raw UTF-8 string and conversion by print() for the test. * tests/dbWriteTabletypes.R: use \uxxxx escape for utf-8 string and use cat() to output them. 2011-10-01 Dirk Eddelbuettel Added $Id$ to all .R .c .h files and removed $Date$ from them. Removed declared-but-unused variables. 2011-09-26 Tomoaki NISHIYAMA Raise the version number to 0.2-0 * ChangeLog * DESCRIPTION * R/PostgreSQL.R 2011-09-25 Dirk Eddelbuettel * tests/*Rout.save: Updated six reference output files to match current output, differences mostly in whitespace or formatting 2011-09-25 Tomoaki NISHIYAMA Type conversion: integer is mapped to integer in postgresql; * R/PostgreSQLSupport.R: code change * tests/dbWriteTabletypes.R: testcode that R integer stored to PostgreSQL gets back as integer in R. 2011-09-25 Tomoaki NISHIYAMA dbListFields see only the current_schema unless the schema is specified * R/PostgreSQL.R: dbListFields are changed as above * tests/dbListFields.R: testcase 2011-09-24 Tomoaki NISHIYAMA Remove warning on enum, array, macaddr and inet; they are just kept as string, though. * src/RS-PostgreSQL.c: code change * man/dbSendQuery-methods.Rd: mannual 2011-08-26 Tomoaki NISHIYAMA dbWriteTable does escape strings, without a temporary file * NAMESPACE: export postgresqlCopyInDataframe * R/PostgreSQLSupport.R: adapter postgresqlCopyInDataframe * man/postgresqlSupport.Rd: document * src/RS-pgsql-copy.c: major code change; some derive from R * src/S4R.h: include "R.h" 2011-03-11 Dirk Eddelbuettel added a short paragraph to DESCRIPTION reminding people to install PostgreSQL itself * DESCRIPTION 2011-03-07 Tomoaki NISHIYAMA dbSendQuery when the return value is not to be used. Use dbGetQeury instead. * tests/createTableMixedCaseTest.R * tests/dataTypeTests.R * tests/datetimeTests.R * tests/dbColumnInfo.R * tests/dbtemptable.R 2011-03-07 Tomoaki NISHIYAMA Support for writing Date and POSIXct class as date and timestamp with time zone Manual and code consistency for postgresqlQuoteId and postgresqlTableRef. * R/PostgreSQLSupport.R: add field type for Date and POSIXct for PostgreSQL * tests/datetimestampwrite.R: the test for above * R/PostgreSQLSupport.R: identifier -> identifiers * man/postgresqlSupport.Rd: explict that one or more identifiers can be passed to postgresqlQuoteId 2011-03-06 Tomoaki NISHIYAMA More handling schema. * R/PostgreSQL.R: dbRemoveTable handle c("schema", "table"). 2011-03-05 Tomoaki NISHIYAMA Handling of schema: postgresqlTableRef generates "schema"."table" from a vector c("schema", "table"), and many of postgresqlQuoteId was changed to postgresqlTableRef. * NAMESPACE: exporting postgresqlQuoteId, postgresqlTableRef * R/PostgreSQLSupport.R: the code changed * man/postgresqlSupport.Rd: documentation change * R/PostgreSQL.R: dbExistsTable accept c("schema", "table") * tests/dbExistsqc.R: test for "rock.data" * tests/dbWriteTableSchema.R: tests dbWritetable to c("public", "rockdata") 2010-11-13 Tomoaki NISHIYAMA Consistency of tablename argument of dbExistsTable and dbWriteTable. * R/PostgreSQL.R: dbExistsTable behave like dbWriteTable on table name. * tests/dbExistsqc.R: test code 2010-11-02 Tomoaki NISHIYAMA Get results after CopyIn so that error is raised when incompatible table exists for dbWriteTable(append=TRUE) * NAMESPACE: exporting postgresqlEscapeStrings * R/PostgreSQLSupport.R: call sequence change for dbWriteTable: pqExec, CopyIn, and getResult * src/RS-RS-pgsql-getResult.c: new function to get return results. * src/RS-RS-pgsql-pqexec.c: new function to call pqexec. * man/postgresqlSupport.Rd: documentation * tests/dbWriteTableFailTest.R: New test code 2010-10-17 Dirk Eddelbuettel * DESCRIPTION: Release 0.1-7 2010-10-14 Tomoaki NISHIYAMA * src/RS-PostgreSQL.c: nullOk column in dbColumnInfo to have NA unless the backend has clear statement 2010-10-13 Joe Conway * src/RS-PostgreSQL.c: Correct segfault from issue ticket #24 2010-10-13 Tomoaki NISHIYAMA postgresqlEscapeStrings and postgresqlQuoteId to escape and quote strings and identifiers. This is used in dbWriteTable, dbExitsTable, and dbRemoveTable. * NAMESPACE: exporting postgresqlEscapeStrings * R/PostgreSQL.R: use postgresqlEscapeStrings and postgresqlQuoteId in dbExistsTable and dbRemoveTable * R/PostgreSQLSupport.R: define postgresqlQuoteId * src/RS-PQescape.c: implements postgresqlEscapeStrings, which is adapter to PQescapeStringConn * tests/createTableMixedCaseTest.R: modified what is the right behavior * tests/escape.R: test for postgresqlEscapeStrings * tests/dbExistsq.R: test for dbExistsTable with complex name * tests/selectWhereZero.R: Change species to "Species" so that the error message will not change. 2010-10-12 Dirk Eddelbuettel * src/RS-DBI.h: Applied patch by Brian D. Ripley to correct declaration of getpid() on Windows * ChangeLog: Moved from inst/ChangeLog; now C-x 4 a inserts filenames 2010-10-05 Tomoaki NISHIYAMA dbWriteTable copies tha data via the network connection * R/PostgreSQLSupport.R: postgresqlCopyIn, adapter to RS_PostgreSLQ_copyin * src/RS-pgsql-copy.c: implements RS_PostgreSQL_copyin, adapter to PQputCopyData and PQputCopyEnd * src/RS-PostgreSQL.c: initialize is_select * src/RS-PostgreSQL.h: decleration of RS_PostgreSQL_copyin * NAMESPACE: decleration 2010-09-11 Dirk Eddelbuettel * src/RS-DBI.h: Applying patch by tomoakin@kenroku.kanazawa-u.ac.jp from Issue #21 to add missing unistd.h to help with Intel compiler 2010-07-14 Dirk Eddelbuettel * R/PostgreSQLSupport.R: In postgresqlFetch(), correct case of as.POSIXct() call where format string is passed to tz argument Thanks to Steve Eick for the bug report. 2009-11-05 Dirk Eddelbuettel * R/PostgreSQLSupport.R: Apply patch by Robert McGehee to avoid the default tmpdir not only on Linux but also Darwin 2009-10-19 Dirk Eddelbuettel * DESCRIPTION: CRAN release 0.1-6 * tests/connectWithNull.R: allow for port to be passed via an env. var. * tests/dataTypeTests.R: idem * tests/datetimeTests.R: idem * tests/dbExistsIssue.R: idem * tests/dbWriteTableTest.R: idem * tests/loadDriverAndConnect.R: idem * tests/selectWhereZero.R: idem * tests/selectWithAlias.R: idem 2009-10-16 Dirk Eddelbuettel * R/PostgreSQL.R: Add missing paste() with thanks to João G. 2009-10-14 Dirk Eddelbuettel * tests/selectWhereZero.R: Fix upper/lower case table name 2009-10-13 Dirk Eddelbuettel * DESCRIPTION: CRAN release 0.1-5 + No new features but fixes for bugs #1, #2, #3 and #6 on the issue tracker + Both #4 and #5 are feature / enhancement request for which patch contributions are greatly appreciated. + Lastly #7 cannot be replicated. [ Neil Tiffin ] * configure.in: Added standard OS X / Fink location * src/RS-DBI.*: Consistent formatting via use of GNU indent * src/RS-PostgreSQL.*: idem * src/S4R.h: idem [ Dirk Eddelbuettel ] * src/RS-PostgreSQL.c: Apply fix by Joe Conway for seg.fault on alias'ed queries report as issue #1 in the issue tracker. * src/RS-PostgreSQL.c: Remove unused variables * R/PostgresSQL.R: Correction to dbExistsTable() to also recognise queries of the form 'schemaname.tablename' which was reported as issue #3 in the issue tracker following earlier emails by Prasenjit Kapat -- thanks to Prasenjit and Joe Conway patches that I merged * R/PostgreSQLSupport.R: In dbConnect(), stop if any one of user, password, host, dbname, port or tty is NULL to prevent a seg.fault which was reported as issue #2 on the issue tracker * R/PostgreSQLSupport.R: Wrap dbSendQuery() in try() to be more fault-tolerant an queries with errors which was reported as issue #6, thanks to Joe Conway for the suggested fix. * man/dbApply.Rd: Commented-out \usage thanks to new Rd parser * man/safe.write.Rd: Fixed cross-references thanks to R 2.10.0 parser * man/PostgreSQL.Rd: idem * man/dbReadTable-methods.Rd: idem * R/dbObjectId.R: Set missing SVN property Date * R/S4R.R: idem * tests/connectWithNull.*: added new test and comparison output * tests/dbExistsIssue.*: idem * tests/dbWriteTable.*: idem * tests/selectWhereZero.*: idem * tests/selectWithAlias.*: idem * tests/dataTypeTests.R: Remove correct temp. table 2009-01-26 Dirk Eddelbuettel * DESCRIPTION: CRAN release 0.1-4 * man/dbDataType-methods.Rd: small correction for error noticed by the new R parser 2008-12-12 Dirk Eddelbuettel * DESCRIPTION: CRAN release 0.1-3 * src/RS-DBI.c: Fixed to small memory leaks, with thanks to Jeff Horner for a small patch to which we added a similar fix * tests/*: Corrected a small typo in env.var 2008-11-02 Dirk Eddelbuettel * DESCRIPTION: CRAN release 0.1-2 * tests/*: Even more small fixes * configure.win: Test for $PG_HOME 2008-10-28 Dirk Eddelbuettel * DESCRIPTION: CRAN release 0.1-1 * tests/*: More cleanup on the tests * DESCRIPTION: URL fix 2008-10-21 Dirk Eddelbuettel * tests/*: Tests are now run if and only if the environment variables POSTGRES_USER, POSTGRES_HOST and POSTGRES_DATABASE are set; the variable POSTGRES_PASSWD is also used. This allows tests to run if the local admin wants them to run. Thanks to Uwe Ligges for the idea, and to Brian Ripley for supporting it. For now, CRAN won't run this though and it is effectively disabled in the default test during 'R CMD check' as the vars will presumably not be set. * configure{,.in}: no longer test for libpq.so as a second confirmation as OS X has it as libpq.dylib and would hence always fail. Thanks to Jan de Leeuw for the pointer. 2008-10-14 Dirk Eddelbuettel * DESCRIPTION: Initial CRAN release 0.1-0 RPostgreSQL/inst/0000755000176000001440000000000012124517222013402 5ustar ripleyusersRPostgreSQL/inst/devTests/0000755000176000001440000000000012124517222015203 5ustar ripleyusersRPostgreSQL/inst/devTests/datetime.r0000644000176000001440000000505611455242163017175 0ustar ripleyusers#!/usr/bin/env r ## assign a basic time type now <- Sys.time() basicTypeTests <- function() { ## print invokes a conversion to char for 'display' even though the type is really POSIXct print(now) print(class(now)) ## we can also convert to char() implicitly print(format(now)) print(class(format(now))) ## but what is important is that 'now' is still a time type ## that we can 'compute' print(now) print(now + 60) ## one minute later twomin <- now + 120 print(as.numeric(now)) ## and the time is even stored at millisecond granularity!! options("digits.secs"=7) ## need to tell R we want sub-second display up to 7 digits print(now) ## and now we do print(as.numeric(now), digits=16) ## same milli/microseconds here ## you can also go the other way and parse a datetime object from a char vector then <- strptime("2008-07-01 14:15:16", "%Y-%m-%d %H:%M:%S") print(then) print(class(then)) ## and we can convert this from its default 'POSIXlt' ('long type) representation to 'POSIXct' ('compact type') then <- as.POSIXct(then) print(then) print(class(then)) } dbTypeTests <- function(dateclass="timestamp without time zone") { cat("\n\n**** Trying with ", dateclass, "\n") tempdb <- "pgdatetime" system(paste("createdb", tempdb)) # create a temp database stopifnot(require(RPostgreSQL)) drv <- dbDriver("PostgreSQL") con <- dbConnect(drv, dbname=tempdb) dbSendQuery(con, paste("create table foo (tt ", dateclass, ", zz integer);", sep="")) dbSendQuery(con, "insert into foo values('2008-07-01 14:15:16.123', 1);") dbSendQuery(con, paste("insert into foo values('", format(now), "', 2);", sep="")) res <- dbReadTable(con, "foo") ## fails with 'RS-DBI driver warning: (unrecognized PostgreSQL field type 1184 in column 0)' print(res) ##res <- dbSendQuery(con, "select to_char(tt, 'YYYY-MM-DD HH24:MI:SS.US TZ') as character from foo;") res <- dbSendQuery(con, "select tt from foo;") data <- fetch(res, n=-1) #data <- dbGetQuery(con, "select tt from foo;") print(dbColumnInfo(res)) ##times <- strptime(data[,1], "%Y-%m-%d %H:%M:%OS") times <- data[,1] print(times) print(class(times[1])) print(diff(times)) ## yes we can compute on date times dbDisconnect(con) system(paste("dropdb", tempdb)) # create a temp database } dbTypeTests() dbTypeTests("timestamp") dbTypeTests("timestamp with time zone") dbTypeTests("date") #dbTypeTests("time with time zone") #dbTypeTests("time without time zone") RPostgreSQL/inst/devTests/copyTest.sh0000755000176000001440000000056411455242163017366 0ustar ripleyusers#!/bin/bash set -e dbname="pgtemp" createdb ${dbname} echo "Created ${dbname}" cat <= 50"); dbClearResult(rs); cat("After Deletion\n"); dbGetQuery(con, "select * from book123list") dbRollback(con) cat("After Rolling back\n") cat("Table book123list contains the following records\n") dbGetQuery(con, "select * from book123list") cat("Test Run 2:\n") dbBeginTransaction(con); cat("Begin Transaction\n") dbGetQuery(con, "select * from book123list")[1, ]; rs <- dbSendQuery(con, "DELETE from book123list WHERE intcolumn >= 50"); dbClearResult(rs); cat("After Deletion\n"); dbGetQuery(con, "select * from book123list") dbCommit(con); cat("After commiting the transaction\n") dbGetQuery(con, "select * from book123list") dbDisconnect(con) dbUnloadDriver(drv) system(paste("dropdb", tempdb)) cat("DONE\n") RPostgreSQL/inst/devTests/typeTest.r0000755000176000001440000000277611455242163017233 0ustar ripleyusers#!/usr/bin/env r usePG <- TRUE if (usePG) { cat("Using Pg\n") tempdb <- "pgdatetime" system(paste("createdb", tempdb)) # create a temp database suppressMessages(library(RPostgreSQL)) drv <- dbDriver("PostgreSQL") con <- dbConnect(drv, dbname=tempdb) } else { cat("Using SQLite\n") tempdb <- "/tmp/tempdb.sqlite" # assumed to not exist suppressMessages(library(RSQLite)) drv <- dbDriver("SQLite") if (file.exists(tempdb)) unlink(tempdb) con <- dbConnect(drv, tempdb) } sql <- "create table foo (i integer, r real, t text)" res <- dbSendQuery(con, sql) cat("Created table\n") i <- as.integer(11) r <- as.numeric(22.22) txt <- as.character("blim blom") sql <- paste("insert into foo ", "values (", i, ",", r, ", '", txt, "') ", sep="") res <- dbSendQuery(con, sql) cat("Wrote values\n") df <- dbReadTable(con, "foo") cat("Read values\n") ## now test the types of the colums we got stopifnot( class(df[,1]) == "integer" ) stopifnot( class(df[,2]) == "numeric" ) stopifnot( class(df[,3]) == "character" ) cat("GOOD -- all types are as expected\n") ## and test the values stopifnot( identical( df[1,1], i)) stopifnot( identical( df[1,2], r)) stopifnot( identical( df[1,3], txt)) cat("GOOD -- all values are as expected\n") if (usePG) { dbDisconnect(con) dbUnloadDriver(drv) system(paste("dropdb", tempdb)) } else { dbDisconnect(con) dbUnloadDriver(drv) unlink(tempdb) } cat("DONE\n") RPostgreSQL/inst/devTests/PostgreSQLDataTypeTest.r0000644000176000001440000000457611455242163021706 0ustar ripleyusers#!/usr/bin/env r ## Create a database tempdb <- "tempdbase" system(paste("createdb", tempdb)) library(RPostgreSQL) drv <- dbDriver("PostgreSQL") con <- dbConnect(drv, dbname=tempdb) ## Test the numeric mapping dbSendQuery(con, "create table testnumeric (intcolumn integer, floatcolumn float);") i <- as.integer(10) j <- as.numeric(56.6) sql <- paste("insert into testnumeric ", "values (",i, "," ,j ,") ", sep="") res <- dbSendQuery(con, sql) dat <- dbReadTable(con, "testnumeric") cat("Read Numeric values\n") ## now test the types of the colums we got stopifnot( class(dat[,1]) == "integer" ) stopifnot( class(dat[,2]) == "numeric" ) cat("GOOD -- all numeric types are as expected\n") ## and test the values stopifnot( identical( dat[1,1], i)) stopifnot( identical( dat[1,2], j)) cat("GOOD -- all numeric values are as expected\n") ## Test the logical mapping dbSendQuery(con,"create table testlogical (col1 boolean, col2 boolean)") i <- as.logical(TRUE) j <- as.logical(FALSE) sql <- paste("insert into testlogical ", "values (",i, "," ,j ,") ", sep="") res <- dbSendQuery(con, sql); dat <- dbReadTable(con, "testlogical") cat("Read Logical values\n") ## now test the types of the colums we got stopifnot( class(dat[,1]) == "logical" ) stopifnot( class(dat[,2]) == "logical" ) cat("GOOD -- all logical types are as expected\n") ## and test the values stopifnot( identical( dat[1,1], i)) stopifnot( identical( dat[1,2], j)) cat("GOOD -- all logical values are as expected\n") ## Test the character mapping dbSendQuery(con,"create table testchar (code char(3),city varchar(20),country text);") i <- as.character("IN") j <- as.character("Hyderabad") k <- as.character("India") sql <- paste("insert into testchar ", "values ('",i,"' , '",j ,"' , '",k,"') ", sep="") res <- dbSendQuery(con, sql); dat <- dbReadTable(con, "testchar") cat("Read Character values\n") ## now test the types of the colums we got stopifnot( class(dat[,1]) == "character" ) stopifnot( class(dat[,2]) == "character" ) stopifnot( class(dat[,3]) == "character" ) cat("GOOD -- all character types are as expected\n") ## and test the values ##stopifnot( identical( dat[1,1], i)) stopifnot( identical( dat[1,2], j)) stopifnot( identical( dat[1,3], k)) cat("GOOD -- all character values are as expected\n") dbDisconnect(con) dbUnloadDriver(drv) system(paste("dropdb", tempdb)) cat("DONE\n") RPostgreSQL/inst/devTests/timeTypeComparison.r0000755000176000001440000000216611455242163021236 0ustar ripleyusers#!/usr/bin/r suppressMessages({ library(RODBC) library(RPostgreSQL) }) testTimeData <- function(tt = "date") { createTempTable(tt) channel <- odbcConnect("beancounter") odbcres <- sqlQuery(channel, "select * from timetest") close(channel) con <- dbConnect( dbDriver("PostgreSQL"), dbname="beancounter") pgres <- dbGetQuery(con, "select * from timetest") dbDisconnect(con) removeTempTable() cat("\nFor type='", tt, "'\nODBC returns ", format(odbcres[1,1]), " class ", class(odbcres[1,1]), "\nRPostgreSQL returns ", format(pgres[1,1]), " class ", class(pgres[1,1]), "\n", sep="") } createTempTable <- function(tt) { system(paste("psql beancounter -c \"create table timetest ( d1", tt, ")\" >/dev/null")) system("psql beancounter -c \"insert into timetest values( \'now\' )\" >/dev/null") } removeTempTable <- function() { system("psql beancounter -c \"drop table timetest\" >/dev/null") } testTimeData("date") testTimeData("timestamp with time zone") testTimeData("timestamp without time zone") testTimeData("time with time zone") testTimeData("time without time zone") RPostgreSQL/inst/devTests/demo.r0000644000176000001440000001441611455242163016325 0ustar ripleyusers## DEMO for illustrating all the commands in RPostgreSQL package. ## Run this file using 'cat demo.r | R --slave' at the command prompt. ## Create a database tempdb <- "tempDEMO1dbase" system(paste("dropdb", tempdb)) system(paste("createdb", tempdb)) cat("\nFor loading the library: library(RPostgreSQL)\n") library(RPostgreSQL) cat("\n## Demo for the working of methods in RPostgreSQL\n\n") cat("## 1.dbDriver(\"driverName\") instantiates the driver object \nEg. drv <- dbDriver(\"PostgreSQL\") \n") drv <- dbDriver("PostgreSQL") drv cat("\n## 2.dbConnect(drv,...) creates and opens a connection to the database implemented by the driver drv. Connection string should be specified with parameters like user, password, dbname, host, port, tty and options. For more details refer to the documentation \nEg. con <- dbConnect(drv,dbname=\"dbName\")\n") con <- dbConnect(drv, dbname=tempdb) con con2<- dbConnect(drv, dbname=tempdb) con2 cat("\n## 3.dbListConnection(drv, ...): List of connections handled by the driver \nEg. dbListConnections(drv)\n") dbListConnections(drv) cat("## 4. dbGetInfo(dbObject, ...) returns information about the dbObject like driver, connection or resultSet \n Eg. dbGetInfo(drv)\n") dbGetInfo(drv) cat("## 5. dbSendQuery(con, statement, ...) submits one statement to the database\n Eg. rs <- dbSendQuery(con,\"select * from TableName\")\n") dbSendQuery(con, "create table book789listCosts (intcolumn integer, floatcolumn float);") ## insert four rows into the table dbSendQuery(con, "insert into book789listCosts values(12,13.21);") dbSendQuery(con, "insert into book789listCosts values(50,11.21);") dbSendQuery(con, "insert into book789listCosts values(100,200.1);") dbSendQuery(con, "insert into book789listCosts values(5,3.56);") rs <- dbSendQuery(con, "select * from book789listCosts") cat("\n## 6. fetch(rs,n, ...) fetches the next n elements from the result set. n=-1 means RETURN ALL ELEMENTS.\n Eg.fetch(rs,n=-1)\n") fetch(rs,n=-1) cat("\n## 7. dbGetQuery(con,statement, ...) submits, execute, and extract output in one operation. \nEg.dbGetQuery(con,\"select * from TableName\")\n") dbGetQuery(con,"select * from book789listCosts") cat("\n## 8. dbGetException(con, ...) returns the status of the last DBMS statement sent over the connection. \n Eg. dbGetException(con)\n") dbGetException(con) cat("\n## 9. dbListResults(con, ...) returns the resultsets active on the given connection. Please note that the current RPostgreSQL package can handle only one resultset per connection (which may change in the future).\n Eg. dbListResults(con)\n") dbListResults(con) cat("\n## 10. dbListTables(con, ...) returns the list of tables available on the connection. \n Eg. dbListTables(con)\n") dbListTables(con) cat("\n## 11. dbExistsTable(con, TableName, ...) checks whether a particular table exists on the given connection. Returns a logical.\n Eg. dbExistsTable(con,\"name\")\n") dbExistsTable(con,"name") cat("\n## 12. dbRemoveTable(con, TableName, ...) removes the specified table on the connection. Returns a logical indicating operation succeeded or not. \n Eg. dbRemoveTable(con,\"name\")\n") cat("\n## 13. dbListFields(con, TableName, ...) returns the list of column names (fields) in the table.\n Eg. dbListFields(con,\"book789listCosts\")\n") cat("\n## 14. dbColumnInfo(res, ...) produces a query that describes the output of the query.\n Eg. dbColumnInfo(rs)\n") dbColumnInfo(rs) cat("\n## 15. dbReadTable(conn, name, ...) imports the data stored remotely in the table name on connection conn. Use the ï¬eld row.names as the row.names attribute of the output data.frame. Returns a data.frame.\n Eg. dframe <- dbReadTable(con,\"book789listcosts\")\nAfter executing dbReadTable, the dframe contains:\n") dframe <- dbReadTable(con,"book789listcosts") dframe cat("\n## 16. dbWriteTable(conn, name, value, ...) writes the contents of the dataframe \'value\' into the table name specified. Returns a logical indicating whether operation succeeded or not. \n Eg. dbWriteTable(con,\"newTable\",dframe)\n") dbWriteTable(con,"newTable",dframe) cat("Checking the contents of newTable: \n Eg. dbGetQuery(con,\"newTable\") \n") dbGetQuery(con,"select * from newTable") cat("\n## 17. dbGetStatement(res, ...) returns the DBMS statement associated with the result.\n Eg. dbGetStatement(rs)\n") dbGetStatement(rs) cat("\n## 18. dbGetRowsAffected(res, ...) returns the number of rows affected the executed statement. If no rows are affected, \"-1\" is returned. \n Eg. dbGetRowsAffected(rs)\n") dbGetRowsAffected(rs) cat("\n## 19. dbHasCompleted(res, ...) returns a logical to indicate whether an operation is completed or not\n Eg. dbHasCompleted(rs)\n") dbHasCompleted(rs) cat("\n## 20.dbGetRowCount(res, ...) returns number of rows fetched so far.\n Eg. dbGetRowCount(rs)\n") dbGetRowCount(rs) cat("\n## Commands for Transaction Management \n") cat("\n## 21.dbBeginTransaction begins the PostgreSQL transaction. dbCommit commits the transaction while dbRollback rolls back the transaction. Returns a logical indicating whether the operation succeeded or not.\n") cat("Eg1. dbBeginTransaction(con) \n") dbBeginTransaction(con) cat("Eg1. dbRemoveTable(con,\"newTable\") \n") dbRemoveTable(con,"newTable") cat("Eg1. dbExistsTable(con,\"newTable\") \n") dbExistsTable(con,"newTable") cat("Eg1. dbRollback(con)\n") dbRollback(con) cat("Eg1. dbExistsTable(con,\"newTable\") \n") dbExistsTable(con,"newTable") cat("\nEg2. dbBeginTransaction(con) \n") dbBeginTransaction(con) cat("Eg2. dbRemoveTable(con,\"newTable\") \n") dbRemoveTable(con,"newTable") cat("Eg2. dbExistsTable(con,\"newTable\") \n") dbExistsTable(con,"newTable") cat("Eg2. dbCommit(con)\n") dbCommit(con) cat("Eg2. dbExistsTable(con,\"newTable\") \n") dbExistsTable(con,"newTable") cat("\n## Commands for Freeing the Resources \n") cat("\n## 22. dbClearResult(rs, ...) flushes any pending data and frees the resources used by result set.\n Eg.dbClearResult(resultSet)\n Cleared the ResultSet :") dbClearResult(rs) cat("\n## 23. dbDisconnect(con, ...) closes the connection. \nEg. dbDisconnect(con)") cat("\nClosed the connections:\n") dbDisconnect(con) dbDisconnect(con2) cat("\n## 24. dbUnloadDriver(drv,...) frees all the resources used by the driver\n Eg. dbUnloadDriver(drv)\n") cat("Freed the Resources: ") dbUnloadDriver(drv) cat("\n") system(paste("dropdb", tempdb)) cat("Demo Completed\n") RPostgreSQL/inst/THANKS0000644000176000001440000000072211455242163014323 0ustar ripleyusers Thanks to my mentor Dr. Dirk Eddelbuettel for giving the oppurtunity to participate in Google Summer of Code 2008 and guiding me with his unending patience and knowledge. Also thanks to Google corporation for their wonderful program to bring students and open source organizations together. Many thanks to David James for allowing me to reuse code whereever required from the RMySQL package. Also special thanks to Paul and Seth for giving valuable suggestions. RPostgreSQL/inst/README0000644000176000001440000000712611660732422014275 0ustar ripleyusersAbout the RPostgreSQL package: Database Interface between R and PostgreSQL For details, see the Adobe PDF file "DBI.pdf" in the doc folder or see the documentation using help(PostgreSQL). Examples provided in the devTests folder illustrate some of the functionality. ============================================================================= Basic usage: ## initialize the driver to PostgreSQL drv <- dbDriver("PostgreSQL") ## create a connection to a PostgreSQL server con <- dbConnect(drv, user="userName", password="123456", dbname="gsoc", host="10.23.34.23") ## run a query, and get the result set as a dataframe dFrame <- dbGetQuery(con, "select * from someTable LIMIT 50") ## run a query, leave results in the library* ## note current implementation does not leave the result in the Server ## and there is no benefit using dbSendQuery() fetch() pair other than ## compatibility. rs <- dbSendQuery(con, "select * from someTable") ## fetch up to, say, 50 records dFrame <- fetch(rs, n = 50) ## close resultSet rs dbClearResult(rs) ## close connection con dbDisconnect(con) ## Unload the driver drv dbUnloadDriver(drv) For a more complete example, refer to the file demo.r in the devTests folder. ============================================================================= Important Information: 1. The present version of RPostgreSQL can handle only one resultset per connection. Thus dbSendQuery/fetch usually do not have speed merit over dbGetQuery. ============================================================================= Frequently Asked Questions (FAQ): 1. What is Database Interface(DBI) ? The Data Base Interface (DBI) provides a layer of abstraction between R and relational databases. All the classes in the DBI package are virtual and need to be implemented using the various DBMS libraries. The vendor has written some functions for communicating with the database in some language like C, compiled the functions and the compiled code is the library. We write a C program that calls the functions in the library, when it wants to access the database. Every database library is different. The names of the functions vary, and the order in which you call them varies, and the details of passing queries to the functions and getting the data back out will vary. To manage this, DBI was extended for individual database back-ends MySQL, SQLite, Oracle, PostgreSQL via R packages ROracle, RMySQL, RSQLite and RPostgreSQL. DBI for R-language was initially developed at Bell Labs by David James. 2. What is RPostgreSQL ? The RPostgreSQL package provides a glue between the PostgreSQL database and the DBI of R. The C programming interface called libpq was used for communicating with PostgreSQL. 3 What is libpq ? libpq is the C application programmer’s interface to PostgreSQL. libpq is a cross platform library providing set of library functions that allow client programs to pass queries to the PostgreSQL backend server and to receive the results of these queries. 4. What about Rdbi/RdbiPgSQL ? Rdbi and RdbiPgSQL are a 'fork' of the DBI interface for R. RPostgreSQL follows the DBI as do ROracle, RMySQL and RSQLite. For any queries,suggestions and comments, mail: rpostgresql-dev@googlegroups.com For security issues that should not directly go to public, you may contact: Tomoaki Nishiyama Neil Tiffin Joe Conway Dirk Eddelbuettel RPostgreSQL/inst/doc/0000755000176000001440000000000012124517222014147 5ustar ripleyusersRPostgreSQL/inst/doc/DBI.pdf0000644000176000001440000012312512124527403015246 0ustar ripleyusers%PDF-1.5 %¿÷¢þ 1 0 obj << /Type /ObjStm /Length 3058 /Filter /FlateDecode /N 73 /First 570 >> stream xœíZÝsÛ6¿¿É\d$’™NæìØN=MjŸÜµMû@Q°„†"U~Ävÿúû-J´%Ûrb·—N*Àbw±»Ø€óYÈÂ4a‚EQÂ"û>“,Ž‹Y¤,aÜ‚¥Œó?>ãæ8ga(… :éûŽ˜äØl$™ ÀT3‚>X”‡*¤H¡)ü‹$3™Ä¿B”!‡bq!$©ÕFؼŒYLôeÂâø ª˜ä‹­ÇI‚gq zØJÊ¡',…$%ÝGBþã»ï˜·Ûµ³ªfÏNGûY›³F5ìl¡rì¨lU­š–½©«nÁ~ÐÙÑ›Ñþޯϟ3ïu­²VW%Ö)ölÿ%O¹øI ŽÿÒ‚¿ÍÞ«ŸØ…nglvµPu­ÎÙ"Ë?eS°ÔÕEUO éYxÁNUa°ƒý½wgpÍ †ß³EÑè¤jÚi­Îþýö{weš¹íè¼®šê¼eè²3UVõ v\gy¡^ИnÑšýš«¦Us–WóyWêÜPî}Ý´µw­šÐÜ¢ku9·'u5ér…]M>ëEÃþi uQ¨³gÝøw•·ìþ~¯Û’Ùe¯º*Y¿;K÷<ËDº¿wDÒ|õÊj£,«¶aq|}vŠãK¿‰ùMÍ/¯i¸mÛ„¶¶‰lcQp‹ã7h£ÙØc àd5út^M÷T5UWçÐj‰xï¡+›ªž¿³9æcKÈ;^¨r7'yc˃w¨["vܵ….ËEÚS›ªwÕ?4j9m†:Н!¨¢š2ï?Z]¨úæ;,‰50ñêUÏÍþŠìO?ÿB'Æy+»¢ NIq\åŽ$ç(’î""WÉ4NÕË{gàíôÈþ<›gºh«—°=MÆÿjڬݙgílGµ³?wò)y{°\ÃGF2ãFΦÃmç{æ-Y àŠ$Ïg2jØáÏoäðšHñ„Sø$ƒ$a§ùÈ€?ÉpIrÍìH D="Én¼¤ºAºˆ ¡(€‘Sˆy"ºë"&ºˆ†.è?Ýu9]űD .=]±‘®àv¿ÑSœu’dR”âP:úO@2ÚD2LcœU$~ò$åF’ˆ&_JÕÉx#IØO)uÛÖ†6¿(Šuµuï Ì« B2å9&PlBü øïšõkøÞkD´Ñ^UL†(ƒk(Å— <­æYy;N¹ Îïß“8ϳ®ÚãvžH¼³Ýþ/»äà²}sÖRæÖAH@ìý 'Í2J®±™Ah{¡ëÙ0-lh6G6ˆÂ>‡p)ÃõpmCøÍ &k‰wønÏ<‚è¶ÌãëåÝÞÑÚÝ[™ÑMt„$Zç·{ dôz–ÕD¾¡²Ò¬^¢“ýtÝ´G•‡Y¼·W]Ræ*Þ%4y¿ËPQ].õ1Zªåm6À`Ùƒf-à®1^cØû¯ž´3:F"X ept‚ûŽŽ¸íè<¾~Sº¾ØÎ=¬Å>­œÓmÔ¸t1áz9È{¿C2kîþAÇm멇 «Äº ñ–•É£kâÞYØÅÂ.ÁAŠ{)¯óÎw!J}‰´1ÄÖ$ÌbÄ(0Y£“âÄ¡¦k¥G¦—®¹fßñÐ8Ń-÷÷·Œ=áBn°”û®`Dü0Kñ —Ì5‚Û$k³’P,žƒÊKž¦kñŽ.Z£˜.Iד¯º¸ºòåEÖ4ª!Ö+èò4&OðþÅÔ'ïS_ú—Å’¤Ë¯[b|ÏVú¸ùØ%O}ÔHËQñF|ËÒóo•Þ¦‚&¹Oz_WЬ2Õ5w/°IϨ™ä_ë·ÏI’J¯Iªï$u«Çû«ê0W5‡ËªÙ©3ZbïÔDg6¹%¤’,NMe²¡¶èVØœÓî?\b}@Q-íÆ¥eLÚtBZÔÖÔ¤#cÅÉݸ«ý¹«°¹«.¹;Üe¿<Ü­¤îøí↛õYÛ.^zÞÅÅÅÎïÙ猞ivòjî-ÌËJÛx¿Oƹ§Ë‰ºÜ™µóâáíôlûôNè³éÂVgãnN§ªÔ—;¥j½ïï½þ¶PÆÈ”^°·e »›­ÅU;ƒw­ê©×V 7^r¿€=$s2ñÍM+=,~%{“±ÞY¨º æ¾à­$¢—NøiŸžE·¼±¹[Vó«æÂXÚ¤Ê;J‰Ì[ŸgÆ¿€Czƒõ¹¹€—ü«Åeޗƪ(FE6n ›4D¼~oðLQDoÞ üΓ=L¬Ý³ z$§Gø¤­éÞôÊ7ƒÈ¾>_¾ÿ}4W»‡+Ÿ»¼è%|‡ÕLJMëDÚfyN®Ì;×ø¿Àÿuf2½YWN³º›Y‡ù· ×ó ×VÓªTØFM¡to\«Ïàb®ËŽ;™÷KžÕ„çO׺4 Õ4šnè¼iÑ¢?:Dö˜ êÌ;18«@ÈOÆn6¢n€4›Né.ܶ9]Ã¶Ï uÉ<œ>x‡®ÉÊ ôà™vº0$ uN·Êà:^‘°£}¯ÖÓºããhU91RPsÛ¶º ݶÎ&jžÕKs“ŠÃP)“x?O4}R )ª@XyW“b®Ð“$Ëê“*Çt„“ï-A½¼Z\õˆêɹ‚´u ŒpX^QMuždOÞìj1S ^«©nèÛì{žåVjZ+0K_XmyíEÕt’® Ãv†éU7Ë»–ôÚ!«(u5!›±XsdE‘Ÿr°Ìͳ&ï Ã]’˜é?º¬nIKø{–玔nÌCˆ·ëLb×ÑÝêq×Éyw%‘]c€Þîé’—‡äÀ!9"9X->rpGîhw´‚;h¡ãñc·èØ-:.:îV‹ç]ÑêEq…Awv>8 †C V+vóïgUM¦¤j±0FLeEæ@²!ŠÌ1‘­PeVLF󥘔C¢5D¢V‹µƒÓNáô N‘˜JG¼r‹*·¨.ªz Õâ‰þ¬ÍRçÖwn}7\ß­Ö]¹ùÖ éj9s«cü濹Áonð›ü?wƒö¶ìÙ~•ÎZXßsfkâëï‚izs0xNßMÚÑ£VÍ T8è Î#=Nå /зe¹½ÝÛ?¾;Z÷¨`‡OP4íï½ |ßÇœ{®·s§£ *Œºç£~´Í‹ö‹á0N²êÑ„CÊ?U UŽLÙÃÝCã]wÆÜÝ¡Üy©Ëƒá&&]™gåhÒä O(ÄpTá/÷— &L-6štãJ74ßœëW¹ ;S9tDÇ}Ö`'ê‘Ùž/úi1PÝ Hð·Ù‘ã6ë—kês=íjc$Üw{6Oˆãaß0 Ghû2Ó«J†#!‘ò#dWC:dWbÐÄÈpADCº’¢Á@LC^²Au_›?/LÒëCÄ[p}ˆØK®‡î›Õáƒ?w_®?Pâî3ÖáDÜ}źö9÷à $R_l˜ ÉúrÄ‘`!×çK¨wújÚ•’ÿì#Bmendstream endobj 75 0 obj << /Filter /FlateDecode /Length 1369 >> stream H‰ÄWKÛ6¾ûWèV²ˆñMÞº»n dÝ\²=ȶÖV`Ù†$'ØüúÎph¯7MŠ¢Z±i’óúføÍìõ|òü…+d1¿ŸH/”´EÿòRz'¤+œ³B©bÞMªb=yþòVëaR‰ª‚Íåä»â¥2–Ýì»n¿ƒµölÊKÉê±^ÔCC;³ÝØô÷ܳz™v*vǦ׳;Îÿ˜¿šH)¢ÍÆi©X…ÓN˜l<{WN³ÞÔ8Ín¹a‡fÙÖ[øm j†‘~½DGúýñ@f„7Î¥ÒŞ) Iš{®4+¹fC».W‹_†±EWÑŒ›/b¹I*@4ªˆÆë“ŠŒ„r…dWÇõ1y`Spš$Ÿ¿0i#´q,-¥Ö"ÖZa ÆZžÝT!žÝ8ðùÇIÑé$G«,Ÿ9?žH^ƨØ{kú;Ö¦ÜDe5¢?UQ*!#ŠN/,B(kÙ  ØA‰lÏKÏVÇeÚhyE¨ÒW¢|T©*ó¨R“J*SYv=ÃÄv³­a— X!–a6AOÚÚ­º×édDCÌãW¸ÂÛÒ*Š ÚS µÃì€ö”›€Š¬ o¸¬Ø@©1ÝÝÕ(Rc„WÒΗéÅr}³øØ‹³I'*mì鮉žŒ !À˜Âï¿Y|ï>!f“[à³ðÖ©T·À¿„¥~4¬iß~júÿ1¬ofKÿhXðvv.¬üËЂPÁÅo…öïCr9$ öƒûn¦Ì†ô®ŽÛÿ®ÃSæ‚#¡L —ÏÝsd¢‹!À+·ÈýD…s4{8p !j¯1ô7ðË‘D[£à£ÖP,&«óŸ/ÙÙ"ƒhö;ÜÛm;¶‰ÿƒƒëY¢ú§e>t(îØä’Cƒ4„Ô\8†cúÛ ¸à¬b+òÿ7HPÛµ@BŽÎҪݧk #c¨*t!\ºp N¦@HöŽ+®{¶?ö\j¶Lqxç–‰—p;uZ©€ß…šG »'\}µÀˆ†±¯–žPaªE ýj1hm¿¦ä9º¼oZ œÐœÕ~yìd}Ð×eO”·ä<VheËDÌÔù¡•ѽ]©I‚÷PÝ©çãíE“N>#àM“EÒz’/Ýâ>‚\²ÝúX¯ñÐD˜ÎÞ ¸Ö´)z„ðBL´¢ejÑ06`ïG ±©»@o¼EJôä-®¶¨÷˜Š 0éÛ¨‘=˜R@$<_Ç]yÖÕ;p1C'ñMƒßÃØtWÓ´ó:™De_˜ò³Í­9U¸,}$—sŒŠbkÒ óPå[5w8_`Ó̹Q!±²ÔSÁ³ä–ì¥-L‚rÐÂïqS±%A=ÐL嫌:êë(g›ý*k’g]›Õæ$õh3ž3ƒ’ÉØ!í<ÖP¶tî©é¿Eÿ©Z’¾Ÿ¸‰4¸<2àÑ ?ž¨!•²¡R~Usà¬O\…9Ê’÷ìÕÅ®Qí ~<ÃgÑ$ÐЗy¼ØïÎB^²G™?®ð'IÌN:´#[„ÐZ‹zð­@X"ëHõ¥3oPÑW‰6* _Â’Fª÷@§G<ìrOàÛÓ¢R^„ó´xâ‚M›< €\ ±ib«eß.š|ç`Èõx@c%$ªÂ»B–6T[P㦡q/é¢7by³…áþ025ÔÃÕÛ ãc‡ýÃaÛ.ÓK$STÕïË‹W“ç‡lÝ×]×îÖpSU¬½T~Ç kéDÄ?1J/\0>ñ4âŸ'€+4×_ç“?a»øç endstream endobj 76 0 obj << /Type /ObjStm /Length 1672 /Filter /FlateDecode /N 73 /First 620 >> stream xœÍYÛnÛH }ïWð±yˆ=÷Ë¢ÐÆ›n€î6HÚÅ^ÇQ[·ŽØrÓýû=”K–5Nb¸h Öeæ<䜑÷$ȇê/’4‚ ¥IÚ+ ŠŒ4Y< †\Ä;‹Á†®&xŠ^ã’¤ðxƉ‚¤R†¢$©îàÆj£ÒÚHÑ’tïI/-°ð‹ÁxÁá=ð¢ÁKÅ„Â[!IIÁO.*¹š”rüÊ@y Â’2 *`œ2ŒÑÊz”³<&’òjI Áz™M’ÈÑA3©I cØ$ÒRÁ¨¨%+'iŤIOZ[~ÂyV$m1CBm™ÌÔΦ¼ŒQ@ŽP\‚##_X2l¥TŽŒ‚éÖͶƒ?cª1‘Œå1Zq–¹•ðÞƒd2ÙÓšLdKµ!+ª1–¬<Æáî“Ú“5–DzVó˜HÖ±,#ÈzËÞ’p:ócÙÈÓÁ¬"Àˆ“Ì!,q ºHÌtÚótO®BF 8Ç:›HÎ+ÿìÅ êè_Ò¹sêÿõ÷?˜KbòùdB—Ô?ÏF%Xáz+#zN¶JW¿ ¿üü’ŽŽhÙ¬¤ç3ÌyOPÿì[É‘\I8N³¼¬¨îßËIFÏÿ̦3Œ?èFQ÷(X(gÓì+¯—&äi^N‹ëy…°Â=.æ˜whÚ4$œŒ§x„%U¡¼òYÜ,„ÛmÂ×í¼:¥ãÉp6Ëf4̯é÷¬üT\ÏÚöͯV ÔTa!6åÜÛ¼D®Pél ß¾“·å þnnòòÞ^}Ö6 5ºSBeȽý‰LÇ_³é6qz%Îl§'î¸ÈólÝ—"ÍABŠ~œ”ól6Ÿlp¸„7+{Ü–@h¹k0,‡ôî¿ÛŒ~ÞÞŽó1°D·+t¿ Ý®¡¿/Ç“q9ÎR n¶º5з·YN§³Ù|»oÆ7ãrÈx)1þ …ì×Ao1ŸŽšênä…,™È=(n‘|$§eizÑ72ϯßÊ×P4#¾{}Á%©‚>:Ââ. ??Aò\’q‚Œ¸Ôö%I¬ŸM‹ÑEÆ¢ûgƒ¨Ï^6uV{L˜p¨6)LXQ ­[g J‰¤f&_Ó‰:ßæökæ:œ I3¥“j¥›D¡|P7‹ª™ÒMHQƒE3.©™r¢ö€²²Ëë`:&#Z+ajw¢ÅÙæ9JUÌ)»ð'»ÁœYpgðtÓ z¿¡Û„ã^Ϫ ƒSK?¸Pðq(Œë@ÜoеàœMÆ ºØ¸òFT~Óm,‘Æ2ªÆBû×÷kgÜ[1f¯š™ð=áœLgíjKѹw˜jÅ^ukÁil&RK?º:ûêà;²¯ÝïJmÁ9ìdR¼)_ë†-Ôúé´nÚ™F޳¶#Ç5Áx¿â7<ºÊqQ·r§óMS÷›BZp ;¾ÔÒ–¼®©Øûmëöq-8‡­bÊ«ÒÙÚ«Âëu³1½´l3¿™®üÖs…ašÕÞ·«ý˪q» þûóÓÅ¿çŸÊòö—~†v¯w•M&‡“áÕ¬7*nªGý‹«¢ørPõr¯Šéu6…0ÖF²ðãêF.n~£þéJ5È®zKĤå÷ó«’»÷þ›qþ`uý2Ï‹ò^»n²º½LnŒÖäÞÍóÁ‚õ—ÛE±N:_‰æ’Ží%¦øîî®7÷ÊùÝ8Ë{ÃQôb3ö!C»N¾?¸8>TBÈض¹\’Ѽ®åÎV›ôŽAYS–2¶£lƒÙ4˜ov~®«ókƒé4XðuVT>¨Çúãóðë°7›çU°Š»|R ¯Í.±îPƒž=< Âîìo)qR× G £‚˜Ã ×w(1(L;[Í'€Éz'V[ùpšÕ˜ ®Q<½t˜0…7ãÑ´˜Ê*V®‡å°_\_úO§Maˬ¢À<‘bgÚTH‹‘ºÞ¤!¨ÂO,¥T• ”V»[-ÓG^4ú'â÷8ÒèŸðZ|äéFeÌŒ­7‹£9>O^ü.s˜2HÎrŒ’ný¬Ò.e¯zª#çÅPEÕÙðcÖdJîy´·ã.èG…›[ÖC÷”zØ6Ú¥ bh´§¾«;ÝÀJ×Cìöë–"Ú'uÓÃÛiÁçÕ½búqGªørïcv§J%òQsóØ.÷?*B¬×U„X¤ÒG™ýô²[âX|Zñ÷ßQî¿Æ,¾£„%ȳÿýmì±endstream endobj 150 0 obj << /Filter /FlateDecode /Length 2063 >> stream H‰ŒWÛnãÈ}÷W(Þ‡mC.ټه±eïNàÉìÚZ,‚(PdKbL‘ /– ÿž:ÕM]lO †nu×½ª«O]-.~¸ fÞl±¾ðÇ¢™KÿÌÒó}'™ÅnìÁîÂm.~øéÁ›mú Ûu\ן-ò‹¿ iÙžëºâ“eÇ¢,;å¢ÁªsÞ)‰HïÔÖ?!µ‘V›:iä³V½ÒJ£$pℵ-¶Š¤Ä©(,ÛÙ­²ÞŠ6S4¤]ukËóD–Ò¥˜_Y lóÄÒ¢o"3µY— ªÇN$†­’[de]«|(-™ˆ'(*‡È’bh@tB=·¤€ôÏÄõI‰±Âfšl)¥¿îšz°U]Ѐ#àÎlÏñRÎsr.«á•€É÷$3­²üqâq,;ñ‘T¶mUæÙP65™/ÓPŒ& >e¡©«-h S`)¤)ËóÅsÛ0!)’‰ûŽY¶Œ#ññ—O˜|oÈ4!-«r()dë¥ë‡m6ÀYWäÍn7Ö°Aб§à”Ö„»)…>-y"T^.]Wæ`’ÈQ,>?€†Â%¾tY^©8 Ä/ ˜Ë›N=üzg¶•åŠ!wSIyÎ:î@KïÊÊSYÀU/rÅ ›Èb³ÛÄ[(ûmPl.¶§Ò EÎB¥(:*‡”ÊÁs…êz®ã‡¢ƒw­2 H¨-? >)EóÈܰˆR–àkÀ·Ë°duYE_üÑT«HŠ:Œ=ˆ¥”D½³Òæ(KFZ! ³ƒžÎ¢HPjeèÔBÒšBÑLZ°íÙìÍÛ,»:0 n<[6•÷÷¹Å²¢$C¢O¹®ª[ý`.˜ôcÊ;÷ƒH0 (_o¬±ÉCFÓÙüŠ®¬ cŠ +ÈVøš ü“i!R·¶2 ]9¥PjK¿ûŽ”QH®·MÓ+½æ»‹EÛ5­êôz~…ÚÊý4íò ¹¤¹#Ð8á&¹þQP¯:°˜pI'pS}'ŠîISüÙ6ÂWs¿—_æW×—T»§h6ÒöšíZ°„Èڌˢ¯/§õØw¼&âËv_œ>1gŠÆb2¼änÉ’½ÌŒÞ}Ó=𠿝vy[n¶Sp*õ¤*#g×6ÝPRÉèe«ê´I=›, ®Íò jáκËv¨’0ŠtÄq¢žÏDžÒ$œ'NkuÞøMÑ»+ûaÁÇK—‚³øçëî«©nKUš á qù¯1{TýYªŽ]¯\SJV7ÏÄÚ³†3ÖZí¿vª«üF‚çÄi¿V~¯vÍ“:Añx%‚ØG GCŠÕï]9¨ÿmƒ©ÚršqhÇá´Lü4þÿÊ$«ªfoÒ@+ÕÙS)ÐÆ)í{w…óõN ;Õ¿®ùz”~U÷r6ërE*I)Çgr.nîn®ZÆÆ)‹ÓrWv]Ó™lœ¢ÌvæL9OM5Pÿ¤½ó._ÞÞùl¤¨f÷• íX…po3IªTþu§²~ì^ê™ð{ÿùæþæh®^ýh.ÁaãЉ&?†—ÖØð£>ø¾¬{zî¾ÿ†_îç7÷šòêoÆhŽÁ±0í÷âIurž—¿þvwÇä‹?^ˆý¶D¹ý¡Xýœõ×Í®­Ô Š%² ±ÿÆ={¯ÞóíX?žË]«!ß2çT¥ÚJ àK÷ý;xf"hó%öLJЦ¤¶É ž¾½Aü´Ñg!þcºÃáJ¼ó ÜvÊôØj¥dx3vù«¾št]©¬»çkh¢shA“xÊ>Ÿý¡O!ÎÅê·ºj²bz=èЇýæ µÁKÀABO@„! J¤aLè¼"ÐEH甎h7–÷c€+/$¸ˆ2Nù¸$N†›~ài¬szÕ¯>:{ i¶‘ÖnÄ#.£'7Z¥Œ´ŠŒX`u?ŠE£më "ô* ¢.TKÝ@a¶ð a4kœùÚÖô^aŒ|0&$ ,$¡ßzÃÇüÄtL ´^ZŽéÔAêGç•û©.4[1Â"!ÅÁ§8¤˜2d¾A‹„€|4Á7ÆÞ!©o€ƒ„õïàC åjÇNJ?bÃ5.#™î9 =ÆmŠ=ÔÍj³Èg¶Òø4hö³1„P64Kèi¨ZàkOwdòþpG¨¬<]VÜKtx²r HÇ£]oilEÇÌ@lElÖam x¤ø—f0œÈ+ä€Ê·ÙQO”6ÞFÝpžy:L hÁ¿J¿:æä5Ó±Dàèà˜Pó3ë$ûk䌜xbÌË|펆£ F¡ô8 }˜ZáÉܰB|G„Û$rO.04N9!ãf£¦Äø‘˜Ð9¹°Í4tGÕèâ<&}*àÅîâGªÆ6’¦'AIó+WQÖ™‚ñø!µ9× — íó£¨]4ùÈußiÖùVùÃI_;©Ç‡á à6 ,R¾gÀ&}i¦±À=Ì XÓó5|¾Ä2àxNº¯ÈŸO©¾í:2ÐoRIùjBó¨F‚ÄõØÈ!2“„{©¯ÃÁ·_PÒ_yj2£ØNqœ›gÔV–ÔÊhɧ©Œ‡'*/‘ÂÇ3'¤3ϽIÂe$w;êX¸’^rò$8³§ ê8V˜ÜÚf2ç+ΤIEá[©0i P(©]mˆ¬çë28II:6´VÀG’Z•r6޹8ôŒH¼išÊÃãH/=87‹‹ÿ 0• ˜“ endstream endobj 151 0 obj << /Filter /FlateDecode /Length 3197 >> stream H‰¬WËrÜÆÍz¾b*«FJ¢»ñÌNí„.)¶D&YˆY€„3/c@ÉüûœsocÑŒâJ©Äiôãö}žsûÍÕììÊÎíüêv–ÄÖÍü[ÈÈIœ§ó")b,¯gÉünvö—K;¿Ûc|ÕðÏ—™¹Nl]ý<;û>W1U\å^äèÈ–sóÉ4Ûh‘›ÍáOÛ gKºý3KÑÂ%©°àÒ ÷2,3çÑš7ï/£]ýðßÌÈ+Û” |«ÆÇIœ$ŽC÷¾­^ŸZSG‰Ù,9Π‘uæ×¨„Ʋns³r3DÞàÀºÝ {µ Ûè‰á>ˆ9`DT˜÷÷m¦YlK ”úf{ŽÇ`U{ ·…Þ èÓ×âlW˜¾Ý?pj5ì϶È×9³›|ÉÖÛ^6¬ñå=,ÆÍ)ƒdE=¹ÿ&˲*vî·ìxlbY¯ªõgG›V :Ya lbî9®EÑ¥XÝÉøî›N}ìG(ŽÇ °W…»Íí¶_×PŽŠ¹Ä\zpÝõbYõuD}Kº\Üm©.³«¾©÷ÈI§Älo~FÕ|›»]§¿ÃÝÇcGí‘>j$R¼“¬€gë;ÉjïƒQÛwÕ+ØD=.F‘»ùÂÆUUeó«sÕ蓹@X3 °/E :‡;þA]¥Inê>lX¡žÚ[\—:ËüNûœ©›#¶M7¬yÂ3Ìì£T×Û¦»F­·G¯°Íï±\ÓÙœJ+T> “ã.;@’ º¦– Ἠ>¬-u¢œ3Ÿ-wØìktFB7Àêx8UWüòÐöÐÜg4‹¢ÚÜ=À¹PÊç‰LpaÀÿûíÃDz_™N¦p,—áž›ss_÷K•Åí[BBµ Û–[¹!÷¦.µ·mßnš–§}r8ƒÕKXñ ÷ŽŸVµ ’ûvÔ“û)‘!¯þƒÔa \Š ¡ðúIÆ9JóHrÀíz¯Š\JÌǨ„z@hu¢Ò*AÀ$µàK¤Ç4µ>‡`¦% ·ï"WÁd$IÛkÍ÷geUMRQ6g6ì]Ø¢ÐÈ2ñl鯭Vms ¿-ÄS¹¹åžŒ?é$ñž?î–d¶ù˜ðÏÂVÎt’ÿšÀLn-M6î/Ÿ¤!U¹}á ÑyÕ <êÌò½Ì|eÝ¥*^ßðkûùå¼d`7JÈ’zBÙ ÛÄ,²)ëÐ)q¤tŠ£7È€ 쥇}Ô!R¥qþ\‚ʈ¾â”ëL|óË•f-É÷î•ßé˜J9¿¾}?F?ä$k<î)¸Û‰YwÌ´¤B¦ñ*v#!‘CE»Ô›”Ù$;Þ—³eàuï§Â|…Be©Ô=‘OCâ³§/´T¸»(ÍMËK¿ Ã[†ÜWG·@H~¨"K1Z!èÅÈ»X&gX §ÀŒŠÄ+á’ úš»ú:Ü(Ö“RY¸*•“€š•‚…«¬¨¾Þ­$â -â*š0áÚ9(|j0“Â<¨ºëE y¢ x6¹[z ¹]Ê_ã ÷FîXIˆ€ctÛuD€Üpæ!ä OJ½¢&¦“›ûíB£wðª0ø¡^ÒR¸úa„$ [„”^@e2x3‹8¼çI¶ô(‡ÄSUvè3¤UéÂÕíðEP‚ç.µš¦ÍÇWùÿÃ컋هٛ«¯ZNç@ÄΊ0íñõÖCšÄe–9Õj1éÿ;úÅ#@ÈÀ>8SèÚÞ„t:Ò…ZûíßÙ¥2Ìæ°oˆgÍ+}ÞÔ²¸|êËW"ÞUÉèO§®‰Ÿªéâ$-Šã®l$Oá|—¢+ØCM­¬Ä€Ç´: ¹€”g¬yh8êc¬dI’ë¾õ"´ÓIŒ~Ï?­ÜÝöa¤_¢Qÿ£ß)ÝQÖ’P­bÁ AùŠhµ2ùÂð¢Òà…4öi.q Cë}\Î=_§O3-*pÂ94xsA·§æíªÞï¥j½¸Ÿ% ¤‚Å÷-J …°ðÒ{ë…¢·¦eìÇKC›ruÏX”Ý*Ï,¡ôÌåBß>@îxf]‡.ç@¿—íc—KÀ !pj^Œ£ùyTñ›–!æhl¢ÉZáÊi—¤8¹YÊv4cÂlAˆ(³TR”Ný¡^=GVÏuØèÙoêæß‹v³¤»³"47ã'á.ró#ÂÜ×ðL˜’^¤!r¢‹-שRRKiŒŸÒvîS¸üà6»~Ë}Ÿy.<>ÜHJ#ú®YîŸc%-W‚ÆcwSDúžÒë&4w«0qx_DN3olYúÐ cª£7!öD;ÌÙc»Ãžþ¨GxùNCÒ 3@ã:oµ±£ $Žíò:Ë® e§•ÏŸúâoôã–J±VY³Ö~÷µäj.Óã­ÁG¾é-xQµ\okA"$KÁ©; ë# zÚ;…#¦/ ZkRzÍÊ$Þ‘›í tx_fz;'°Ší·zRE®ôw6[<1wƒR¤ì íy+€CͨÜQÁ*´)‹£+ŽùÿES©›ê˜¬äÿ¡¬r™‹N½örúâë_uÖ¯•B½z?669œ˜.Í?"+—y6ƒªe7JžÉs6*üyÁheõ}@Ü[·*-T³©?×£ õÄŠ+ÉÈ”þ‘êd!œá&þjPŸ©ž)iZ[)ê ¡Ž… ´'+™ZfAVéú^Ç«î†_à¨LçûǪLb›dÕ)UÂL±Qè2$v õ|9é5>‘‰>Ïå­Ë~ÈÛ64v 5ä™SŒô•öRðbÒtûvÅi`ßp?Ò:>ÎR‡·šF6NÕ R›¼¦ZqD×Dcÿ÷eL?@2ÚŒaòô—Tùi—ø~Òj¤Õz¤å§…«èÏ¥I8”Rw,k‹ ç¿…“OÐ 0»½ >Äð}Ä(’á­<Jl JOXƉOC¼øñæg>)¦}N§Ié§Mâ+]wc»–¦YqšuÞwŸáêÿ‹¬·ÛÍFzþÍyE\•Óô“Î@Ü?•Šw€/í3R?¶û‡Õ©µ¾ÊÝTØëH®ôQ"TÙëÕŠžgœ0‡Ï ˺?¸»¥[¤Ð‰¾Ÿ”jû@V#óOÍ2KƒS>aïú™ÎÄ'‰9Ÿ4ÙÙâɤÄ;¾b%cJþÒùÌ)Šz˜ú&òž-ËÐÑ{1ËmVŠžöx|røõ‹ÃÁ_ä§±øéîòûgòÏä?”WËNÃ0üŽ Ëo'Ü8òÜ£´…HU[UáÀß3³«&¨.­#?²YÏÎÎØr/ÐQ&:¸ˆMm6§ÞANÏÙª÷¬7ñ¬ceH GVv_Ÿ¨ÛÍïïéÖsZÛ"¬­§xa/[û—w³?kdï3œå”t9"ãÓ€*ñúS}P&Ïr‡)¯";›¡DÑÖ:ò1Ø:(}Ou-ñ8ÆóǶ%gz®E|¹*ñ•‡¤‹ÚCÅôþÇõüuåä©¢´ç  ÜVïÅy5ªo:?rÃ(¼ÕrX¥Fq§/±ZTÚ„ÂøÀÖCþ§EMÈF/‡éÈÅhòƒ·GnÒÆ)²R¶Äâ¥6+ž¨k°ôJ(€¡ü®‹(éævîzéI€Öx<³Ö¢6^Ÿ(c°•GÜõƒæ“7ÛÝ}ewna•"% dòSKú(¹§´UƒºžÎú¨¿2Ò÷Mr¬dÁ,»—y’6ÇØËiÆK'U{ó“ê;»F³ŸEY¢ ê.Ç}W¥]œT뇨ÄVCÃqËÈz]s B»XB¸ØÍ2ö­ÉØÍÒØ3õ§E!²Ån°Á8TlŒopx¡€ÓõáNR endstream endobj 152 0 obj << /Filter /FlateDecode /Length 3377 >> stream H‰œWIsÛF¾óWàØp™pïKæ&+ö$5®Œ#ÕÌÁò"!‰H* iGÿ>ßëÆNÉ5žr™^¿þÞ¾€gÿ~¿àÙ¯xø’ñB*Ÿ}ËÏ>dŸ>ól½xóþJd÷‡…È6ÙB8^p)3Ëea­ÉL(´÷™ðEp>kª…0ªPñ@ÂÙ̸Bð-GJJ†ÌX]8ñ ƒ®ÐA¿,Cs^xå¾#CyQx.^–Ñ)anBÈ‚)„—cŽ«ÅÅõâÍ»‰ìúna¡‰ŠÎ“–™0¾:jW8xìz»àñ¸¹ÇÃõjÁ./~¹l6_«&¿þ²øùz!)¬7ƒÄP-Î$ÎI@ cAýv¿ÛU«ãf¿káà¼6ð¿Í¶}$:J}ÆS/R‘œ9/ º'U@ˆ}O©Ïxâ=8€zp…1&£?VŒ‚DŠk/ú(:[È1X\ñªbË0rH'£â9CæïEñOÄZ>30Zr“)­Mîa8ð9‚iÏÁŠÃbîzJ=¢ØB†((¬•…AvÕ#œŽç¿¯²ÝÀÕS¾»* ¨ãÕâãÙõí³"æjüOj…Çàq 9`­¨Þ¡W€ÑÒÁ&áÖk¢àŽ´Ä£!\¶<±h@ñ^ôö‘<$Ì`]u°‹•ÖÏ\ݾ?UAXŽ3P”/$pÛS d¢ý<»Gj#Œ=Àæ £-¸1 ±„;Z–z~§^ܾZˆh 2Ék4လî)u¤xíÆJµƒŒæ^F¥„–ð8rAPÑ)c.ƒ~FH8Ò¶ã©Ïn%åAŽåµ© Ëâ<‡ïé %Ü”ÉHÒ •Qx JËRŸ]ŠÒ$§õØçelž¤¦ øÁ¼1W2OÂá*Ø‘1ó[I “H’±}¥ë Q ]«Ðg4J{ÊdºS… ºç©ç—’8ìa,®£Œü)=*Ϻ‘?Ç\É¡ÒÃÒ‰Cç·¢@ ÄD`Grê 4ŽžŒì€ÎØW ­T…ŒÓ,±Ôg—¢<-@DÆò:ʸh4õr®†‚˜º‚Ñ p7ÔÇìN’&\<Ž^O¹SÃ!”S½7ÇLÉ›ZA¾V#ßÍ.M“¥ï5ÂkD=Lz©@d‚KÝFs×r9gb'E#ˆÉï1ÔRoµ*ŽÇÙ­(𹑠¾8ÑЯ-šÅxöÓlþíö F3Íå¥À 'hfAIo\v}¹`ÿ¾¿úø¯a7X¢S-G,¿]^¼q  9>¶@]ïLÜ„C#ÎE , %)cÂÇÃ9vŸiU³iU£jIáJOíp”h6Å +ZÁ1(±¦}bïrÇ6¹e÷§¦Ê—J[&ò¥`?åK#5{› Îj—¹b‡<àÿK{ +US6«‡'P¤ew¹`û†;âðPÑxv™kvAH¿€© Z`×¹d­Dâßÿ#¡Ëøþ-‘HïOUCòµ`eÓB¯@ÞoÒ‡ô«Ö +ÏöwI•¯tÐ੬óÏ׿Â~Jƒ ù’!“#Vuyˆ 0,çd(š Är¶¦4ŽUå VIX½Ï%gß{80ÐO±ò)¾Yǚ걩"ÌîH(Ú'&a XG‰{ Õ¥c_sæR²%q=V«Í T[Ñ}Á6ÛǺÚ¯ŒÙ·”JÁrDf¦roŸä:Ú·$E2ðå¡Ê1A>Ò 46lÿ•7kú…W¥ röнkÍîNô²£h¤´è %êÍy ‘1Œb¤ä ˜HíÙ-½›²­2o,K 4Ç(aPˆñ8Tä@Óxÿµ*¢oÞÉ”ð0X‘Á“xN¿?Þ¼Ó‰×ÐD–¨ â%>ü|[ Û#S[Aôu…ý‘w€:ùï?¹Õ(Cédb:ÁW¡5PQ">&'r¡Lß}³?=âP„h#eM¤_"y.¹pÿŠLWäCÉ(/¿T6ŽÂ.(g4ûe”r±ºŒ—é¦)›º[”Üà¶Ðì/‚$k·N©¿9¥Çù‡T±lC¦•"AeË5ÊÖ Š¡¥ 4Y•uý”Äß‚J©Ñ>5åqO/M2i¯Ù‰‘eõÚì{yȶI/Ç2þ=nÊ#qÛªÖ¾”«c„¢úJþ´ä<gE? ð·ôó £‡^J®ˆ*“qìõYZ=Ó'R¿a7ù$eÐ9¾N‡¼Z<ïÀ°÷õç=Ö?/ß™3(¬s#ó;P†›0‡º¨š?ªºzº¼8t¤Û¯˜àÑ×¢áB‘¹!sVFÓ±×—’Ãî®Æ¥ô*ŠÅÃc¶4³ˆižr€rŒ²[´N} YœÒ¤Œévˆwk$ñ"Âñê<)ëV³|"FÊAêÄ—®fýc‰EHê—ífíËmäÿï Ê>ÛA´™uôÏuE§ÄÝÈmr‚HŒT*°&òœ’w #ތÆÆfbš·øåÏSÕÄÖœ¦81A—±mÐôÁßbÖ8ŒÇî#üéãO?DLÿý‰ÄÇÆ¯0ËU¬XÛ¶6Ò¾C§çÝý©#=¤‰z[ÑY¼G @¤21oã¾PÇŽ†s$fV2¾3ºPÔ©åH£Î¬6a01šckè¡ù ÷µ ƒHžé}ïì“fJD¿šVµ7XæÛj¸köÛäìKà_@‹(«, Å&ÆVivÃ6EÅ£­ö‡¼Ê kör#Pç…¯vXÉb£Ñ÷ØJŽåM^|NAÓ¤ƒŒyî]?.Û=ð:fPðp,§%…b¸ž™‹Ï'«ÏZÏݾٖÇíaÎË9¶¸ÝGREÊÅ9<ì¿Í`TpßEÁ×Óe}û¾:þ²»ÛO  >|×Mñ]f“÷^c=Å”Ýá—Ãó¯A:*ìLÉÓv[¢ä¦SÄðοŸÚWĚѬŠëTµnëÓ·¥™¨KäL‰•5ûN®Œ«Ðo•ÕúEÇ $Íd*ªnw›Yid0shŸ³H`v¹³ÆøX®þ(ï+ ®Øyîb Bɶm"ÈÒÜyNÐðÝ9²Ä:¥ÎÄÝ–TømßXÅÖ›ú®gTiÎ&Á§¶£;ÐŽŠÝ¼ÜĽ-5ŒÛÔ|b<ð1¨Cðãvð)‚Ð Wý§xÛ½ÚÎÕ·›²ë…û©ñu·N+=¯ÓÌpòåñ5ÝäipìIçÔ|£i)ÄÄ!+½V4±ìZREOÞõj úƒ+~;kbs£ñTQ+ œ|Ñvt@‹çStÐõ«”I*àPчG €ß ÔÌç{ý´Sµj©ßܰ¿`ÊŸEÄIWÛùìQðÆüð|~löëÓŠZ¯°qX —æí~·êT5PÊ (Å‘ÖLº/?ÿ7éÕ²Û( E÷ó%î")ÆÆ˜è¢R5«ÎªÝ0)#E¥ “‡4ýû9ç^CH£Ù%`lß×y˜TÓÄ*[M¨ˆbË€ ­[ßE ±ómLÏ­–:?Ï×±*g*ò¢õQ‰u`lcde&Yž&c*Ý:«€KzèEAúfòçÂð~·y9‡C`6ví¥«¿&«oiÌ.Ù ŸÜÃQ8T*ÄYŠ/YµÛመÚôíÒ¾·lÍM}–“4gòûW/ѬüHÄØg\ЖÉ"Åþ/ª8g¯T$1É«ÙI°0!,Æòóò?¦"GcÖ ó© t*©J¬èz×9¼¬]沑|Åó´Q©¹òP`ÏÌq¿³R¼µà^çã¸Ë w K1 aƒZ\È>ÉdÆ&ŒY3cÇkŒÅ;¢Æ¾Ûr"â¦ý,l‰žáFóÞ¦çZï®ÊŽWüÄ&f®Âpåå >Sô<ØNæ!ñQ\g±rSyš´ž¤ƒË´¢Ä%S4+œf <¥¶”À,Ù/dV¶BHŸéãNЯÊå®ÝšµVì‘ôå2ÒWHôŪð9“ã”Åòéä@,9Öô$Â)Aç';•Pø‚í™E¹|§M’Í0p 2ª#Ä€nFá o¦î0³»ewø2«Öáƒ@šhÙÛÓ—DHÔ*@—G²$†Y’Q*d†KÁ0]‘â2Z…ö”Ó¿mäm½zãkñšë=L ˆ­t 9€cJ M:ƒÝv$ù)ƒ_â[µ¶ Ø~IP”®zxÔšš»ëÊÿŒEÄTùñ.‡Ç‘ÎüRXÙ‹m<‰6ÙFôa›@Hù³7 …yW#zOï±R¿;%¥Ø‰ü£Ïì•b¼*Ñ|ԛɅìZìÃe<7ª=u];ª¬¤ðSæ-,*¼¨D…+ñxg6uÛòB>5ö~fÜ„i]¾ÿxzš$ö®šµà–—-‚œ¨ªÍçÚnÍo>9¥ÇÖh%Ä·.¶_eÒ»M‘tØ.µYîØwCnÛú'ß´XÞèP8)Hÿ>7à yFñðüí¯0¥" endstream endobj 153 0 obj << /Filter /FlateDecode /Length 2843 >> stream H‰¬WMsÛF½ëW¨tT‰ð|`§ö"«’hËI,Ÿ¤=€$(Ñ!.Jv~ýöëH'vÕV*&4ôLw¿~ýúêöìÕÏþ\ß.Ί´pæ\ÒáIYŸºì<—yJï×gòüáìÕ/ÕùÃÓ™L¥¤ÅÙ™øuYw¯“ÛÏdÇ;:ÍdAVn¯y›Å¶;qÝ.#Ås¢”¨Úd¢ -–‰ëDŠÍŠªuUwô[&Fà/›ú‰væZ¬Ë¯ø$3zûØ4OI!*Zñïm’‰Vž?…©/i#^h]J^¯ñ¬·‰2âaËçýçößtsonR%µÛß]³‹/e7òÐ)ã÷ÛTp±ãkHñ”X±I&VT³åâ+1Ñ>UÚfç•j™ÙþË,|¹¤/êù2Ñ…xÆó|[®È;—Qx&¯ŽÖÊɼäßD‹K¸.)Z¤éåÐ %S«è¨¡wb>ý¥ênêEs/æí3™°Îß&¶â_ÉÄI#.Öå—tÖÔu5ë–ÿ‹û$šïÏÈd#X¦^ÎDŠMŒM­V nE±sÓ„ÜPŒr¢{¤Ü!)†¼ t|ÁÝÄÈB,ØçD[äÏ^ž’\l§üÄ[Q  zÍÌ+¼š%J´Ë)Öa+ž5¯ºr¹Â>²YÎÃj³Ào†›°Õð ,¬J,„Eœ<1FQÌågwùe’ªÒ¬0Κíðë È|læÀjc˜ÅQx¬åZ‹Ê˜ÔŸ;“¥yÆÅ¶Ï2™„ý7ázOÃtÓyÁ(®¯n>L?Sx=ªìp˜r)ÎX"ñöøC|³ðö”x^Ȱî«ŒÊ Þ~Å ª&úm³Ý`#EºÄ»ÞyqM%wE1¸ÁŸj`Ô3„ñKpÔV‹Q†A ýqïqh²’‰/x]ñ^Ên„…ï ²õyjýQõ™Øì™X쟃lO½Ãa[à)/(eSàþ€pÝ-ïé:U\ 5âé *£ìÊiÙ#Õ3- XåC`Mª»€Ù¯ø§«Öi2É7xENÕU5GwtX#^LCõÑ‹°£˜V8˜‡ßö’?D[š*iÊ÷›ý9!ƒH"Uõ½øÐ–œü ÉΤø-27 |h«´öû[lÐXŸç"®9Ó£—ÜÉ$0§ s˜Ë¨lÚ†ø –óªD¿ùãPWmÙ5íˆK)‡Òä1ñóiÈû½¸˜óÃûr] q@Ÿ8bÀ=?ÞÉ·Š%È'S¨¢L,×h¬¯qû.QHoÆá¶}¸1&¥õ½­A þÉí” >©œ›!'sb±­g»FŠÍõÐ7tw?nbïØ½yF: PGýÑTDÕ™xÄQL±ÆÇÛ2%ßj‹´õàø54ð²îoÚ·ÿÞ)] œš5m[á«Mä‘™‡ÈÅ6õõC`ÜÁgB]¢CSˆšég`p¶gŒ=¤ú 3ØõçDZ:M–âZèýÞX,Gd öjnT‘ë˜ø*°¡‹&Ÿ…šÑâ…ë T« n/6´/^3;!eÔ}G]øÛ ÎŽÌ{‡ÂN¦>3ѱ;n°”²nY®–ñí ªbF:®O6Ç32@ˆåè{b8ÝàżßIY˜dY!nQ†‡ßó%vp±T£Ò´©öÖ|¿ƒ»»T…ëïÞV‹ªÅ•‰J¡ÚŒ´L¡sHµüwÄe]$73â Rb:Ô ˆT ^Aq2Íh*ûž“ÞQ½¼ `¬NÈ7OÇÊfñÇo{TŠðx˜©Ë\eš¹â®|¸¾zs”–;1ûݶ~½þÙ™"æ“ÊšŠªP¥¹UcÎÎ8[‘åz8,XŠÂëŠÐhú.\ÏðQþt"ŠU`dy1G~L(.˜cåFhú&(àQa[ï'›{f±*Ž#êɸK.E‡eú" DŠfSÕ‘³hý]÷£ÒrZ!Ç¢6¹áiÿãÛ)†V]šg§¦¼´ãÉ(^ú`xÒÒï&$›ñ‰¼»7¾ß'__!èï>’€HGt¢Aæ$`¬x»|êÞì'†ÝxA7LÓt7?ô²ÌßùßÒŒQÇ}fÝ -ƒ®lCW[­÷·Ô †TAët,¦Õ®÷<„¡ñϤ;y‡šÆ~¬²Ôoó29øèÛüˆ—B79¢¥çÑ)såšÄ¨a9 r4${ߕȹËÉáqM´½Ñqï?½};Yóìè8Tâçúâ@Gjc÷Añ³3¢nÂé@pèÐd1Ä–í4\ ñºÐüãRŽmowOMΛl‚Yîý°ƒ× çÚ±FÜn6M‹¿uFíª[nV à]ÆãxHŠs]Æé¤¥:©º-Ôæ…]‹¥bAœöŒLý`)üRu7õ¢¡˜Ò†"pîdèÔ;‘ðEÖr×ß2SÂMå'¦ÏUÌC IâÄ5š‘çfJ!_W“gH ävÕ[_7lxL U*':‰ß2ý²­¦]—»„c•d=Û›6Û.fR¦…4P¹/˜ÐÞ)Î#y`ÝŽw|Œ,87Ä@…㬻×#lgúa|bZ^lW,*–˜m¢˜¢¼ÔFâÜ¢üçV™!fXØÎ«ãü㬓ʪމŽlw1Y|ŽM¤*p3O~§**0¢¡j#YW#™úîjá„”ðÔv{Õ*.¸ý_ühï/ÌQï¿¢dlj¯Hz¼’>øi`7µRºQb•[Jÿ?AIÒS sûÃ-㹟ŽÚ¾{Æ9ˆƒ¸ë™Üh„à`z>n  ¾õ§ qàäímýÞ†wP#ªÈèô‹XC­å6¨çE¨ÐÁæk8tuƒšµñMÉÝPì#±:Öå0´$pŒ¤UTÜ¡ÂIÄÒë§K|žhXÓ‹à^ãò#ÀÈTMô?AocR•k¦Zë‹bhq¶ZR=ÿ_°{y‡ë8ZÁ{¢Å¢Šã°Ö…Öx}E:‰š‘èrŠõ¶l—<e(GŽM—ù–ƒÌ $š¹áYÄœ§Æ›"ÍSãPÒy›ÿü¡kPéÉH9ðkA4C“ñ܆K ,Ÿª@~ñn#É\~”ÕÀß¾Í$«HuÛ“E´.¿¤‡|˜Ú¢Èÿ¾²C1i€L¢ö×ÛuºêízÊó¨ö Ù“d5÷°BIôQWÍÉÕò„¬,D bº?h wbÃ]„‘‘È¥|ÝÅYÚaòŽr¼­X†&$H¨O›pzT»;á»°;b4ìæ.Ìû÷Æ‘c\Û¬bó[‡~¸·S_†1•§mc j;†aV]ÕôØàr/ì·N-{¶~cªÓôwPPÞ„CnƯj_ÑŠI•Ž´À(&ºP½$É ?ÎáM%÷„¤Àš,G¿[¾‘dûT¯šr~Í}è^\„†ôžúìE?èöò-OefbkŸ(@´bΉ›K~®Kü»Â@è³áN;", Ÿ©€E[U,Ã7«U˜-[ÎæMhͶõ¯ïŪ™•ØB2žÂX:ìDAV¤–JëuÓUÿÈE ÔX *ÌAƒ)äš«„´‘J4M õ#0]¤ 5I€Í6KPM`t](v@­ìbHA“IÒ9@­ùé™`›k”äCŒÏÌK –@Û:™@Ui°æ— ¸œ5±»¨49955Ü3:Òo5õ q ê¢)èšéû ˆ¢Ác®!\W`ÝÓ endstream endobj 154 0 obj << /Filter /FlateDecode /Length 3320 >> stream H‰”WM“Û6½Ï¯˜Ê Ü1ÄIÀ{ZÇÙ¬S¶·ÏͳФ$:©P”Çóï·_”(j&qÊe   ûõëׯïo~ü·¹•·÷«)c—¦· ý RëØÞæIÓ„ÝMr»¾ùñ—Oòv}¸Iâ$Q·÷åÍg¡c-œ3â§HŠmq8Dÿ»ÿ•Ì*oÖÄyž[2zÿæF¼yýö§®mërhº6ºÿBÓ2?ÍÅ.Ó¼¹ò{gÖÆÚbóÏâ~Ó¢…ÖJ|múáXléE)QF v2¯Æˆº-‹=ÞÑÂЧ¡Æ‡ÄŠ!ÒbSÃD.Êó)Zæü­Ãz) ?ãÍë(ï?ÝáÍÒ`"ÚÊOhŒ±ï»ÈŠ¯Ø¥©ÆMв¬ÇÃÐQ½]8$¹]ÈX:•ÂpŸñÚb×D)]d¡¤ë¯dÅ Ú]™Dô´;¿·ô…¶W;XQô>NLíèÐX•û ‘â¿ø«¸¯JS±+Úb]ïêƤ–ú¢ÅĢċŸŽ÷‡æeæ·+ã`p§3ÜN%†o·Àõ´¿Þòª¹=¯ÂÂr§27X!ýŠ·-æVøi"•ÁÁü䇎ø¡ÔèÇI?Úû™uOnWI"оÆC*V}'ްB„AÆvÛk·5?×°É[Þð¡á·5Ï¡ÁNÇûÁPâð‰¶CŒù}Íô[Á–x‡ît :ª´–ˆž°`ÿ,LœH9õ'œ“zç´„®†þ#6Nø`œc0" ù‚³h‡SJºMWÁAмV?P“àAÔfJ±|r4caÃ.s™xA§6;‡Œ)àO²ÚÆIj•ŸÿY”ÛÈJU@“öÁ5ŒhyôXÕ¯.÷"7ÆNR–Ð¥œsáRÕ2ìô ªþ+Á2Í2ÇñCVŸÉL;“‡“â”ôóxCœ/‰­&W'³”,ûº| RÂ+Qpæ“'»}Ýrb'Ì©£¤%TñƌۘTRv#H%•Þ£àÊËŠ´rYø%‹~5‡j$¯\œkŠè Ÿ§m꣖;5ú;‰½s )Î G9$æ‚þÒÉ6Îr•ÎãIž½p“Š—º1ŠüÆi•çâÓÈ¢ÊJ¡ùX1eÄô¬´ø¹(7þc…£ätº1ò'ËÅc³ÝâcðØ£TI6¨)7ð æöG_È$Î3kæùBWô±Ùú\DÁ2‰òt`àL¤áê¾®>Æãu|7º¢„JìÜ1?TK"ëú‡ ï¤1%Ù$'2žÚõ~Òh0Vtêk{‡öÒ˜ŽVî ‘+2GîT'á2ÏàÈH'p»y.Ñ}L"ç%(œâx¨ûù1²Džp¡È|Œ;Ú,g¨t|±ÄêëîIQY]~A”˜™ggôa Ž¨š~Ã' ¹©­Wav.Ë¿ŸÏˆµâÌ&é è® …u@½ƒÊ×'\”÷œ°%VF.Q~Tèy"¦”ƒ¦ô~FôÂû§O´è#éŒwØÒxñ‚:硘ó<ÈäÅ’¢‚Ý”Fîóçºp£„ ßrñ¼ :ð ‡B¥‰èV¾Œ”£.› B—›/8ýÇw/JB2–_éƒaÃ`ðÅ¢,ebÛú,f[¦q¢ûþ0ç1ÅXÏàÉœ6Íé…rqšZ;­PTË7Í¡«P®Ról¹Òqîä´\]W*"†ëJ…àuœü(©V]›?S p •Q5A;–Eϲ #ÔÂ(Ùe™-Ok×^61õ¿ß>V±4ò*#‚üãÒIüÁB ›Pô5$@wì¡” ˆá;€ÒiWïºþ)JsqçÑϳËß#¶ðÊåEY'~cÞ£ÑÀÎræÑ)·Ýº)Ñ$¨„$;]£,††ïA§y$¯lêSQ¹ÿ’ˆ2Ž·#Fð-ëºòÒHÏé+%C7Äsr…øÒsò‰\÷‘´üÓEìõ#ÈI¼çöY,8BŸRŠ…çT ÷Kn%Bé“9±$jªÌ}pb‚ üGÞì<Œ´‚éc'‘…I(Η ó-WhPFp¿¢ ólÏr}¥0(õ~«Çí0« 4W:ƒøPKqÖ„{#nU.Ã'@–Ä|kÇ`Œ¹\B`¬ÃC¹ñ‘§ãUPÅdH-‚v)™«ê“ÈÐ&³/Ðü4Ç(g×FçZZ+Ê£uM<^Œã!M»#öG̱†5•…¦º,O†ø%¹rÞ š•k-Õ¤“ Í7·Dâ{jõp+,Ø’'‘[šäYÀkTqÐT µ%®ßO~é’{¿øˆç§¡†ñ}E¦ºQ™mf$^.´*ÚÙ§Æ7Í”Ò(_iÂñ^ ì~_@0wå[ÚÓ\m¡¿ûâÜÿü£ééHs凜GSÎ âvùK=¼mWÝz™<5*žµ kOíµ''ÿ®ŠEåÑ£,Ô:е R]Q–3/Ys,É6ËFŽQѹpЬÍ*µ….1cj„¾]þµ¤#µ8O-‡ØÉ ¢Ùo@T]}ôôømÄ•N“qÞBòbè¢@òjR¯CŒJu~™vAY>Î! %†ŠÌ?°DEDòç9(™÷›q…ú" îÁÐvhxÞ¶Rok‰Ÿ/‘ ÊÒ&sÊUE<ùyˉ¹ÝItTW#ÄÄ«žtù…³3‚Ɉ¹ÅDà4+_È tò9ªU¬d¦ç;œ?S«yœäùKjõŠ˜ ÉÉ31¥pŸ%Ôÿ7ÒÊëGÝú)žz¬ Ù1C’ò¥Î…¥Å1¬ÁòÍIzbÎrb¡ðXÛ¬±×q#s/°+?4 ¤EðJš~¡ÄS²º³fN¥'%¯Ó¹j¤ÚËPíå÷Uûy^þü­¬÷Д©ú Ú¿‘Ž ¨·Àdßz­Ëu¼ÉiͰu’4Q:0,ÕÛzÇÀç%üJâ\«+ª¬ûþÃq7«4¹UsÊ|yÙífÚÊg̽?¬gu±±YúLÆ?òÙu%ؾʡþA`çôåZšù´EµpÀ©ÓéÔ ¾©|óšÔ ¹,ðCÍÙÏ*&cËçZ1òÎPxsk Q7—Н˜ ÝQUÝãÄq"'?Æî™î®®®ö¼>»ð÷¬ nwÏ»^Ý"_øVUÿ|ÓÔH¢ÀñJ¾ì0ï^GGù°Öjy ÑtÈÕÁ fè4Û«|c%6Y´~ ‰lœÝñɆޒhheýÝ0Ʋâyz©²bÍ)3öûE?\„½}Tã¯ú:Ž(±O©sÛæuªeÐLÓB{'6x8g(›=)žyûÀ…üê µl>±Û3ªR!Ž“Ò’XdŠÓx)šäÿ±=sèRåx­‡a ·Ÿ’*TèY!{¾’¦ºÆöô*.ÁÉÐöGÛê!PµòíšÎÿ/ñKÊ‹Y ΄âq¢è{ôp:!êè—}™x‡™j?ülÇ~®èuÂP³¿¥^\Çt"l†7Þ~h&ÇëÈWr· WìßÍ[&½¡ó¿É(ÕOƒVÔ“*Ø­W÷]Rºa®,Êú¾á‹©í®ë•{ݪWÔèþ¤ŠÍ¬0ò8ÙÜ_–ÖPBŠ*¤mÅ$Ÿ–|ãçá\íj/iùz–•à·I^\ùd"“iÃZ{v):‚ãØ´—nmà}ùg·ÌrXÍæÞ'O8ã#Žò9d#‘b$‚;wdÊÂD h’GÇ% =#Ê Ûž‰ZÚ¢¶ž]Ý ÞtI0FITè·:ŸšàË8ÔÎÒÀë ä8r² jñðvá5rW÷çÒ; 3a!”“±)Ò%T’–>›”À˨7˜·"ð«×1ÂÒî J"^Ö~d¢,ý˜(ÔðÃcR±3£îœ€§ J°o’TÅÙfN›Ÿ¾¾û-À¶…' endstream endobj 155 0 obj << /Filter /FlateDecode /Length 3280 >> stream H‰¬WMsÛȽëWè8H™0æp®x½N6eoÅ–¶r|€HH¤C\”ìüú¼îP@ÉvUÊe ˜ôÌt¿~ýúÍåÙËwê\ž_Þžiáôy†áIÚÅüæ,;¿;{ù÷ y~·;ËÒ,Sç—ó3±-w»‡¦]$—_`ÊS&Í3C—oñVáçáL¼ k\X“¥¹–2,š‘=I+¯Ä6™yQ&3-`8‘™hh MfV,’™ÒN\ zYíðf3Ñ-i¾Û•·Õëëä¯ÉçËžÍlê´—ç3™Eaù8ØÈÄÖ‰{ú.+DYÓVß’™,,í¨D‡Ù%=T--±¢l©ÄÝ~SÕ4‡¥×¢­ÈL™„*ü¥Sfž_É,‚©Š†•˜7u]Íidˆ–rM×ÊD•Þ¥/h¥ _µU¹‡¢ådZдtØ?Íü?tìŠwǨ ã/)~I ñ/vFFn€]vÃÕçèOûm[]')wÀÇL¥¦ÐzìM¼¹¸y¿ÚuŸªÝ~Ýí®Ù<j­iš^'ÑTć4©.Ì@¾‡¸É[–A‘‹ÛáUêµQÑê oßüN5ØÁb­¶aí•hn¾Àˆ¨V™˜# û¶E”×Àƒ–@ã¼[%Ê‹{¸¼¢Eì0‡1Ê”L%9dF•=\ꊱéèå<ìÎ8>ްë* ®âRi­_…œ:¸…‚ýãªìGôJ|(¿…oª¡q:ÏÇÆÿãýû‘qçct%V·d°G'Èx üïöôº&:#v=xXIÊådôŸ…ÿÎ8ui‰°[åàÖ&+NÞÚeâm‚œÄnv‹©ÑîbœòÔ(g‡ypHó’¥§Ã)ø¡âlŸ©®i€ (45AòýŠ=Y é.`hÇHá¬$›ÛžG:§3Og@öëèZZ$2n@+÷mFø¸ýQ‡~é¬0J½üËÙŸ^“õ°qṪ˜IA14jsñЖÛ0²¢ËZ)Vu˜)é3ʼn÷Hy$„ŒˆÀ A‡}'~"ïªWØTKðQ AmºÍzÝ<`É*AÝQR+bX£E\1~š:ÑZÜWõªªçœy±+»e³ t…Õ.¸Ãz8ݳ¹Ív½ºý¬t¼!p&škº—¡ñk|#3:5 î¢sƒ|~Äٵؔ¸€0>ÏÅ¢¤È”émBQÊ ¨tŠ¨Ø…«ÛB\ؼ„æùèŽÇîãüæ Ç;š“zImÌ¡°ÐgsÜCì=/6# 5bNQ׺ˆ•izƒâð˜zeוóåµÀ-9óž<3ã¦÷WbÓ„ZDà߸üáHŠ¢µGõ5¬‹+úÌ)Ù@`xf¶ìâ%<ªòax‡ü.DCÅñ[ð… ®ì­5W蜋¥‰ùXh_áYõ…sšž?s¬¤ˆ•j¦SkC­;ö §”øÇªî^©2“S"Æ óCE¦Ôç|f½pHÿº\SòçL\oP­?àòÚÞ]¬:Ú£š9 1ÒÑMt$-ªÊçUpB\pŠÕr…ˆ…¬ÿRùã±WLšV' ‰¶")„Ðñ Úƒ÷z<íl>5Zcš_Üü‰qX§uáÔ±Rxæ{à¦ÆúIÉXÜ\Tõâã¾j¿ ¬9Ä);¬VYâôò-#n$¶‹ ™ùÉao«n¾A¨zAÁΉŞ\S(&ZYxqññ==–h¢BÚkܸ$r %ÊÀŒö'qGÔ³J+–‡i 1y óàrÄ}EŠ…hü.ŽCTƒA›$E¢h†LÜ| óålA3eW37ôFf”Òóþ` Þ$¼é݃øK‰e’J[záÂ|8åãëªìØ#`‚’7Z›Ç#ö7¢»c£Ÿ@  ‘‹‰$m)‚¢:)F/Ë›uõ}-ªS_’÷´5úHVÆúÖVª2uNïÈBŠù²l!v¨ÒKŸAT”›øz-¶ Õ¨¾NÝP´¤W}íA Ä«¶™­«ú®[ö\$qG#Gº¥¹ •9HWŠºÇ]™j’Ò«ŠP‡e` zlµ¦uþxsò:×Cõd¨ÊlZä:fÀ)1æLq”6x§9¤I:Mz Pˆš¶f‡ø}BßÃñ„¯Æmè±ÈNFÒ¡íÔ?ÖU@Ìn"4]£-¥g‹)Ž„»e1æb~8Š^ÐMø‚eJ/Zm¢Ìrp#¸SÑxÖÁuÐÊ4~l¹#la°Ñ(í]ðÆÍ€G%5¹tcZ"ÿŒ£ãÔ$8 ‹;3¥øH’#ö™ú‘>äH‘ki5ý#¡"²KH«V‰#hó%~iÀkÖ=˜&®šž_LÎ §m]Û<¤5ƒ{X.œ“.w!>ÝÓ*Eш)ÿ„%ÄÅÂû± Œ.,Ékô¿ELÉ{7‰ÒbßÅGçÁ·!Ǻ(ÿxœm÷”³ødÁ–Jÿô¶Å)HÞx Ê“,ý$£4‘ÌÄ•MkL„#ZéÉÿÝ®ºjzt¦'kñúó@Ô¡–¦…Ísªî™”ýI,=UîËõþ™ ªc‹Cçòq$¼hcj³²GaB/¬XXÇ|!*¸Ä!AõÄ#|ÆÁ®:E«j'íô”„Q¬sÞùaü–å–`è QÞöÁ"qé='NSµsVô”Pw¡ì„ÅæÐù‚#,ú.–ÀH·!ÞõѾé$šj«Ç^i 1B/c?€cr?uÄ©j•;y+›ŠH€ k}øÁ«84[aO÷³Ï.Ô+â êŸt=íî)-1 êÝjNýšR$ƒxéVÔ+;?®PjÚ ¾:ö>lE¬ã¢«2Vûù¼ª,ð%·° ÁºéÆ2ÉPýÕÇ*‰òàׯP·»Ÿ–GF¬ùqðG.âiéuh_§–ûÔ)ó#êÄæE,`3¬‹ÙV}%Q ÜÍ ¢XÇ`ÍX&ËIÀ58MMÔÁ³ …W¼æê§u“"ò 0àÖ…;†ƒ p¥7± ¢|R°˜HÜÔZ?£p7Íýólö "%*IŠ{Ö Õ\0˜…TC,=Ò"õzÊî'BêseN*NJ„{F2S9Úª\ò4¬}6¿n•ÿ” y]øa^C”¡òu×Ð0ƒ¼v.æµwƒ¼¶nœ×$ƒÚpUˆRíåâI;Ôݾ[UëÅîç ó?Æ«¦7A ˆÞûKð ÙݱI“¦‡ÖÞ¼`ÁÔÁXMÓßy;»|ÖÄ‹a™yó>hÙÙ; cFA×°sAÑâAÐ5Ê2ª²táªÃ7¬•§F‚íÅàñ…7㷹ǒ¾a±ë]ÍM/-ò#–Ûˆ™ƒ/ÛUîÚØž$6¹+1‘:*×åØÜ™2ödw ´{¤ð)'!/KCJ)v«¦ºëçzßláB‡a…ؽgÕóÿ…ÑÞÖaØÑ½™XÖè @…EìO¥œHH(P»5¦/o:¶³âÌoJ¼&Ž÷däC_Á?®lÒ7b Îm£ ?ÚJqÊö¥E«pòƒ¿¢ê€q÷.}5…‹:*JÌ0QïÖ`ï™z$¬†p ûwM¶‘;óºc«\¶¡CÌÞé> stream H‰´WQsܶ~ׯÐ#ØñÑ@‚¤3Œ7©3IÚØÊ“”ŠÄéÎ9‘Wi9ÿ¾ßî‚wö^ü&ǬLjOQÁðÛ7Q©~ü@9`ßÈ ÊOËÆ¾¥T16œyÁJ¬)–èyûæÝ{w²إ¥ytóîö#ŽðœeqÀ@»ÂÐí(Ë­,¿þ€uƒ\Þ¤©ÚÊ@—$+á´ ×;‹‰°¬1å2Dsuœe¶xdà¾ê‰,½&®£÷½þéCäÔ;™¤ÇŸX•Fœ8…«B Û¦êÉl«ƒ“³Lâ]õ¿Ë0çÃíÙ7—$q‘»bž œµÅÿ*²j‡_úO;e©Z÷Ý=ŬDN²™…zO€z¥ê =ü‘­°Ññ6¹ÔðNä§(}FHŒúu‘ȯ,cþR²àæpʧѪ,SõM¤Õ®:,x,ó<.6O›,w±.¤ÚðAWÎ?Ê•ÂÀ«ô‚#{"Qr¢µ£<2 {z&S=)Ñ­ã@ªCÝooOo´:o´Ú„A[ä åï+ñž"ôÆ™HáKÕP aiG3kš¡<†Ë?í¾æÏ™üå¢uç++ùøíÊG[CaÇ{*žÏØ…É’!Ó‰’`Î ¬>±EEü=Õ¸LélZ¨¾ˈW­7t튇o¢'‚¼¯ˆ#¬ lÀøÜQbÐÞÞç15:Ns—-I²ó¼6iû˜ „ôüž¼¯ÅôŠLÈ9ÿÈÊcu¡—ÀcÂ~ŒQdçì÷„ p}fTÙ®kâ kÕ´d?†köJ– qJõ3”Úä;—Húw”»´¦P÷'·ƒz™¢}‘‹žø×·®#ƒ…혿3­n—ß9­Ø¬ µr(XtÇ«¿ÌÙpƒs4›€Q¾SôK ¾CÈ ) 4Jó†ÌBÔSòQ°è–=á tû†zÃÖaªqZm×r±Êî”$Å“Ø}‹v¡fô‚)†ÈY6ŸÅ €¾ÞˆCpp5=°ñ] îäœæÈ› {ÓX"¢ªL¬|!´…Çøœò5iEü)âTƒ þ•àþ˸fûiÛŒÕN$JÓ«~‚½à!ÔDúªR¡|°üZ^›% Ñ=•älÒÞíhEªåØ^6»¥€å¶ûiçÉV²/}%áô=+)\½FvÇŠp¼áœ2FK“âеñ¹yÊ5×?¿¢ÛÆø¦ãoDÓ= $õF5‹Ñ8å뉻qÚˆª»eÕÀßù ôz¡¡aIZº\RžP_Q•M¾¤98;Ã×m'¿M%e/fªp‰“-:æ"™âÞ7šË˜¥çæ²\h GT_ÿJLõؿ׆&M .gQ¾Tæ–´ç Ú3:¨ñ7°!âšÀ@ÄR±&wÜÉH Dwß{ñECÎxµÇ(Ö:Õù3ú˜Óé†EBz“2 ÒS‚8‰óÒ¤áô=þ<\àÄùE¡XÒ9ÅgǃpËèØÐ-u‘*Ñô iR™©Ïòᱹ.gÂM‹³’™ªôèwÌRtJY€Éz!C ‰s]L("œ 1€,Ã5' Z.ôd À45<’ÀE1)˜e[Ù+Íj!ä,‰†Î :ë)a™M ëÀP‰_µ>&‚Qñº¯î=ŠuZhõšf“ )#IµqB:î+Ö‹ ±ÍÜ# ßþu¥õ:×É,š¡‹eÅE5€ÛÔÁ÷{nZýÀúŠÛ°èÆK¯óÞ–×ìv¡€S3êÊ'SsN§^†šifZlœÂ‡ÿ¹!ä>pç«^óˆwTé§pnsÏa÷eˆÜ!“íH€ábËòRÿXš]h[<*e®¡T8’ðž?u\Xè¡”’ÎàìÆž„‹š¡ÌÎιêFíºš‹š›ú W„ î»ÁSP§À†ú0MZ„~ÎöŒJÉ9d²{šg@oâ$×Å£´ï(ÖΩ[é.äìCTrjµøln³\`ž wÔѵ‹ÊƲŠ;é©4æ1Ôé#…è ¡Ÿµ N“!Oº»­¸ ²h‹¨ÔÕÀ‘1¬qÁuí…ì¹aê¸éénéÁî;?¼k×Ý ÿqû‘@o<:gå±@< :p€Ì_‡\rœKŽ ,Mdª=ö>Ò?ÐÓêéšj7NØf·= "ÃXì ъñóáVâØÜ˜YË¢óóe=)©I:ò%õ¯¥ÍçYÍBrðÌ Ç20+PO眣þ¾m‡W È¥fòÈ r¿¼üz܉z"½J¢X3x.‰0 «‡Sšokÿ8¸t~­âAZ5:‡­K§‚Ÿ&…ýcñœù„â¦3V› MÐÀ*0qG Þ D I¦½T, äRªé2À”’‰;©PÝ8’ o´ -€l™’ÂØgò_=‚Ë¿ZxÁÅÆ–é<>(®‡¸ZSs6™; GqÎþ „òØŽ÷·|g—M•keòœ+›ôQT6­”q$3ë®o¢ÆÑ¹@¨mªöÎ7/$ÑO%ÑG"é—gŠB”,"2²Qö¥éÜÉù½@ÙÅà|ý\Š 9?s“Á1kn¢¥ï }ÇšÀÑW⺸îÆÿ7K·éüä6t$2BÇoŃ¡Ù3Vóå¹—A{E!W÷ÏÇ>ØJ€MuÀEîÑÙüIÀ†3!DðÔ}°š l<´žrÿIRÏõëÅŠØ¡à.ÙF®´=ÄúO‰ åt‘‹x¿#£¤ê@7Ü Õäo¿=ªz úa#²ž£šçñ]Iå‡Íy§Pä''ÍÀ\…ãî|ëûjç y8Ò@¨¡iœØìÊÜc•¹ú*ˆ¶#žçmE`±ýnœjm?&M…™¹%þÚÁŒŒ„+¤ ÍÄ@g˜ãà¡>2(ðÄ]{_o)²ÿ¦¼lr„(¼÷$°Ð…öÞ€+‚  C ·wf^±$.Ôuéôç½ò¾éå#/MOw~úÿ¦aoˆâoôgKþÅÿ+ò}ž.K¯½MhTr š,0ldßuªqˆóé…"k’ÿ%{U'Ñ€k”à%x%$-»˜í•;ãUä.0"³[\ÖòZ޼6‚ ”½wfHÑìšRÑx°Û©a= ¨ÌbÞªŽ¹Ð«Œ­˜!Y;‰lϼÚ¶K¹‹¶oÞ Íq?r¼:çên4¯‡ cÍiDvl!åLU¸Ò²!©¨\’z^Ô;µ‡—?fí‰ endstream endobj 157 0 obj << /Filter /FlateDecode /Length 3095 >> stream H‰ÄWÛnãF}÷WóÔ\D4ûÂÛÌÃ"sK²ÈÌc/öÁÎMQ²²)P”=þû=§º©«'ƒ,‚xZd³»êTÕ©Soo.®>f—úòfvQÆef/üçW:-âÌ]æIãýê"¹œ_\ýt­/盋$N{yS_ܪ¾ÙD¹ÚF«–þZ«ø ‰´~ÀoWªªba ÕTõƒ_ÕÝr»j±Ö™Zð_—¨á¡áK§¸[UCÏújÅgÚÈ™Ýv9õßȹ¹î÷á» w¶þ|.ùv-ûjf´êf4°”›~»ù\šèØ$.½¼y£?p&gLŠ‹›°¸KÕÐãru§¢‰“§»G-?¬°V«h’¬€±F 0虯×ü³{ãœ_u|‰MW 1.KŒØ¼5íS?/Úáutóû>n&vFk„-ìsÞ¢ià,mšQªv€“3x´cÛ ŸiUÃ?`ŒçüÈjµÀ²­eã´ æí$Ü #˲LÇÛX9[“¸åebªóߤØZ¤ÁTnÄŸ§ uìOοéV½ûéšøëc¤—ÕýÇå›Ë2œ 3Z–eù’eÃóú;–ýQ ¿•J dB0AhL :«=4â6Dè”ÿÁuúr&³L_(ÞR«• ™—ž}­ŽqÊYÎQ²ã€Lí<¸iL¬S}š:Ÿÿõë¯'žYØ6Á>]x?YD Ì™è\M|€Ll$nº4îÄï­8ö&lÜ!<²ó-ó#SÛO«nÀ‘“<Òª_D6AÈ´á4)îe#-IIZ()óP¡0•¬â“–/g]¿ªx(Ÿtm|Þ.Jk_lH­ûëfxÊúT­×‹v¾¹S³åtƒ¼J‘Wq¼oŽ!3tFÒØc6Ħœ1¥áË…¬ÛŠ—8^‡£²1É@ýnÇl§Ÿ-0üÔø‡yÑF9…"§§Ì §L4ð^ôÆðÔ4|£6Û9]Æ6)Îj+Än ¡o¥À wÐZÀ³Ó©ùHªŒcéöe ëèØ&¹$­PBd„øÖ1ê7ÍÕ¿#0k£oœúºµD Fî÷¸W¸¦™EPc•ˆ„°oŘI)Ѥ”ÊHn:ÐXÈÖôßkRa3Y¡ gpL–áT'œ„ÇM/¿dÍjL3°R´êÃþ‡°cEû:†ƒ†eÚkµ’K ´ºV#É*µ8‚GdkØ-ëQºötÅñð*¼n›fêo_u}¸±%ôàäs-¹¬PˆM¬ghßÔgÏž^*üyœðA¦æMÛôx¡èÀf3PN×sGg 1SªG¡û­dOnvt&\2%m9 -,èq¨°Ç.®eæƒÈÌ•B«[lºyðÍFÓ$ôµ@pó7øKœÅ LjÛ Ï{ô^LIä”$³å‚ÿÖøíX£¶Aù1}ŽtBL0ae[”4ˆB« ò—g~Io9þxâ§BYà}›&Ì"'Jݦ…ÄêNÕcÓ.ÂÙmÍ·yŽÄlÄ›ŽÚÔÊý’!6•úÍÕ×È?í™^U^ÉbQWh’6µÞ’™|…ò‘‡Hf›•þ‚&04;,'L+Þz+nGw/ǺûßéC~Þ§ÁL)¤D\’—¡Àÿ/íâsé(T„¤¿c!Ê(3îõx¹ÿìzÁü¤¢S—;µ×¨÷?5Ã/í¬»cñKK a»gé'g¡³³îRà¹ä/êäÔ $bïc‹GHÔA Ù·Â<Î3§Oë3õgú˜oƒ£a¢“æ…Úýô´mÁ롦;ÎŽlY饖å ]Ý_Ù²úfØömhX¤QÖ»zI!½D…ò‰¸{«¹Ã³Z¤¨.²Ãf÷|ŒåÛnYºãD–{Á,dòA: ‡ ŸãYµXÅE§êî•Ñ(…DüÊs8*x/!·ËádN öçB}$¢tœ—.?ÔŠññ`€þ›:ÿ¦A$¿tO›g3L3Ýó›úÃ$Iþ—DÓí¢ fÝ õKP3½“²:/ö44<‚§…Ë»ÈT ‚½V:Ë,2Nº ¤1 !-â<ÉΪ#¤Ôý³ï!@ ›£ÉA-Ô[Hk|JíòÉXæÓhžÑͳ4/ ’]/]fN¥É/œ&sbùtÁ&¶{.f¿î™qò\ûn=Ôñ©ö~Ao2Ê?W›wÝj-·ýÿê՜իˆ;tËn¾¨«¥±W\-Ðæk 6sÄ¡v?-Ê1‚·û€ukН´ª"(#':Ú½ÈTÆ·A!ØI ƒ&žÇýŠš(¨ÞÜøVî#Õ‡«ÎB;J9çöRÎ%’¨è¤õC3ýû×~#p¾<ßuÛïó¬èÿMi¦˜Æ’⻥i‘ãciZtÃ1÷-Rv,M‹aê´4­M|EòcÂÁm¹¯n[›”æpÅ¥0"Θ5ÞQÑŸ¥¯Ë`zr–ÚÚ¸¸4y——7+N(sÇc̲0GŠôóô.TU†ŸB¾zíüIöȤÆÅæ´2.3+ûU¸7uqÎ{p¼“Ñbœq¬;œq¬ó¢x»^wý8& îùåuª¸¯Dº€+¦'Ï”"¿… ‘Äd+k’½®ZØ¡>Þ}úmûFe/¿xaXq$³¶Ä(–aâ8n9ŸB4š£ÚTL¢…Ê·Ì©Xú~d">¹3Æ™uÏïV¬°…HyŠOÎG„ûÕ‡>ØD]?ÂÍ—L׊Ïçü9ëz0@ÐO_sz´êÇ–§>{ƒv‰n‹_®³iðvS¾ŠqS?›xè°x$BUÿ<Á w ÿ¹‘ótJåû{NQz—dÒû0ì\!ºÒcÐyŒ¿ ©]áçõ‰vuqêŠSéúªö6ý«#’ÅÙN$ ²Ü'zü1r%gWð6MÈ…®dâ;XÔ•4®È¿1H®{?<2:üW³Zm×N~ùðáƒ(.ÄÚÓp¼õéo2ësbtºL`§Ë,XÇ”ñ‰E$3ØØmï÷p"xô¡NŸ#+š~QãC —™3a/–ç4EºˆI9Ç ¥Úù™„òû¹¶ª¼$¶6?›3^-Ú¡™Ÿ†êÔ=šû¬úÜ .êÆ —!’îé;µŒXV¤ ”tûìûéÙ®–Ý(ºï—ؤ¶Ê…­IÝ÷±!!3µMÿ¾çHÒnDÂÌÜÇÜsî=¤Ï=çlj«תûIé>í;ë¥ëÒã¶®um³ÆBë¢5kL­Ýê]7=NÖƒèÜ^4r«­Í6ëüùè[Âm!z¨rXö›ÌšP Ùø(_V@Ù'©¿8 V~ë°°ê¹iHGËDÖ†ÏotüV" 0:ÁqñÔ /šÿA:_ü¡š€ýÀ;¦¼à¶‹» -˜2iÙD3ôWHFI1hU†ƒŸ)>™ÖŽ<ð6Ý0öi2ÇÙxüŽïi`%îÀˆž^ó6KójDoæð''Τ'+J…ÄSõ!ÆDgò `âù¥+´ñ'ßjâ®(Æ®Î3íäÙ| gLc?^*¿&at|Ê?( ‡iWŠ£kbX#áCüKÍ @\çšTû½º¿ ˜Ci«:®PYÁeìÚž'<Œ2˜çP‘V¶ÕÃaùöñð+ÀØOM endstream endobj 158 0 obj << /Filter /FlateDecode /Length 3700 >> stream H‰”W]sÛ¶í3…&OàŠ&~ö­ŽÝF½ùhbåvîÄ÷–([‰Dª”T×ÿþž³©'v<–(X,vÏž=¸œ?e#=š.‚2*3;ŠñçžtRDY1Êã<ÂûuŸoôè~ÄQ'£é,ø¤.ÃR=…c“¦j^/BmTµ_…©ÚaØfjŽ/Uí0Po9bUÕp,±Ç¯Æü\â޵ªñÂ䪽ûÌw3¾ë×ÂzÇשVëj³©iC—ŠSZçÇ Sª®’euGS¥ÚoÃBì7ÜóÞíÏ 4fK[]»é8eþoúK0ÖQRÚl„o'éhz%çÖ<7œ®ÃégDϸèù¹q?ËȬé;Nºž¿.´ã8JŠ‘Î`±ÍÊ4Jñ=[—“àâ·‘.^ñãò×—üš¼íº}L®Fßדà}p9}ž§,‰t&¶$Oêå«?8ß|fM”ÛÄ|ó™[ì›YtFŽ‘±±íƒdÿ>>ÖXuÅL¿¹Á«Õ­z|à¼Ù~k&§P­d}îF¸´úêXùõ³Ši³Z»ÍM% g=¹e«Þ™YÅG¿V\Z´Ýºò©I£¼Ð9S£K#©ù„3LÌTÛ܆L䩺 ¡5¬­úÀmp |òÆ&pÀØlÚPÕE.&&“ç§M-ûÒœF¦Híyž_~üðáúíËÿž„=b›”‡©™Lm»3ÜÄI^žÛ{óîíõ©1SèüÔåYÈx«xÈBN$‰pugꮯ'„`ÆÊÕŒDÑ$QZfæáãÄwí¹§e¦Ï=}Ñì×u·œ½8;z—É3Äݪê¾êá¤=.C¢M+Ûô¨$8Vð¼HTÏÛ½ðF -B“„bž ŒÐµ1(™G%ª×UG.bËá‹gdb›[³³c®_}Ïw1ãfÔdQ§éq¬>©¦êžÂ´à¤GÝ"*¼®‘Ñ,‘GZ'-E·! […®jwõnß9þ"&®3§A)@M*0Æ’ŸÆ–-Á ldzgû®C:Wä?ÔQµÛU³G—†r ¤ 2 ì ó$KiŸ¦ºes†a\F…) FÒ6œß]U»j Õp‹çwwŸÑRXnÝS«(b8­Œ ”ÿÍð¸¨HÎúÒÕE)þ…Û]7ð‡.Kô×݃ƒ¿=ê¤ëK*!žÏ¿GŸÂATx*fÕ®^ 3±sA¸ºAYÖËd¨[¤ç:Ù—ŸÕ‡bòòj^¹ CŠAkÉèøâæ’á ™Ö퀂A®eþ¹¿Hü[¹pÀ:#1ÁŠ\§Ž%ËÌݹ Ä9ç¥jx7³Ç¥: CÜ©£ù]ÔTëz{Z¶[ã¼øjå‚bcþ>± [nX·¸Ÿ|È.pÒWÆÔ%ötooÕr°-yPö_ƒ¹¦4Gçêæýk´"ÒÉ9Ì|3]ÎYË”QHÎ`LôYGά7|³ªfK™rï®FÐ5›Ï½'- Mm&e2ŒR:öÈ,–]è´(³(ËŸå‹èÅ7‹òøÒ:Dˆ|rªc¨ Æ©m ò¾WÄ‹ÌàCeڤǩ’ͯ§ÁïÐI!ZNó;£,F³up9 .~éàâ?.}ɯɛѮÛ×Áäjô]p= Þ—Ó¯C¤…ßYáš]¢^œ$‹¿Mªè亅Jƒ#å7P‹Äÿ»~zl»ùf¿Så¥þë“Xóíþk­°¾MŠþ®DÁmÁ€Ò‰g;¶eóF†Z$,ñ«/®S[æÍ’_צá6/3%ÓÕ=WœW«lÅV:E$|SТWf´X+štž€ƒ§`Ǧh6õ"ÔNЉj#GåZT[-]¦õ;ù¹‹"=²£6”'¢ÐØÌ¸”©Û~qŠ6Ü ò¢ÌÏ!0¥éw’ƒ"²e:”ˆÕ™;ö÷w¡E1îC«©j$PF‘êój÷È péY8ÝhSz›‰^Å!m†kÅÍ·æ3…˜Å1e…Ï%®N;Ø ˆ‡·¹'kŶøa»Ó膄6&©Ìܤj>‡Èl#d¾hKUoåJ"[`ñüy_ úמ°Òœ+µÜ=ñ óÆëËí¡FNK„¬þr,‡ZM“¬Vj¯!/Ô¬±ón*×*ŠÎAâxGEiv(¨Ó£‚B­Eå\Îqâ™É¤Ï t^÷mº[’C¤ AAÂÈû7€i9K®š–Þk34vãD†ˆrM¡Š…paéµÓm¾¿£ØI×NVHoÕÿEÅxkpÓv½r¡Êlç¶®ïë¦îè‚»áŒý™OÆbßÌήm'Ñ´hG¶8/Î#J=‰*š×Až¢L¼T?O•r“7ZéKí½¸*µ`b/½f"Xf ¤ ÒÏ™+|ÎŒ‹AmÙr8=mJú6”{œDU›>×ÀcGàªgLêŽùÔ$qy ÷èäòu2–¦æµµQ1²ÚyÁžv$5²p\âžúD±é¥¡»\M¶Û=GD(äDŽ”6_½fŠ–ëå®"oºÜy¼ƒç]ÕíoJûÊ«e·i Š~‰DM<~³A*„x´•X°rÓZuìÈv@ý{Î9wœ&),XDqÆ“ëñÌ=¯‹ñÏ÷‡r{_¾QØbO×r Ý~»®}g{Mëè\Ÿ½§+ü\&_…:ÎÚj©Â‚YñÉßè;ÿ—”ÊÉÌȶfû¿®Djpº¢Ëý` á=V‚βhÝÊË&s†¸M_3ר(! 5Uj4.ò8ÀcÜI®"F:Þ³h­gmC•^;´’Üq&òÇUµŒô­ä¶L âÁ!r~_±^5Y‰ºµÑ±{&œHL÷¼m熽m´=$!ްi{a¯´Øà”Áµ%h”hÖ•Y>c-ù¢»`v½ùFEùôú´Õâ `’}Ã4.Ÿ…eˆ ¡guÙ6ãÔTÖtâ\J9Mõ–¦xÇêâ|f {ÿ(Ñ–p£-¯p”o5Ïgƒ.ÆñR› «‹¡n‰ŒÃ€&·F¤ LåZߣҊ5´ÍCm |õ.áÍ—3_ÆqâΕwvY—5w)Hâ ýj¥ñì»ÄÁ Ô%NƒÏIýŒ©2uÆæ¾9=ŠHth„[Wû¡™Oå“Çñ3y-Û¶_B.~7J¾brÌÌâ¸<’¦*ž"¶a|SòóÑ&¿4D=ô~çãI¦IæGåE]ˆØÓk@íÊÝðgª™ÕÐì¦ÑüÞ¶ôu× O¼mteUÕ»iö²A^„' o°nýd³ ©•î·~´$iîÚ¦ òv4BȤÄÑjÅÀ3eùf½}W6iq0[¶p -]nž‚‹O`˜=Af2¹‘V¥^ÌÛXÉ%>#…qRêk/5ãÞz^±0=jõÉ^Æwnz˜¯ šF*^íÆðTbPµR£™¨ÇÒ6M[3ã@öåêòí‹¥ ï©wA’¹ô\ñûͺ š®9ë¿<Ìì]x”BÁ£¿ÑûrÆÎ9X]—Pi ^|<Ü™7? 1ä°A¬{g€uïj:3#Ç™jy¤3µ)¥†Q$î(ªR3DÔ0σ$ýϨšE–«˜]…q`òð“¨j‡·†8ÓL]„É*Ȱ¯Yî#í1ˆà¾h o—i,@áüxÞ¼g²JD‰h¸ÛÅ}9šåùŰַûnªÑ®L-èé©·YÒU˜|‹$ȰS Ë8²¢CºÊ\Ãßøüì÷ÔwÖlüz¯/>r> ˜ùøçKÖÍ@ «‹¯jÏ¡å`æä<¯†Î:÷¼ˆ ñ×6[&xº½dt|ÕCy§¦‡T ¦B–K ϰTõÜù€xHQ¸ƒóQP\„+žúäü endstream endobj 159 0 obj << /Filter /FlateDecode /Length 3508 >> stream H‰”WÛrÛÈ|×Wè-ƒ”\“‡-+JRNy“Ý•ªöAÎEl ‚’õ÷é>gQ’7•”Ë€¹kwÏõÝŇ¿¥—ñåÝö¢ «Ü^Fø§O±µayYDEˆáýEtùpñáï·ñåÃñ" £›‹{ó× 7ß‚Ufw˜Ú¡?™ùSðï»`ã\7δJrì{w#+3]9aå.XÅÆ«¤Hñ'ÎÌ7nƒÿöÌR³"ãš]ÝsàTø°JòÌè+KSãO™›5?MÜ2–#†ÃºˆCûC‡_XsÅÖYÓotÒÙÚÍàüÆýÀOYeãıy¤]œ¹™­Ï"³ b3Œâø* «ª²—«8L¢4›Ýök{Fk;ðw„©©7¾ÑÕ47OpuÇw7û_Dæ ÓeÚš?]'«idZÆ}r•Êlu¦›0wÞNÞ\ÿx«!W[&7nœºqëv:ºn+‹èüYQc5-v“erbÝkî¯Äóˆ>ÇU²øœªÏ§~ãÆ7Š#Ä?ÛŒ_¢ÈJ¢“n¯â²b WIRÁA96Á1¥úˆ÷­ŽF×´A&Cü;0H1<ðóžèHR˜ýùq˜‘šþ´w#—4:cSOx©õQcÄâÒÜ $®’a$C•fòö¤VwîÅá%ÉêìžÁÔÜŒNt­|k'·ÑÍ2:ED3ó(Õ–°¢5é˜ö úpúnòmŠêJ++ÕUE6æÁ«³òúx|VvˆM³áà ¯ò{’#rÓÈÛ~êÛ¦æã$† î†y훎mXÕûÞl+,O£uÅH³¶Ò8“~;ÈQ[%f=ø†·U)ƒÏ= úVY´rÍ&ä R'¬´ŸbĸÌß5”U^vIPFÍàýR0*¤Ëcvylº•›§¶`€Ñy‡C·L]%65sœ-®õ¾eç§•TH–˜¯'7>û¥x@.-:³qH7O»¶“¾ÃÞ;A:Á ‹®¯×5qº·<Žð@¨Í–¿lÎÑ£âäfç·Tƒ²Â°[aç±Ã9§>µ¢àD÷è|kщ‰T'æ}™,zqŸõ%+@LÍxT¨°ÚéWÉ´S<>ŠGðâ‘ØéÆ/ái1¡Š^ ýs‹Ò줣K”26Š2+k#Ö‰˜ÄÜ+ÖuÉ<ÀÐf‹º?Í E„ÛÊš+&§ÄÔ§ ³%’hÙä†xó‰Ï%BCÌ=?®—ãœóXÄGtAAÄí³~ÞÍj“d™n+ñ§ç»Çˆö÷0lÚ¡hZÄ^LY™nÔ\|1¤–X\YZ†‰(ÐcÍ zŒëNü=jýÎ~¯?FÖmwdRóØ|d꺣Ìgì€-ú²ŸY¬Š=‹YÔÔè¾rPŽ"z ìhZ1Aí@#(˜Üýñ­™kAjRÝAúªžKÕ´2Ó_±Gäkì÷›WêÛF{…ºcîšÍÒC´\\Xéw|… äþkPVsSj¼”H”5‹Êwm#¨eF{ÜÏÍxO(Í™@›`Kæ\¾žyoÁZ WóûQÖ $064¶(ÞÅ«µ–˜[$¢¼¿zo‘­ƒV O=¶ë³êâ©✺8Ö¬›Åj€î3éû¯bXê¤A΄ ò—›¼®ý3 0³ Ø´ØwöLH ǦÖ5x¦Acñ±´4(6µØ xVÒÈíÂÐô~S=l¤ìÛœ(þm:3MäÂÁ„>›¥Ë>…Å0tÿ7Òþû"ñ²ñÄX‰.Jc ˆ¤"EÚÉ_ ¿µû¶«ÇYu[…ÜЕšçi7ô2FNQ$ñR5 ³2/Fàÿ·éwÄy·ðãî·´)Â4õ¢h%;`¯Pg-à–Õª÷èæ“yýù_Áª2×·þÂ:˜ßÞ ÛwϺ—øÕ¬8‘†×6 ¬#G7Z ø”’u#ÑÐï¤å†×ºz¬ås@åE4F׳|‘„‚›…—K¹î D)ÔǨDèòAH]î.û½Ú(??Q¯!¹ò§Ìµ¥R3ÂVӇʜÓ,n¤ó§8ÑØoÞ—ì½Ñ€Kt+‰å|eô=ù|«[^I.Eë$ïÃÏŻĿÕ2‰’æÕµS´e­dˆÛìž:lÕœ§^eIV’k?ólóø˜#Rñ >ÓDž°¿z@“ +$­æMòApYË ]ïvžlœÂXk~þ¼ªø)á§Ò|üç-ÕlBó'&ü,¡CФLǼ“Ah<]’XÏ=èÓ ÊÛï(Ç·ò[¯ùûÌŸ ÞKü«BÈ•€†é¹+ï{‹wD>l¿ÏÉ,9ŽDøY& Ùâ‡Po*¿•^+pcUpM¬çe SSš¿cºáÍ¡“„¤™òH¤G-P–JD`\ÝiÁ>µ$)~_·½}mÃÿ¢¼ŠB=¹C$ aáRtz!5¡_Eó•”™«B¢ófæËC€Dñ‚cÖ‡l¬{^PEzÙD ï¥î{´ž—ı]. ¸ÄâΩºlŽ´ÑFn¹ |»æ ïµ³þð3gÏ„üÇMÀö,ônª²šuŠ-û yŽð¢ 9ÝÿÆ»*„Ô÷ÞÝ›B Âñ„dÇH¼&;.kd¹gfÏo6³òæß¡ç©q–(¿Ðgi~Ю,wáCxõ†º 8TœÅWJÒlÖŸÛãtSOõº>ºã``ßÎÏÙ,N¬ªÎÅ3~ž.!2Ë¢mžÚß¡e=è®^wîS¿i›ù,àPæïë½Ã±¯b—49{%Ú¯°üµâŽçËžDµÐ¨';H0O½êdäJŠgÜ[¹×Âzb~‘l4ª|…8üa1jé‹(Ì"ÕÕ¯HÛ×ëu+Ä—kòõ(È"Ë×µ\?Ý÷®(HP½'ò—KËÍcºÒò–Ü^7N¹ÇË7AWSe=ÎD1ߺ uÖ|Wu·Q&UÑ…˜<±× r:|=9Avau¡¸r!"‚Çá0¼ßIŽyp=tl§ìÕ¤ÍõÂî‡Óè×2CÉ9û­gí™ý7‹dTù'²ð°×Ëd¨÷ˆO½^(õ8÷ yë$ˆìeR Òþ?tWMoÓ@½ó+rL+Hl¯½±A\€pâ€Ú‘›lHDí§…ϼ7ãԉʡéz½_Þ™yõÆvl£ÙÐÞê Š¤9N²ó§¸ÔŽãÑ`çú‘eîáLz¯Ðû(%žn®kBÒ@$Óséø 8Õ víö†^¥Ú)USMvuoÒ)J†?B’©¼P³@DEi`‹¬Ha„̈M W]Wr1`1IÆ |ü ô8ûø¥¥§Û¬Ô„Àô*ír_N¿›Hèvõ2>½˜øåî¢6Eé:Þ®çí.JZˆ^ËŒ£±Y‡Hƒƒ”Žê¤ÕÙsR1)…(¦'tž:ë¡}9s¹—°$k¦ÎÍÊI–8yš¬š?B‚¢¦ïdÓpŒ'q§¢ÊÌŽÄRåÓ–®%4?Ãyšq®pƒ./ ›¡=> F(iç(QOÎÞ®cÁŸ©ò'&ÑrnT 1`0“Ä´V¬íá!„VÇbÔ ¯Ökâ:þ¶¸xUžÎp”F¤v{£üL™Ò/•Þé¨:_¶r"&Ð×ÅÖ˜oàcÑ6[ÉòÈ4O_L!Þ³&ÛuP™‘úÙ"°‘Š® æ,¾ž—¦(²åêÍ?©¡ÀN endstream endobj 160 0 obj << /Filter /FlateDecode /Length 2522 >> stream H‰ìWÛrÛÈ}×Wè̓*qˆ¹à–7Û´wí²"¯Ä$[%û"!’kPxY­þ>çô ‰v’ª­ÊCÊeÀôLOßNŸ~3>¾OOÍéøö¤ÐEêNcü OÆç:ÍO³8ÓX_ħ³“áOWæt¶9‰u»ÓñääZ}Œ2UF6Q¿GÖàɨWQR¨M4°>U£ryùzSn Yñs¬ÞF¹j꺚puÙ»O^ñˤœU_äðÑsןÏ÷÷÷Qê”þMÎ~ÔMÍ-ÐQ¬&Í*r^v|ø:þFÛØ'§ã‘Øàƒ jÈäZðÃ+$j¾nv³9Þ“<¼C7ooŠX]DNÝUÜ“5ÂKI‰’æ"“ñÂEgaB Zhñ”Èqaóuó ‘–‹®3F̪šòp£®+îâÿ.|ív¦²5Þ7ÑVL¼VŸ£T¼lhêWQKlœ{éæÖê5­»[ʵ5)·íSÃc`´5…»nfërµâR= Ÿ?Ô®"«Ö·‘±ªœðL›íÙt™X=´·ÑÍšb³(‹ŸÙ°¦6Õ>ËáF­—½+’ ·¨¨ßtú‘:jz³ÐwÕz)* Túä 5†ï}(ãµó©ÔAûhœÓùiê2Z€W2áJ—Õm…SèŽU=©6íaÇjÊå:³§©I´“šz2îÚ|¾HÛ%5KbНðÑë?VåúÛ^`ò9œ°˜ÌËjÉÅ\ý#ò^ŠgŠŒÙÑ­ ë§ZW«‡pˆ”ݲâ"<^ÖíÙŸ#ƒÞµ‡QÿŽ5×,xRçž„Fíó»Qñæ0*©9 |wØ ¤ªðGÁêeyò_çê¦i¾õƒ»$iñbx\Îðä Ož„ÇÆD^ oÃ#møqÆ£,ge¹žÒ»`n<¯dŪK8r0ž,‡ãoò% e²×-dOnIú¨‡³ÚDE#ZG ⤪¦ƒöªÀõØ%GÊ®g*E3jnùàzrÊ2Â[™°¡T1\\ã—ï7‘ujÇ/Õ”¢Hç+¾•ü³¿Ï¶õ%ÅœA–¢Ý6Ô±ºÛud.耔Ȩäb)Úˆ‰]¦æo8ˆÏ›»ÃPøòÜ>CÄÇÌt=w<ÇãÉBow÷‹ªÖåD#qÞ6µ4Tä°tSâòèêmÈ1ËW^÷0±rm}’¼”X†Õ¸‹’ˆ¾\ÒDüSÕ5¡ù¨–‹Ñ‰‘,òŽmKª°ÂX’sôï¥Õúrh Äu‚¤W’ɨWŒ*_Ìø©Ü6üYJ:ª6“r½­Èyb´nƨæ:ó¡È¡ß ‘–fÀŒTí¸.BLìƒ|6©6>ÞóYǰBbÃΡ (¨Ë)ð<’í»ËäÚ¥yþävbú8zó6(ƒ‹x…D]ÝU_PçϦ†+vÖû9/]!‘vu°æ\plÝЉü3x̉ØdÏP¶-¥m…ä÷z"ŽÀ~ ³B0¸½þæµI’~ëÀé·ò÷Rovµô´Qs_/›rêÊu¹éƒ:äû©ì´u>?ÖÇò¶#TW#T‚3,Lös³7ëÇ&1§ d,ÀâkTÉâH–R®ª–$žS@¢$‰ –¨EÙž;zÚÊR\Ü-A2œ’rÄw©, q—+nÉžµK ‘OÑÇšï0Â6a¦aÒ„ÎnØ´Š¿ìùà8ý†›è¬pÙ1|bã]HCµ¹ vÀ<&t¤e2»l‰N tOƒîÉÖÉžEÊ/«-ßðÊ`$8‡.)Hg Û¶F>±3š Á#¿Á±mJ¶íu”66„gíY;s¼{bÝfö{SÌË]³’1QŽøðØ5㘯ßíš?žjZä Í ’H ÙÂì騛ÏSß/´pÇ v£ƒKèÌZ{lÖØc„^ç(Æc$Ãq¢QïÖ³&_o½5H–Þñxã‰pN0W^ÆófUndGª„–pYj&"’`˜#•°©Uï0EN§aPà@Ö¥œ’=Rv°ÙG¢/j=…ÿ)W¦˜°ƒ)¼ ÐfÕ-3ö>2…וðc@/ß䯶0Š2sJ“ØÌ‡­O_ÙBl^<ó rE8³ÙÕ2v¥h/}D’ÿ¤ÌRþÿ³Ô³YêYæÿoÌR/DéÏš¥^Æ:ÛbÝOU#öÎHrAL.¡¤ª„nô°îq(jÒñt€„c…>Ü0è³udQ»‚ (ì c ÒÚâpwËŠó®ƒ@ê#xd¯9ÉPj#YÌÓåÕe;yÁ«‚<‰þè&òø®Kä±9B=@„G>§õYÂ+eÊ7@ )LÆíÊX¦Þ»ñÉ¿x;%p endstream endobj 161 0 obj << /Filter /FlateDecode /Length 138 >> stream H‰21R0P0U0S0"s…C®B.cC ˜2ÕaK…ä\.'O.ýp —¾˜t pVRž¾ %E¥©\ž. ÿðÿÿÏÀøÿÃÿ öä00ð```áff```$„‘ÕÃÌ™2d>È} {¹\=¹¹ áê*zendstream endobj 162 0 obj << /Filter /FlateDecode /Length 901 >> stream H‰äTÁ’Û6 ½ë+|g"š HJÊ­»Þv’i;]§=ìæ •¹²Òµ¤‘å8ýû¤íØN&ÐŽÇ$D€øð€›e2ÿÙÍp¶|IJYºl¦è%Ì2YÌr•KRo5k’ù/8k¶‰’JÙÙ²Ná³"5Â@R¤ÖXðž;¸ç³V8^iñ-üÃ9TÝŠk£ÉÁü7‘Á77EŠpvÛ–l‚YŽðÓܲU]M©ï¶äÁð‘8m%ÔäûhíIîø›æ *þ>ä³eП"ø‘¿¥ø¸|Ÿh‰®ÀYŠR+CÏ_$ð®ËOa!DiÊÌ‚¤cŒ²ˆÑ£ Ç}íýªíŠéŒ é9zÌ´ö$8„…ÐÐnEÓHKû,4Ânò+ÖZx˜ª)jÛºzWoE½H3Ø »‰<óiZ)ä†-Øåß=¬û!¼çTùLI[šcÞœ3-ûÞÄÇéh•fZª¢Ð –Ú©ã#×Ó4¼Ï÷û½¬[9íö­ïdUËjšßöÝ‹jð]í·,Ì·)ó4rÊ)éBjcíW(]Œò†Jos«’MÏêrÆÏ?jÞu•Hµvð¡kE¦à¬¾¬g:75i¸4Ú(XŠÜ€¯×]ÏÄé›ùbÔʲ´'à¸!|0¼„Æpp3¶UÇsª1‘Y²lˆ—”ØÀv¯žÉNÞ ë2«áöíXÓÄk̨¦ê9ì[‚òÌaßNëhp/ð‰XJ•—'ø´=Àwÿ»ÐD5O«ƒ}·W\ 1ûŠ»=á®-rþO€Oâ-!‚Åá©¥DxOH†NÚUãÉó2{JUœ#Æ`Ù’æ.EGI-ȧÇåQà_ ¤~ØxêVÒKœ/¡=åš+DæÕæêùË:eâ+£o2\aNT!Xï¨#6C?’O>žÓÿŽºðËñèDIð8ëªÖuƒ ÷ÿm1RûO¾žd?6W¡Œ4FüÚ^€ŠN:êñ žÏfw˜Í‹]W3 q%²ZðÔˆc55D¼_«®á¹ªhrÞmžýjÅMÁ3Åd4}h#¼Â‰y˜*@[³@ÝM¾m°Í®j˜¦Æ”§éj¨{|'ÈÝgv4ö]¨«ƒïØã„ùÏŽØLדç0]‰ÿ6§`©¡F./Ò̹»eò¯ 1­ endstream endobj 163 0 obj << /Type /XRef /Length 94 /Filter /FlateDecode /DecodeParms << /Columns 4 /Predictor 12 >> /W [ 1 2 1 ] /Info 2 0 R /Root 4 0 R /Size 164 /ID [<12dcc3843ccf2a793e18968594e6c27e><4091cc7ab604670f55782aed66fe1a56>] >> stream xœcb&F~ñ‰ Èc%hOüçIßÁÄÀ¶ìïœFƒnÁ.±윑Àç="ªw*àůàY"ÿ>Ä? Á¥$/ æs Ô endstream endobj startxref 42214 %%EOF RPostgreSQL/inst/TODO0000644000176000001440000000115612124512710014072 0ustar ripleyusersThings yet to be completed: 1. Array and other complex structures are not converted properly: just the strings are transmitted. Datatype conversion callback table for supporting complex data types are desired. 2. Add commands for prepared statements. This is partly done. But not thoroughly tested yet. 3. More explicit encoding support. 4. 'Scale' is not calculated in dbGetInfo(result_set) Try to write an SQL query to get the value or hardcode the appropriate details in the code.For more details refer to : "RS_PostgreSQL_createDataMappings". 5. Check the working of DBI extension "dbApply". RPostgreSQL/inst/NEWS0000644000176000001440000001027212124512710014100 0ustar ripleyusersVersion 0.4 -- 2013-03-27 o Initial implementation of prepared statement o Use system libpq library when available on OS X (darwin) o Force ISO datestyle for PostgreSQL-R communication by default o Time zone aware Timestamp POSIXct conversion Version 0.3-3 -- 2012-10-05 o Bugfix on dbColumnInfo and others reproducible by gctorture(TRUE) o Do not implicitly make new connections, which interfere with transaction. o Change the notation of the LICENSE Version 0.3-2 -- 2012-01-10 o Adapt to the new windows toolchain. o Do not make libpq.dll on windows but just make libpq.a and link it, so that libpq.dll need not copied anymore. Version 0.3-1 -- 2011-12-31 o Remove GNU make dependency. Version 0.3-0 -- 2011-12-29 o The bundled libpq source codes are used under darwin as well. o More compatibility to other database drivers under DBI and sqldf. dbBeginTransaction, safe.write, make.db.names are removed. dbBuildTableDefinition is renamed to postgresqlBuildTableDefinition. isIdCurrent is renamed to isPostgresqlIdCurrent. row.names is now integer. Version 0.2-1 -- 2011-11-16 o libpq source codes are bundled for Windows. In other envirionment, this code is not used and existence of libpq as specified by PG_HOME is still required. Version 0.2-0 -- 2011-10-04 o Error check for dbWriteTable o dbWriteTable does not write a temporary file. Control characters in strings are properly escaped for dbWriteTable. o Remove warning for enum and arrays etc. The value are still transferred as string and not converted to arrays etc. o use c('schema', 'table') to specify schema o Integer is mapped to integer in postgresql rather than bigint. Version 0.1-7 -- 2010-10-17 o Several potential buffer overruns were fixed o dbWriteTable now writes a data.frame to database through a network connection rather than a temporary file. Note that row_names may be changed in future releases. Also, passing in filenames instead of data.frame is not supported at this time. o When no host is specified, a connection to the PostgreSQL server is made via UNIX domain socket (just like psql does) o Table and column names are case sensitive, and identifiers are escaped or quoted appropriately, so that any form of table/column names can be created, searched, or removed, including upper-, lower- and mixed-case. o nullOk in dbColumnInfo has a return value of NA when the column does not correspond to a column in the table. The utility of nullOk is doubtful but not removed at this time. o Correct Windows getpid() declaration (with thanks to Brian D. Ripley) o A call of as.POSIXct() with a time format string wrongly passed to TZ has been corrected; this should help with intra-day timestamps (with thanks to Steve Eick) o Usage of tmpdir has been improved on similarly to Linux (with thanks to Robert McGehee) Version 0.1-6 -- 2009-10-19 o Added missing paste() call to dbGetQuery() for dbListTables Version 0.1-5 -- 2009-10-13 o Four issues reported at the Issue tracker at the Google Code site are addressed, two more are feature requests and one cannot be replicated o A number of other small fixes and enhancements to code and documentation as detailed in the ChangeLog file Version 0.1-4 -- 2009-01-26 o Fix to one of the documentation files Version 0.1-3 -- 2008-12-12 o Fixed a memory leak detected by Valgrind with thanks to Jeff Horner who applied a similar fix to RMySQL Version 0.1-2 -- 2008-11-02 o Some fixes to the regression tests and configuration Version 0.1-1 -- 2008-10-28 o DESCRIPTION: Correct Url: field by adding http:// parts. Thanks to Gabor for the hint. Version 0.1-0 -- 2008-10-21 o First Release o This 'RPostgreSQL' package was developed as a part of Google Summer of Code 2008 program. o Its implements all the features in the DBI (and a few extra like those related to transaction management) RPostgreSQL/inst/ANNOUNCEMENT0000644000176000001440000000174712124512710015225 0ustar ripleyusers RPostgreSQL version 0.4 We are pround to announce the availability of the RPostgreSQL package on CRAN and its mirrors. This package provides an a DBI-compliant interface between PostgreSQL and R. RPostgreSQL was developed as part of the Google Summer of Code 2008 program by Sameer Kumar Prayaga . Some highlights: o Initial support for prepared statement. Known bugs/deficiencies: o Arrays are not converted vector or other datastructure. o Active issue list is at http://code.google.com/p/rpostgresql/issues/list RPostgreSQL is hosted on Google Code, for more information see http://rpostgresql.googlecode.com/ For any suggestions and queries, please contact: rpostgresql-dev@googlegroups.com For security issues that should not directly go to public, you may contact: Tomoaki Nishiyama Neil Tiffin Joe Conway Dirk Eddelbuettel RPostgreSQL/configure0000755000176000001440000034403612124512710014343 0ustar ripleyusers#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.63 for RPostgreSQL 0.2. # # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, # 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## --------------------- ## ## M4sh Initialization. ## ## --------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in *posix*) set -o posix ;; esac fi # PATH needs CR # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo if (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # Support unset when possible. if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then as_unset=unset else as_unset=false fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. case $0 in *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 { (exit 1); exit 1; } fi # Work around bugs in pre-3.0 UWIN ksh. for as_var in ENV MAIL MAILPATH do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # Required to use basename. if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi # Name of the executable. as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # CDPATH. $as_unset CDPATH if test "x$CONFIG_SHELL" = x; then if (eval ":") 2>/dev/null; then as_have_required=yes else as_have_required=no fi if test $as_have_required = yes && (eval ": (as_func_return () { (exit \$1) } as_func_success () { as_func_return 0 } as_func_failure () { as_func_return 1 } as_func_ret_success () { return 0 } as_func_ret_failure () { return 1 } exitcode=0 if as_func_success; then : else exitcode=1 echo as_func_success failed. fi if as_func_failure; then exitcode=1 echo as_func_failure succeeded. fi if as_func_ret_success; then : else exitcode=1 echo as_func_ret_success failed. fi if as_func_ret_failure; then exitcode=1 echo as_func_ret_failure succeeded. fi if ( set x; as_func_ret_success y && test x = \"\$1\" ); then : else exitcode=1 echo positional parameters were not saved. fi test \$exitcode = 0) || { (exit 1); exit 1; } ( as_lineno_1=\$LINENO as_lineno_2=\$LINENO test \"x\$as_lineno_1\" != \"x\$as_lineno_2\" && test \"x\`expr \$as_lineno_1 + 1\`\" = \"x\$as_lineno_2\") || { (exit 1); exit 1; } ") 2> /dev/null; then : else as_candidate_shells= as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. case $as_dir in /*) for as_base in sh bash ksh sh5; do as_candidate_shells="$as_candidate_shells $as_dir/$as_base" done;; esac done IFS=$as_save_IFS for as_shell in $as_candidate_shells $SHELL; do # Try only shells that exist, to save several forks. if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { ("$as_shell") 2> /dev/null <<\_ASEOF if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in *posix*) set -o posix ;; esac fi : _ASEOF }; then CONFIG_SHELL=$as_shell as_have_required=yes if { "$as_shell" 2> /dev/null <<\_ASEOF if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in *posix*) set -o posix ;; esac fi : (as_func_return () { (exit $1) } as_func_success () { as_func_return 0 } as_func_failure () { as_func_return 1 } as_func_ret_success () { return 0 } as_func_ret_failure () { return 1 } exitcode=0 if as_func_success; then : else exitcode=1 echo as_func_success failed. fi if as_func_failure; then exitcode=1 echo as_func_failure succeeded. fi if as_func_ret_success; then : else exitcode=1 echo as_func_ret_success failed. fi if as_func_ret_failure; then exitcode=1 echo as_func_ret_failure succeeded. fi if ( set x; as_func_ret_success y && test x = "$1" ); then : else exitcode=1 echo positional parameters were not saved. fi test $exitcode = 0) || { (exit 1); exit 1; } ( as_lineno_1=$LINENO as_lineno_2=$LINENO test "x$as_lineno_1" != "x$as_lineno_2" && test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2") || { (exit 1); exit 1; } _ASEOF }; then break fi fi done if test "x$CONFIG_SHELL" != x; then for as_var in BASH_ENV ENV do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var done export CONFIG_SHELL exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} fi if test $as_have_required = no; then echo This script requires a shell more modern than all the echo shells that I found on your system. Please install a echo modern shell, or manually run the script under such a echo shell if you do have one. { (exit 1); exit 1; } fi fi fi (eval "as_func_return () { (exit \$1) } as_func_success () { as_func_return 0 } as_func_failure () { as_func_return 1 } as_func_ret_success () { return 0 } as_func_ret_failure () { return 1 } exitcode=0 if as_func_success; then : else exitcode=1 echo as_func_success failed. fi if as_func_failure; then exitcode=1 echo as_func_failure succeeded. fi if as_func_ret_success; then : else exitcode=1 echo as_func_ret_success failed. fi if as_func_ret_failure; then exitcode=1 echo as_func_ret_failure succeeded. fi if ( set x; as_func_ret_success y && test x = \"\$1\" ); then : else exitcode=1 echo positional parameters were not saved. fi test \$exitcode = 0") || { echo No shell found that supports shell functions. echo Please tell bug-autoconf@gnu.org about your system, echo including any error possibly output before this message. echo This can help us improve future autoconf versions. echo Configuration will now proceed without shell functions. } as_lineno_1=$LINENO as_lineno_2=$LINENO test "x$as_lineno_1" != "x$as_lineno_2" && test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { # Create $as_me.lineno as a copy of $as_myself, but with $LINENO # uniformly replaced by the line number. The first 'sed' inserts a # line-number line after each line using $LINENO; the second 'sed' # does the real work. The second script uses 'N' to pair each # line-number line with the line containing $LINENO, and appends # trailing '-' during substitution so that $LINENO is not a special # case at line end. # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the # scripts with optimization help from Paolo Bonzini. Blame Lee # E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 { (exit 1); exit 1; }; } # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in -n*) case `echo 'x\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. *) ECHO_C='\c';; esac;; *) ECHO_N='-n';; esac if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -p'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -p' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p=: else test -d ./-p && rmdir ./-p as_mkdir_p=false fi if test -x / >/dev/null 2>&1; then as_test_x='test -x' else if ls -dL / >/dev/null 2>&1; then as_ls_L_option=L else as_ls_L_option= fi as_test_x=' eval sh -c '\'' if test -d "$1"; then test -d "$1/."; else case $1 in -*)set "./$1";; esac; case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in ???[sx]*):;;*)false;;esac;fi '\'' sh ' fi as_executable_p=$as_test_x # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= SHELL=${CONFIG_SHELL-/bin/sh} # Identity of this package. PACKAGE_NAME='RPostgreSQL' PACKAGE_TARNAME='rpostgresql' PACKAGE_VERSION='0.2' PACKAGE_STRING='RPostgreSQL 0.2' PACKAGE_BUGREPORT='' ac_subst_vars='LTLIBOBJS LIBOBJS ENABLE_LIBPQ PKG_LIBS PKG_CPPFLAGS R_OS_TYPE PG_CONFIG target_os target_vendor target_cpu target host_os host_vendor host_cpu host build_os build_vendor build_cpu build OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && { $as_echo "$as_me: error: invalid feature name: $ac_useropt" >&2 { (exit 1); exit 1; }; } ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && { $as_echo "$as_me: error: invalid feature name: $ac_useropt" >&2 { (exit 1); exit 1; }; } ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && { $as_echo "$as_me: error: invalid package name: $ac_useropt" >&2 { (exit 1); exit 1; }; } ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && { $as_echo "$as_me: error: invalid package name: $ac_useropt" >&2 { (exit 1); exit 1; }; } ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) { $as_echo "$as_me: error: unrecognized option: $ac_option Try \`$0 --help' for more information." >&2 { (exit 1); exit 1; }; } ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && { $as_echo "$as_me: error: invalid variable name: $ac_envvar" >&2 { (exit 1); exit 1; }; } eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` { $as_echo "$as_me: error: missing argument to $ac_option" >&2 { (exit 1); exit 1; }; } fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) { $as_echo "$as_me: error: unrecognized options: $ac_unrecognized_opts" >&2 { (exit 1); exit 1; }; } ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac { $as_echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 { (exit 1); exit 1; }; } done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe $as_echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. If a cross compiler is detected then cross compile mode will be used." >&2 elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || { $as_echo "$as_me: error: working directory cannot be determined" >&2 { (exit 1); exit 1; }; } test "X$ac_ls_di" = "X$ac_pwd_ls_di" || { $as_echo "$as_me: error: pwd does not report name of working directory" >&2 { (exit 1); exit 1; }; } # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." { $as_echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 { (exit 1); exit 1; }; } fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || { $as_echo "$as_me: error: $ac_msg" >&2 { (exit 1); exit 1; }; } pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures RPostgreSQL 0.2 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/rpostgresql] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] --target=TARGET configure for building compilers for TARGET [HOST] _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of RPostgreSQL 0.2:";; esac cat <<\_ACEOF Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS C/C++/Objective C preprocessor flags, e.g. -I if you have headers in a nonstandard directory Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF RPostgreSQL configure 0.2 generated by GNU Autoconf 2.63 Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by RPostgreSQL $as_me 0.2, which was generated by GNU Autoconf 2.63. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; 2) ac_configure_args1="$ac_configure_args1 '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi ac_configure_args="$ac_configure_args '$ac_arg'" ;; esac done done $as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } $as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo cat <<\_ASBOX ## ---------------- ## ## Cache variables. ## ## ---------------- ## _ASBOX echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:$LINENO: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) $as_unset $ac_var ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo cat <<\_ASBOX ## ----------------- ## ## Output variables. ## ## ----------------- ## _ASBOX echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then cat <<\_ASBOX ## ------------------- ## ## File substitutions. ## ## ------------------- ## _ASBOX echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then cat <<\_ASBOX ## ----------- ## ## confdefs.h. ## ## ----------- ## _ASBOX echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then ac_site_file1=$CONFIG_SITE elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test -r "$ac_site_file"; then { $as_echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special # files actually), so we avoid doing that. if test -f "$cache_file"; then { $as_echo "$as_me:$LINENO: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:$LINENO: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:$LINENO: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:$LINENO: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:$LINENO: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} { { $as_echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 $as_echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} { (exit 1); exit 1; }; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # Checks for common programs using default macros ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CC+set}" = set; then $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:$LINENO: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:$LINENO: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_CC+set}" = set; then $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:$LINENO: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CC+set}" = set; then $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:$LINENO: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:$LINENO: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CC+set}" = set; then $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:$LINENO: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:$LINENO: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CC+set}" = set; then $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:$LINENO: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:$LINENO: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_CC+set}" = set; then $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:$LINENO: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { { $as_echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH See \`config.log' for more details." >&5 $as_echo "$as_me: error: no acceptable C compiler found in \$PATH See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; }; } # Provide some information about the compiler. $as_echo "$as_me:$LINENO: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 { (ac_try="$ac_compiler --version >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compiler --version >&5") 2>&5 ac_status=$? $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } { (ac_try="$ac_compiler -v >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compiler -v >&5") 2>&5 ac_status=$? $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } { (ac_try="$ac_compiler -V >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compiler -V >&5") 2>&5 ac_status=$? $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:$LINENO: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { (ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi { $as_echo "$as_me:$LINENO: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } if test -z "$ac_file"; then $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { { $as_echo "$as_me:$LINENO: error: C compiler cannot create executables See \`config.log' for more details." >&5 $as_echo "$as_me: error: C compiler cannot create executables See \`config.log' for more details." >&2;} { (exit 77); exit 77; }; }; } fi ac_exeext=$ac_cv_exeext # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:$LINENO: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } # FIXME: These cross compiler hacks should be removed for Autoconf 3.0 # If not cross compiling, check that we can run a simple program. if test "$cross_compiling" != yes; then if { ac_try='./$ac_file' { (case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { { $as_echo "$as_me:$LINENO: error: cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details." >&5 $as_echo "$as_me: error: cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; }; } fi fi fi { $as_echo "$as_me:$LINENO: result: yes" >&5 $as_echo "yes" >&6; } rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } { $as_echo "$as_me:$LINENO: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } { $as_echo "$as_me:$LINENO: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { { $as_echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link See \`config.log' for more details." >&5 $as_echo "$as_me: error: cannot compute suffix of executables: cannot compile and link See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; }; } fi rm -f conftest$ac_cv_exeext { $as_echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT { $as_echo "$as_me:$LINENO: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if test "${ac_cv_objext+set}" = set; then $as_echo_n "(cached) " >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { { $as_echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile See \`config.log' for more details." >&5 $as_echo "$as_me: error: cannot compute suffix of object files: cannot compile See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; }; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if test "${ac_cv_c_compiler_gnu+set}" = set; then $as_echo_n "(cached) " >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_compiler_gnu=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if test "${ac_cv_prog_cc_g+set}" = set; then $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_prog_cc_g=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 CFLAGS="" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_prog_cc_g=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:$LINENO: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if test "${ac_cv_prog_cc_c89+set}" = set; then $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include #include #include /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_prog_cc_c89=$ac_arg else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:$LINENO: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:$LINENO: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:$LINENO: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then { { $as_echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&5 $as_echo "$as_me: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&2;} { (exit 1); exit 1; }; } fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # Make sure we can run config.sub. $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || { { $as_echo "$as_me:$LINENO: error: cannot run $SHELL $ac_aux_dir/config.sub" >&5 $as_echo "$as_me: error: cannot run $SHELL $ac_aux_dir/config.sub" >&2;} { (exit 1); exit 1; }; } { $as_echo "$as_me:$LINENO: checking build system type" >&5 $as_echo_n "checking build system type... " >&6; } if test "${ac_cv_build+set}" = set; then $as_echo_n "(cached) " >&6 else ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` test "x$ac_build_alias" = x && { { $as_echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5 $as_echo "$as_me: error: cannot guess build type; you must specify one" >&2;} { (exit 1); exit 1; }; } ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || { { $as_echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&5 $as_echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&2;} { (exit 1); exit 1; }; } fi { $as_echo "$as_me:$LINENO: result: $ac_cv_build" >&5 $as_echo "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) { { $as_echo "$as_me:$LINENO: error: invalid value of canonical build" >&5 $as_echo "$as_me: error: invalid value of canonical build" >&2;} { (exit 1); exit 1; }; };; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' set x $ac_cv_build shift build_cpu=$1 build_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: build_os=$* IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:$LINENO: checking host system type" >&5 $as_echo_n "checking host system type... " >&6; } if test "${ac_cv_host+set}" = set; then $as_echo_n "(cached) " >&6 else if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || { { $as_echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&5 $as_echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&2;} { (exit 1); exit 1; }; } fi fi { $as_echo "$as_me:$LINENO: result: $ac_cv_host" >&5 $as_echo "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) { { $as_echo "$as_me:$LINENO: error: invalid value of canonical host" >&5 $as_echo "$as_me: error: invalid value of canonical host" >&2;} { (exit 1); exit 1; }; };; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' set x $ac_cv_host shift host_cpu=$1 host_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: host_os=$* IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:$LINENO: checking target system type" >&5 $as_echo_n "checking target system type... " >&6; } if test "${ac_cv_target+set}" = set; then $as_echo_n "(cached) " >&6 else if test "x$target_alias" = x; then ac_cv_target=$ac_cv_host else ac_cv_target=`$SHELL "$ac_aux_dir/config.sub" $target_alias` || { { $as_echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $target_alias failed" >&5 $as_echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $target_alias failed" >&2;} { (exit 1); exit 1; }; } fi fi { $as_echo "$as_me:$LINENO: result: $ac_cv_target" >&5 $as_echo "$ac_cv_target" >&6; } case $ac_cv_target in *-*-*) ;; *) { { $as_echo "$as_me:$LINENO: error: invalid value of canonical target" >&5 $as_echo "$as_me: error: invalid value of canonical target" >&2;} { (exit 1); exit 1; }; };; esac target=$ac_cv_target ac_save_IFS=$IFS; IFS='-' set x $ac_cv_target shift target_cpu=$1 target_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: target_os=$* IFS=$ac_save_IFS case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac # The aliases save the names the user supplied, while $host etc. # will get canonicalized. test -n "$target_alias" && test "$program_prefix$program_suffix$program_transform_name" = \ NONENONEs,x,x, && program_prefix=${target_alias}- case "${host_os}" in darwin*) R_OS_TYPE="darwin" ;; esac # Check for non-standard programs: pg_config(1) to configure PostgreSQL builds # Extract the first word of "pg_config", so it can be a program name with args. set dummy pg_config; ac_word=$2 { $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_PG_CONFIG+set}" = set; then $as_echo_n "(cached) " >&6 else case $PG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_PG_CONFIG="$PG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_PG_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi PG_CONFIG=$ac_cv_path_PG_CONFIG if test -n "$PG_CONFIG"; then { $as_echo "$as_me:$LINENO: result: $PG_CONFIG" >&5 $as_echo "$PG_CONFIG" >&6; } else { $as_echo "$as_me:$LINENO: result: no" >&5 $as_echo "no" >&6; } fi # By default, we will not use the accompanied libpq ENABLE_LIBPQ= # If pg_config was found, let's use it if test "${PG_CONFIG}" != ""; then # Use pg_config for header and linker arguments PG_INCDIR=`${PG_CONFIG} --includedir` PG_LIBDIR=`${PG_CONFIG} --libdir` else # let's look around -- code copied from RdbuiPgSQL but modified to use test -f # added fink standard install location Neil 8/30/2009 { $as_echo "$as_me:$LINENO: checking for PostgreSQL header files" >&5 $as_echo "$as_me: checking for PostgreSQL header files" >&6;} if ! test $PG_INCDIR then for dir in \ /usr/include \ /usr/include/pgsql \ /usr/include/postgresql \ /usr/local/include \ /usr/local/include/pgsql \ /usr/local/include/postgresql \ /usr/local/pgsql/include \ /usr/local/postgresql/include \ /opt/include \ /opt/include/pgsql \ /opt/include/postgresql \ /opt/local/include \ /opt/local/include/postgresql \ /opt/local/include/postgresql84 \ /sw/opt/postgresql-8.4/include \ /Library/PostgresPlus/8.4SS/include \ /sw/include/postgresql do { $as_echo "$as_me:$LINENO: Checking include ${dir}." >&5 $as_echo "$as_me: Checking include ${dir}." >&6;} if test -f ${dir}/libpq-fe.h then PG_INCDIR=${dir} break fi done fi # likewise, let's look around for libpq.so if ! test $PG_LIBDIR then for dir in \ /usr/lib \ /usr/lib/pgsql \ /usr/lib/postgresql \ /usr/local/lib \ /usr/local/lib/pgsql \ /usr/local/lib/postgresql \ /usr/local/pgsql/lib \ /usr/local/postgresql/lib \ /opt/lib \ /opt/lib/pgsql \ /opt/lib/postgresql \ /opt/local/lib \ /opt/local/lib/postgresql \ /opt/local/lib/postgresql84 \ /sw/opt/postgresql-8.4/lib \ /Library/PostgresPlus/8.4SS/lib \ /sw/lib do { $as_echo "$as_me:$LINENO: Checking lib ${dir}." >&5 $as_echo "$as_me: Checking lib ${dir}." >&6;} if test -f ${dir}/libpq.so then PG_LIBDIR=${dir} break fi if test -f ${dir}/libpq.dylib then PG_LIBDIR=${dir} break fi done fi if ! test $PG_LIBDIR then if test "$R_OS_TYPE" = "darwin" ; then # in case we cannot find any libpq library we will use the accompanied libpq # This content would be written into src/Makevars at the end of this script ENABLE_LIBPQ=' PKG_CPPFLAGS=-Ilibpq PKG_LIBS=libpq/libpq.a .PHONY: all all: $(SHLIB) $(SHLIB): libpq/libpq.5.dylib libpq/libpq.5.dylib: (cd libpq; $(MAKE) CC="$(CC)" CFLAGS="$(CFLAGS)" -f Makefile.darwin) clean: (cd libpq; $(MAKE) -f Makefile.darwin clean) ' fi fi fi # Expand into arguments PKG_CPPFLAGS="-I${PG_INCDIR}" PKG_LIBS="-L${PG_LIBDIR} -lpq" # Test for sanity by looking for libpq-fe.h, no explicit action on found, error on failure as_ac_File=`$as_echo "ac_cv_file_"${PG_INCDIR}/libpq-fe.h"" | $as_tr_sh` { $as_echo "$as_me:$LINENO: checking for \"${PG_INCDIR}/libpq-fe.h\"" >&5 $as_echo_n "checking for \"${PG_INCDIR}/libpq-fe.h\"... " >&6; } if { as_var=$as_ac_File; eval "test \"\${$as_var+set}\" = set"; }; then $as_echo_n "(cached) " >&6 else test "$cross_compiling" = yes && { { $as_echo "$as_me:$LINENO: error: cannot check for file existence when cross compiling" >&5 $as_echo "$as_me: error: cannot check for file existence when cross compiling" >&2;} { (exit 1); exit 1; }; } if test -r ""${PG_INCDIR}/libpq-fe.h""; then eval "$as_ac_File=yes" else eval "$as_ac_File=no" fi fi ac_res=`eval 'as_val=${'$as_ac_File'} $as_echo "$as_val"'` { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } as_val=`eval 'as_val=${'$as_ac_File'} $as_echo "$as_val"'` # Now substitute these two variable in src/Makevars.in to create src/Makevars ac_config_files="$ac_config_files src/Makevars" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:$LINENO: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) $as_unset $ac_var ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes (double-quote # substitution turns \\\\ into \\, and sed turns \\ into \). sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then test "x$cache_file" != "x/dev/null" && { $as_echo "$as_me:$LINENO: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} cat confcache >$cache_file else { $as_echo "$as_me:$LINENO: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # Transform confdefs.h into DEFS. # Protect against shell expansion while executing Makefile rules. # Protect against Makefile macro expansion. # # If the first sed substitution is executed (which looks for macros that # take arguments), then branch to the quote section. Otherwise, # look for a macro that doesn't take arguments. ac_script=' :mline /\\$/{ N s,\\\n,, b mline } t clear :clear s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g t quote s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g t quote b any :quote s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g s/\[/\\&/g s/\]/\\&/g s/\$/$$/g H :any ${ g s/^\n// s/\n/ /g p } ' DEFS=`sed -n "$ac_script" confdefs.h` ac_libobjs= ac_ltlibobjs= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. ac_libobjs="$ac_libobjs \${LIBOBJDIR}$ac_i\$U.$ac_objext" ac_ltlibobjs="$ac_ltlibobjs \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : ${CONFIG_STATUS=./config.status} ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} cat >$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ## --------------------- ## ## M4sh Initialization. ## ## --------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in *posix*) set -o posix ;; esac fi # PATH needs CR # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo if (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # Support unset when possible. if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then as_unset=unset else as_unset=false fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. case $0 in *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 { (exit 1); exit 1; } fi # Work around bugs in pre-3.0 UWIN ksh. for as_var in ENV MAIL MAILPATH do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # Required to use basename. if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi # Name of the executable. as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # CDPATH. $as_unset CDPATH as_lineno_1=$LINENO as_lineno_2=$LINENO test "x$as_lineno_1" != "x$as_lineno_2" && test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { # Create $as_me.lineno as a copy of $as_myself, but with $LINENO # uniformly replaced by the line number. The first 'sed' inserts a # line-number line after each line using $LINENO; the second 'sed' # does the real work. The second script uses 'N' to pair each # line-number line with the line containing $LINENO, and appends # trailing '-' during substitution so that $LINENO is not a special # case at line end. # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the # scripts with optimization help from Paolo Bonzini. Blame Lee # E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 { (exit 1); exit 1; }; } # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in -n*) case `echo 'x\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. *) ECHO_C='\c';; esac;; *) ECHO_N='-n';; esac if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -p'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -p' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p=: else test -d ./-p && rmdir ./-p as_mkdir_p=false fi if test -x / >/dev/null 2>&1; then as_test_x='test -x' else if ls -dL / >/dev/null 2>&1; then as_ls_L_option=L else as_ls_L_option= fi as_test_x=' eval sh -c '\'' if test -d "$1"; then test -d "$1/."; else case $1 in -*)set "./$1";; esac; case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in ???[sx]*):;;*)false;;esac;fi '\'' sh ' fi as_executable_p=$as_test_x # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 # Save the log message, to keep $[0] and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by RPostgreSQL $as_me 0.2, which was generated by GNU Autoconf 2.63. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files from templates according to the current configuration. Usage: $0 [OPTION]... [FILE]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE Configuration files: $config_files Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_version="\\ RPostgreSQL config.status 0.2 configured by $0, generated by GNU Autoconf 2.63, with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" Copyright (C) 2008 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac CONFIG_FILES="$CONFIG_FILES '$ac_optarg'" ac_need_defaults=false;; --he | --h | --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) { $as_echo "$as_me: error: unrecognized option: $1 Try \`$0 --help' for more information." >&2 { (exit 1); exit 1; }; } ;; *) ac_config_targets="$ac_config_targets $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "src/Makevars") CONFIG_FILES="$CONFIG_FILES src/Makevars" ;; *) { { $as_echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 $as_echo "$as_me: error: invalid argument: $ac_config_target" >&2;} { (exit 1); exit 1; }; };; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= trap 'exit_status=$? { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status ' 0 trap '{ (exit 1); exit 1; }' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || { $as_echo "$as_me: cannot create a temporary directory in ." >&2 { (exit 1); exit 1; } } # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=' ' ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 $as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} { (exit 1); exit 1; }; } ac_delim_num=`echo "$ac_subst_vars" | grep -c '$'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 $as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} { (exit 1); exit 1; }; } ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 $as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} { (exit 1); exit 1; }; } else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\).*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\).*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \ || { { $as_echo "$as_me:$LINENO: error: could not setup config files machinery" >&5 $as_echo "$as_me: error: could not setup config files machinery" >&2;} { (exit 1); exit 1; }; } _ACEOF # VPATH may cause trouble with some makes, so we remove $(srcdir), # ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=/{ s/:*\$(srcdir):*/:/ s/:*\${srcdir}:*/:/ s/:*@srcdir@:*/:/ s/^\([^=]*=[ ]*\):*/\1/ s/:*$// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" eval set X " :F $CONFIG_FILES " shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) { { $as_echo "$as_me:$LINENO: error: invalid tag $ac_tag" >&5 $as_echo "$as_me: error: invalid tag $ac_tag" >&2;} { (exit 1); exit 1; }; };; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || { { $as_echo "$as_me:$LINENO: error: cannot find input file: $ac_f" >&5 $as_echo "$as_me: error: cannot find input file: $ac_f" >&2;} { (exit 1); exit 1; }; };; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac ac_file_inputs="$ac_file_inputs '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:$LINENO: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$tmp/stdin" \ || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5 $as_echo "$as_me: error: could not create $ac_file" >&2;} { (exit 1); exit 1; }; } ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` { as_dir="$ac_dir" case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || { { $as_echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5 $as_echo "$as_me: error: cannot create directory $as_dir" >&2;} { (exit 1); exit 1; }; }; } ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p ' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:$LINENO: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \ || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5 $as_echo "$as_me: error: could not create $ac_file" >&2;} { (exit 1); exit 1; }; } test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:$LINENO: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined." >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined." >&2;} rm -f "$tmp/stdin" case $ac_file in -) cat "$tmp/out" && rm -f "$tmp/out";; *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";; esac \ || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5 $as_echo "$as_me: error: could not create $ac_file" >&2;} { (exit 1); exit 1; }; } ;; esac done # for ac_tag { (exit 0); exit 0; } _ACEOF chmod +x $CONFIG_STATUS ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || { { $as_echo "$as_me:$LINENO: error: write failure creating $CONFIG_STATUS" >&5 $as_echo "$as_me: error: write failure creating $CONFIG_STATUS" >&2;} { (exit 1); exit 1; }; } # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || { (exit 1); exit 1; } fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:$LINENO: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi RPostgreSQL/man/0000755000176000001440000000000012124517222013200 5ustar ripleyusersRPostgreSQL/man/dbSetDataMappings-methods.Rd0000644000176000001440000000234311455242163020471 0ustar ripleyusers% $Id: dbSetDataMappings-methods.Rd, V 0.1 2008/07/23 02:38:31 psk Exp $ \name{dbSetDataMappings-methods} \docType{methods} \alias{dbSetDataMappings-methods} \alias{dbSetDataMappings,PostgreSQLResult,data.frame-method} \title{ Set data mappings between PostgreSQL and R/S-Plus } \description{ Not yet implemented } \section{Methods}{\describe{ \item{res}{ a \code{PostgreSQLResult} object as returned by \code{dbSendQuery}. } \item{flds}{ a data.frame with field descriptions as returned by \code{\link[DBI]{dbColumnInfo}}. } \item{\dots }{ any additional arguments are passed to the implementing method. } } } \references{ See the Database Interface definition document \code{DBI.pdf} in the base directory of this package or \url{http://stat.bell-labs.com/RS-DBI}. } \seealso{ \code{\link{PostgreSQL}}, \code{\link[DBI]{dbSendQuery}}, \code{\link[DBI]{fetch}}, \code{\link[DBI]{dbColumnInfo}}. } \examples{\dontrun{ makeImage <- function(x) { .C("make_Image", as.integer(x), length(x)) } res <- dbSendQuery(con, statement) flds <- dbColumnInfo(res) flds[3, "Sclass"] <- makeImage dbSetDataMappings(rs, flds) im <- fetch(rs, n = -1) } } \keyword{methods} \keyword{interface} \keyword{database} % vim: syntax=tex RPostgreSQL/man/dbObjectId-class.Rd0000644000176000001440000000303711667154572016606 0ustar ripleyusers% $Id: dbObjectId-class.Rd,v 0.1 2008/08/10 18:04:01 psk Exp $ \name{dbObjectId-class} \docType{class} \alias{dbObjectId-class} \title{Class dbObjectId} \description{ A helper (mixin) class to provide external references in an R/S-Plus portable way. } \section{Objects from the Class}{A virtual Class: No objects may be created from it.} \section{Slots}{ \describe{ \item{\code{Id}:}{Object of class \code{"integer"} this is an integer vector holding an opaque reference into a C struct (may or may not be a C pointer, may or may not have length one). } } } \section{Methods}{ \describe{ \item{\link{coerce}}{\code{signature(from = "dbObjectId", to = "integer")}: ... } \item{\link{coerce}}{\code{signature(from = "dbObjectId", to = "numeric")}: ... } \item{\link{coerce}}{\code{signature(from = "dbObjectId", to = "character")}: ... } \item{\link{format}}{\code{signature(x = "dbObjectId")}: ... } \item{\link{print}}{\code{signature(x = "dbObjectId")}: ... } \item{\link{show}}{\code{signature(object = "dbObjectId")}: ... } } } \note{A cleaner mechanism would use external references, but historically this class has existed mainly for R/S-Plus portability.} \examples{\dontrun{ pg <- dbDriver("PostgreSQL") con <- dbConnect(pg, "user", "password") is(pg, "dbObjectId") ## True is(con, "dbObjectId") ## True isPostgresqlIdCurrent(con) ## True q("yes") \$ R isPostgresqlIdCurrent(con) ## False } } \keyword{classes} \keyword{interface} \keyword{database} % vim: syntax=tex RPostgreSQL/man/PostgreSQLDriver-class.Rd0000644000176000001440000000346211455242163017763 0ustar ripleyusers% $Id: PostgreSQLDriver-class.Rd,v 0.1 2008/07/22 20:56:01 psk Exp $ \name{PostgreSQLDriver-class} \docType{class} \alias{PostgreSQLDriver-class} \title{Class PostgreSQLDriver} \description{ An PostgreSQL driver implementing the R/S-Plus database (DBI) API. } \section{Generators}{ The main generators are \code{\link[DBI]{dbDriver}} and \code{\link{PostgreSQL}}. } \section{Extends}{ Class \code{"DBIDriver"}, directly. Class \code{"PostgreSQLObject"}, directly. Class \code{"DBIObject"}, by class "DBIDriver". Class \code{"dbObjectId"}, by class "PostgreSQLObject". } \section{Methods}{ \describe{ \item{\link{coerce}}{\code{signature(from = "PostgreSQLObject", to = "PostgreSQLDriver")}: ... } \item{\link[DBI]{dbConnect}}{\code{signature(drv = "PostgreSQLDriver")}: ... } \item{\link[DBI]{dbGetInfo}}{\code{signature(dbObj = "PostgreSQLDriver")}: ... } \item{\link[DBI]{dbListConnections}}{\code{signature(drv = "PostgreSQLDriver")}: ... } \item{\link[DBI]{dbUnloadDriver}}{\code{signature(drv = "PostgreSQLDriver")}: ... } \item{\link{summary}}{\code{signature(object = "PostgreSQLDriver")}: ... } } } \references{ See the Database Interface definition document \code{DBI.pdf} in the base directory of this package or \url{http://developer.r-project.org/db}. } \seealso{ DBI base classes: \code{\link[DBI]{DBIObject-class}} \code{\link[DBI]{DBIDriver-class}} \code{\link[DBI]{DBIConnection-class}} \code{\link[DBI]{DBIResult-class}} PostgreSQL classes: \code{\link{PostgreSQLObject-class}} \code{\link{PostgreSQLDriver-class}} \code{\link{PostgreSQLConnection-class}} \code{\link{PostgreSQLResult-class}} } \examples{\dontrun{ drv <- dbDriver("PostgreSQL") con <- dbConnect(drv, dbname="template1") } } \keyword{database} \keyword{interface} \keyword{classes} % vim: syntax=tex RPostgreSQL/man/dbCallProc-methods.Rd0000644000176000001440000000166111455242163017146 0ustar ripleyusers% $Id: dbCallProc-methods.Rd,v 0.1 2008/08/10 18:04:01 psk Exp $ \name{dbCallProc-methods} \docType{methods} \alias{dbCallProc-methods} \alias{dbCallProc,PostgreSQLConnection-method} \title{ Call an SQL stored procedure } \description{ Not yet implemented. } \section{Methods}{\describe{ \item{conn}{ a \code{PostgreSQLConnection} object. } \item{\dots }{ additional arguments are passed to the implementing method. } } } \references{ See the Database Interface definition document \code{DBI.pdf} in the base directory of this package or \url{http://stat.bell-labs.com/RS-DBI}. } \seealso{ \code{\link{PostgreSQL}}, \code{\link[DBI]{dbConnect}}, \code{\link[DBI]{dbSendQuery}}, \code{\link[DBI]{dbGetQuery}}, \code{\link[DBI]{fetch}}, \code{\link[DBI]{dbCommit}}, \code{\link[DBI]{dbGetInfo}}, \code{\link[DBI]{dbReadTable}}. } \keyword{methods} \keyword{interface} \keyword{database} % vim: syntax=tex RPostgreSQL/man/isPostgresqlIdCurrent.Rd0000644000176000001440000000215611667154572020032 0ustar ripleyusers% $Id: isPostgresqlIdCurrent.Rd,v 0.1 2008/07/23 02:38:31 psk Exp $ \name{isPostgresqlIdCurrent} \alias{isPostgresqlIdCurrent} \title{ Check whether a database handle object is valid or not } \description{ Support function that verifies that an object holding a reference to a foreign object is still valid for communicating with the RDBMS } \usage{ isPostgresqlIdCurrent(obj) } \arguments{ \item{obj}{ any \code{dbObject} (e.g., \code{dbDriver}, \code{dbConnection}, \code{dbResult}). } } \value{ a logical scalar. } \details{ \code{dbObjects} are R/S-Plus remote references to foreign objects. This introduces differences to the object's semantics such as persistence (e.g., connections may be closed unexpectedly), thus this function provides a minimal verification to ensure that the foreign object being referenced can be contacted. } \seealso{ \code{\link[DBI]{dbDriver}} \code{\link[DBI]{dbConnect}} \code{\link[DBI]{dbSendQuery}} \code{\link[DBI]{fetch}} } \examples{\dontrun{ cursor <- dbSendQuery(con, sql.statement) isIdCurrent(cursor) } } \keyword{interface} \keyword{database} % docclass is function % vim: syntax=tex RPostgreSQL/man/dbConnect-methods.Rd0000644000176000001440000000623712122717351017042 0ustar ripleyusers% $Id: dbConnect-methods.Rd,v 0.1 2008/07/28 20:56:01 psk Exp $ \name{dbConnect-methods} \docType{methods} \alias{dbDisconnect-methods} \alias{dbConnect-methods} \alias{dbDisconnect,PostgreSQLConnection-method} \alias{dbConnect,PostgreSQLDriver-method} \alias{dbConnect,PostgreSQLConnection-method} \alias{dbConnect,character-method} \title{ Create a connection object to an PostgreSQL DBMS } \description{ These methods are straight-forward implementations of the corresponding generic functions. } \section{Methods}{\describe{ \item{drv}{ an object of class \code{PostgreSQLDriver}, or the character string "PostgreSQL" or an \code{PostgreSQLConnection}. } \item{conn}{ an \code{PostgreSQLConnection} object as produced by \code{dbConnect}. } \item{host}{Name or the numeric IPaddress of the host to connect to. If address is specified, it should be in the standard IPv4 address format, e.g., 172.28.40.9 or if your machine supports IPv6, you can also use those addresses. The default is to connect to localhost. } \item{dbname}{The database name. Defaults to 'template1' i.e if this argument is not specified, it is taken as dbname="template1". } \item{user}{PostgreSQL user name to connect as. Defaults to be the same as the operating system name of the user running the application. } \item{password}{Password to be used if the server demands password authentication. } \item{port}{Port number to connect to at the server host, or socket file name extension for Unix-domain connections. } \item{tty}{Ignored (formerly, this specified where to send server debug output). } \item{options}{Command-line options to be sent to the server } \item{forceISOdate}{logical if the communication of date (time stamp) from PostgreSQL is forced to ISO style at conection. } } } \section{Side Effects}{ A connection between R/S-Plus and an PostgreSQL server is established. The current implementation supports up to 100 simultaneous connections. } \references{ See the Database Interface definition document \code{DBI.pdf} in the base directory of this package or \url{http://stat.bell-labs.com/RS-DBI}. } \seealso{ \code{\link{PostgreSQL}}, \code{\link[DBI]{dbConnect}}, \code{\link[DBI]{dbSendQuery}}, \code{\link[DBI]{dbGetQuery}}, \code{\link[DBI]{fetch}}, \code{\link[DBI]{dbCommit}}, \code{\link[DBI]{dbGetInfo}}, \code{\link[DBI]{dbReadTable}}. } \examples{\dontrun{ # create an PostgreSQL instance and create one connection. drv <- dbDriver("PostgreSQL") # open the connection using user, passsword, etc., as con <- dbConnect(drv, dbname = "postgres") df <- dbGetQuery(con, statement = paste( "SELECT itemCode, itemCost, itemProfit", "FROM sales", "SORT BY itemName")); # Run an SQL statement by creating first a resultSet object rs <- dbSendQuery(con, statement = paste( "SELECT itemCode, itemCost, itemProfit", "FROM sales", "SORT BY itemName")); # we now fetch records from the resultSet into a data.frame df <- fetch(rs, n = -1) # extract all rows dim(df) } } \keyword{methods} \keyword{interface} \keyword{database} % vim: syntax=tex RPostgreSQL/man/fetch-methods.Rd0000644000176000001440000000414411455242163016231 0ustar ripleyusers% $Id: fetch-methods.Rd,v 0.1 2008/07/23 02:38:31 psk Exp $ \name{fetch-methods} \docType{methods} \alias{fetch-methods} \alias{fetch,PostgreSQLResult,numeric-method} \alias{fetch,PostgreSQLResult,missing-method} %\alias{fetch,PostgreSQLResult-method} \title{ Fetch records from a previously executed query } \description{ This method is a straight-forward implementation of the corresponding generic function. } \section{Methods}{\describe{ \item{res}{ an \code{PostgreSQLResult} object. } \item{n}{ maximum number of records to retrieve per fetch. Use \code{n = -1} to retrieve all pending records; use a value of \code{n = 0} for fetching the default number of rows \code{fetch.default.rec} defined in the \code{\link{PostgreSQL}} initialization invocation. } \item{\dots }{currently not used.} } } \details{ The \code{RPostgreSQL} implementations retrieves only \code{n} records, and if \code{n} is missing it only returns up to \code{fetch.default.rec} as specified in the call to \code{\link{PostgreSQL}} (500 by default). } \references{ See the Database Interface definition document \code{DBI.pdf} in the base directory of this package or \url{http://stat.bell-labs.com/RS-DBI}. } \seealso{ \code{\link{PostgreSQL}}, \code{\link[DBI]{dbConnect}}, \code{\link[DBI]{dbSendQuery}}, \code{\link[DBI]{dbGetQuery}}, \code{\link[DBI]{dbClearResult}}, \code{\link[DBI]{dbCommit}}, \code{\link[DBI]{dbGetInfo}}, \code{\link[DBI]{dbReadTable}}. } \examples{\dontrun{ drv <- dbDriver("PostgreSQL") con <- dbConnect(drv, user = "ruser",password = "123456",dbname = "status") res <- dbSendQuery(con, statement = paste( "SELECT w.category, w.cost, p.type", "FROM items w, sales P", "WHERE w.category = p.type", "ORDER BY w.cost")) # we now fetch the first 100 records from the resultSet into a data.frame data1 <- fetch(res, n = 100) dim(data1) dbHasCompleted(res) # let's get all remaining records data2 <- fetch(res, n = -1) } } \keyword{methods} \keyword{interface} \keyword{database} % vim: syntax=tex RPostgreSQL/man/dbDataType-methods.Rd0000644000176000001440000000224511455242163017161 0ustar ripleyusers% $Id: dbDataType-methods.Rd,v 0.1 2008/08/10 18:04:01 psk Exp $ \name{dbDataType-methods} \docType{methods} \alias{dbDataType-methods} \alias{dbDataType,PostgreSQLObject-method} \title{ Determine the SQL Data Type of an S object } \description{ This method is a straight-forward implementation of the corresponding generic function. } \section{Methods}{ \describe{ \item{dbObj}{ any \code{PostgreSQLObject} object, e.g., \code{PostgreSQLDriver}, \code{PostgreSQLConnection}, \code{PostgreSQLResult}. } \item{obj}{ R/S-Plus object whose SQL type we want to determine. } \item{\dots}{ any other parameters that individual methods may need. } } } \references{ See the Database Interface definition document \code{DBI.pdf} in the base directory of this package or \url{http://stat.bell-labs.com/RS-DBI}. } \seealso{ \code{\link[DBI]{isSQLKeyword}} \code{\link[DBI]{make.db.names}} } \examples{\dontrun{ data(quakes) drv <- dbDriver("PostgreSQL") sql.type <- dbDataType(drv, quakes) } } \keyword{methods} \keyword{interface} \keyword{database} % docclass is function % Converted by Sd2Rd version 1.15.2.1. % vim: syntax=tex RPostgreSQL/man/dbApply-methods.Rd0000644000176000001440000000250111455242163016526 0ustar ripleyusers% $Id: dbApply-methods.Rd,v 0.1 2008/08/10 18:04:01 psk Exp $ \name{dbApply-methods} \docType{methods} \alias{dbApply-methods} \alias{dbApply,PostgreSQLResult-method} \title{Apply R/S-Plus functions to remote groups of DBMS rows (experimental)} \description{ Applies R/S-Plus functions to groups of remote DBMS rows without bringing an entire result set all at once. The result set is expected to be sorted by the grouping field. } \section{Methods}{\describe{ \item{res}{a PostgreSQL result set (see \code{\link[DBI]{dbSendQuery}}).} \item{...}{any additional arguments to be passed to \code{FUN}.} } } \references{ See the Database Interface definition document \code{DBI.pdf} in the base directory of this package or \url{http://stat.bell-labs.com/RS-DBI}. } \seealso{ \code{\link{PostgreSQL}} \code{\link{postgresqlDBApply}} \code{\link[DBI]{dbSendQuery}} \code{\link[DBI]{fetch}} } \examples{\dontrun{ ## compute quanitiles for each network agent con <- dbConnect(PostgreSQL(), user="user", password="passwd",dbname="dbname") rs <- dbSendQuery(con, "select Agent, ip_addr, DATA from pseudo_data order by Agent") out <- dbApply(rs, INDEX = "Agent", FUN = function(x, grp) quantile(x$DATA, names=FALSE)) } } \keyword{programming} \keyword{interface} \keyword{database} % vim: syntax=tex RPostgreSQL/man/S4R.Rd0000644000176000001440000000102211455242163014077 0ustar ripleyusers% $Id: S4R.Rd,v 0.1 2008/07/22 20:56:01 psk Exp $ \name{S4R} \alias{ErrorClass} \alias{usingR} \title{R compatibility with S version 4/Splus5+ support functions} \description{ These objects ease the task of porting functions into R from S Version 4 and S-Plus 5.0 and later. See the documentation there. May be obsolete in the future. } \usage{ usingR(major, minor) } \examples{\dontrun{ rc <- try(fetch(res, n = -1)) if(inherit(rc, ErrorClass)) stop("could not fetch the data") } } \keyword{internal} % vim:syntax=tex RPostgreSQL/man/postgresqlDBApply.Rd0000644000176000001440000001005411455242163017113 0ustar ripleyusers% $Id: postgresqlDBApply.Rd,v 0.1 2008/07/23 03:09:11 psk Exp $ \name{postgresqlDBApply} \alias{postgresqlDBApply} \title{Apply R/S-Plus functions to remote groups of DBMS rows (experimental)} \description{ Applies R/S-Plus functions to groups of remote DBMS rows without bringing an entire result set all at once. The result set is expected to be sorted by the grouping field. } \usage{ postgresqlDBApply(res, INDEX, FUN = stop("must specify FUN"), begin = NULL, group.begin = NULL, new.record = NULL, end = NULL, batchSize = 100, maxBatch = 1e6, ..., simplify = TRUE) } \arguments{ \item{res}{a result set (see \code{\link[DBI]{dbSendQuery}}).} \item{INDEX}{a character or integer specifying the field name or field number that defines the various groups.} \item{FUN}{a function to be invoked upon identifying the last row from every group. This function will be passed a data frame holding the records of the current group, a character string with the group label, plus any other arguments passed to \code{dbApply} as \code{"..."}.} \item{begin}{a function of no arguments to be invoked just prior to retrieve the first row from the result set.} \item{end}{a function of no arguments to be invoked just after retrieving the last row from the result set.} \item{group.begin}{a function of one argument (the group label) to be invoked upon identifying a row from a new group}. \item{new.record}{a function to be invoked as each individual record is fetched. The first argument to this function is a one-row data.frame holding the new record.} \item{batchSize}{the default number of rows to bring from the remote result set. If needed, this is automatically extended to hold groups bigger than \code{batchSize}.} \item{maxBatch}{the absolute maximum of rows per group that may be extracted from the result set.} \item{...}{any additional arguments to be passed to \code{FUN}.} \item{simplify}{Not yet implemented} } \details{ \code{dbApply} This function is meant to handle somewhat gracefully(?) large amounts of data from the DBMS by bringing into R manageable chunks (about \code{batchSize} records at a time, but not more than \code{maxBatch}); the idea is that the data from individual groups can be handled by R, but not all the groups at the same time. The PostgreSQL implementation \code{postgresqlDBApply} allows us to register R functions that get invoked when certain fetching events occur. These include the ``begin'' event (no records have been yet fetched), ``begin.group'' (the record just fetched belongs to a new group), ``new record'' (every fetched record generates this event), ``group.end'' (the record just fetched was the last row of the current group), ``end'' (the very last record from the result set). Awk and perl programmers will find this paradigm very familiar (although SAP's ABAP language is closer to what we're doing). } \value{ A list with as many elements as there were groups in the result set. } \note{This is an experimental version implemented only in R (there are plans, time permitting, to implement it in S-Plus). The terminology that we're using is closer to SQL than R. In R what we're referring to ``groups'' are the individual levels of a factor (grouping field in our terminology). } \seealso{\code{\link{PostgreSQL}}, \code{\link[DBI]{dbSendQuery}}, \code{\link[DBI]{fetch}}.} \examples{\dontrun{ drv <- dbDriver(RPostgreSQL) con <- dbConnect(drv, user ="usrname", password="pword", dname="database") res <- dbSendQuery(con, "select Agent, ip_addr, DATA from pseudo_data order by Agent") out <- dbApply(res, INDEX = "Agent", FUN = function(x, grp) quantile(x$DATA, names=FALSE)) } } \keyword{programming}% at least one, from doc/KEYWORDS \keyword{interface}% __ONLY ONE__ keyword per line \keyword{database} % vim: syntax=tex RPostgreSQL/man/make.db.names-methods.Rd0000644000176000001440000000522011667154572017552 0ustar ripleyusers% $Id: make.db.names-methods.Rd,v 0.1 2008/07/22 03:16:22 psk Exp $ \name{make.db.names-methods} \docType{methods} \alias{SQLKeywords-methods} \alias{isSQLKeyword-methods} \alias{make.db.names,PostgreSQLObject,character-method} \alias{SQLKeywords,PostgreSQLObject-method} \alias{SQLKeywords,missing-method} \alias{isSQLKeyword,PostgreSQLObject,character-method} \title{ Make R/S-Plus identifiers into quoted PostgreSQL identifiers } \description{ Calls postgresqlquoteId to make valid quoted identifiers. This has calling convention same as the make.db.names for compatibility. } \section{Methods}{\describe{ \item{dbObj}{ any PostgreSQL object (e.g., \code{PostgreSQLDriver}). Just ignored. } \item{snames}{ a character vector of R/S-Plus identifiers (symbols) from which we need to make SQL identifiers. } \item{name}{ a character vector of SQL identifiers we want to check against keywords from the DBMS. Ignored. } \item{unique}{ logical describing whether the resulting set of SQL names should be unique. Its default is \code{TRUE}. Following the SQL 92 standard, uniqueness of SQL identifiers is determined regardless of whether letters are upper or lower case. Ignored. } \item{allow.keywords }{ logical describing whether SQL keywords should be allowed in the resulting set of SQL names. Its default is \code{TRUE}. Ignored. } \item{keywords}{ a character vector with SQL keywords, by default it is \code{.PostgreSQLKeywords} define in \code{RPostgreSQL}. This may be overriden by users. Ignored. } \item{case}{ a character string specifying whether to make the comparison as lower case, upper case, or any of the two. it defaults to \code{any}. Ignored. } \item{\dots}{currently not used.} } } \references{ The set of SQL keywords is stored in the character vector \code{.SQL92Keywords} and reflects the SQL ANSI/ISO standard as documented in "X/Open SQL and RDA", 1994, ISBN 1-872630-68-8. Users can easily override or update this vector. PostgreSQL does add some keywords to the SQL 92 standard, they are listed in the \code{.PostgreSQLKeywords} object. See the Database Interface definition document \code{DBI.pdf} in the base directory of this package or \url{http://stat.bell-labs.com/RS-DBI}. } \seealso{ \code{\link{PostgreSQL}}, \code{\link[DBI]{dbReadTable}}, \code{\link[DBI]{dbWriteTable}}, \code{\link[DBI]{dbExistsTable}}, \code{\link[DBI]{dbRemoveTable}}, \code{\link[DBI]{dbListTables}}. } \examples{\dontrun{ # This example shows how we could export a bunch of data.frames # into tables on a remote database. } } \keyword{methods} \keyword{interface} \keyword{database} % vim: syntax=tex RPostgreSQL/man/dbDriver-methods.Rd0000644000176000001440000000446111455242163016703 0ustar ripleyusers% $Id: dbDriver-methods.Rd,v 0.1 2008/07/28 01:09:05 psk Exp $ \name{dbDriver-methods} \docType{methods} \alias{dbDriver-methods} \alias{dbUnloadDriver-methods} \alias{dbDriver,character-method} \alias{dbUnloadDriver,PostgreSQLDriver-method} \title{ PostgreSQL implementation of the Database Interface (DBI) classes and drivers } \description{ PostgreSQL driver initialization and closing } \section{Methods}{\describe{ \item{drvName}{ character name of the driver to instantiate. } \item{drv}{ an object that inherits from \code{PostgreSQLDriver} as created by \code{dbDriver}. } \item{max.con}{optional integer requesting the maximum number of simultanous connections (may be up to 100)}. \item{fetch.default.rec}{default number of records to retrieve per fetch. Default is 500. This may be overridden in calls to \code{\link[DBI]{fetch}} with the \code{n=} argument.} \item{force.reload}{optional logical used to force re-loading or recomputing the size of the connection table. Default is \code{FALSE}.} \item{...}{currently unused.} } } \references{ See the Database Interface definition document \code{DBI.pdf} in the base directory of this package or \url{http://stat.bell-labs.com/RS-DBI}. } \seealso{ \code{\link{PostgreSQL}}, \code{\link[DBI]{dbConnect}}, \code{\link[DBI]{dbSendQuery}}, \code{\link[DBI]{dbGetQuery}}, \code{\link[DBI]{fetch}}, \code{\link[DBI]{dbCommit}}, \code{\link[DBI]{dbGetInfo}}, \code{\link[DBI]{dbListTables}}, \code{\link[DBI]{dbReadTable}}. } \examples{\dontrun{ # create an PostgreSQL instance and set 10000 of rows per fetch. library(RPostgreSQL) drv <- dbDriver("PostgreSQL", fetch.default.records=10000) # Connecting to PostgreSQL with the specified parameters con <- dbConnect(drv,user="usrname",password="passwd",dbname="postgres") # Running the query to obtain the resultset rs <- dbSendQuery(con, "select * from cities where population > 5000") # fetch records into a dataframe. # n = 50 fetched fifty records df <- fetch(rs, n = 50) # n = -1 fetches all the remaining records available df2 <- fetch(rs, n = -1) # Clearing the result set dbClearResult(rs) #This returns a character vector (possibly of zero-length) # table names available on the con connection. dbListTables(con) } } \keyword{methods} \keyword{interface} \keyword{database} % vim: syntax=tex RPostgreSQL/man/PostgreSQLConnection-class.Rd0000644000176000001440000000577711455242163020642 0ustar ripleyusers% $Id: PostgreSQLConnection-class.Rd,v 0.1 2008/07/23 03:14:11 psk Exp $ \name{PostgreSQLConnection-class} \docType{class} \alias{PostgreSQLConnection-class} \title{Class PostgreSQLConnection} \description{PostgreSQLConnection class.} \section{Generators}{ The method \code{\link[DBI]{dbConnect}} is the main generator. } \section{Extends}{ Class \code{"DBIConnection"}, directly. Class \code{"PostgreSQLObject"}, directly. Class \code{"DBIObject"}, by class "DBIConnection". Class \code{"dbObjectId"}, by class "PostgreSQLObject". } \section{Methods}{ \describe{ \item{\link{coerce}}{\code{signature(from = "PostgreSQLConnection", to = "PostgreSQLResult")}: ... } \item{\link[DBI]{dbCallProc}}{\code{signature(conn = "PostgreSQLConnection")}: ... } \item{\link[DBI]{dbCommit}}{\code{signature(conn = "PostgreSQLConnection")}: ... } \item{\link[DBI]{dbConnect}}{\code{signature(drv = "PostgreSQLConnection")}: ... } \item{\link[DBI]{dbDisconnect}}{\code{signature(conn = "PostgreSQLConnection")}: ... } \item{\link[DBI]{dbExistsTable}}{\code{signature(conn = "PostgreSQLConnection", name = "character")}: ... } \item{\link[DBI]{dbGetException}}{\code{signature(conn = "PostgreSQLConnection")}: ... } \item{\link[DBI]{dbGetInfo}}{\code{signature(dbObj = "PostgreSQLConnection")}: ... } \item{\link[DBI]{dbGetQuery}}{\code{signature(conn = "PostgreSQLConnection", statement = "character")}: ... } \item{\link[DBI]{dbListFields}}{\code{signature(conn = "PostgreSQLConnection", name = "character")}: ... } \item{\link[DBI]{dbListResults}}{\code{signature(conn = "PostgreSQLConnection")}: ... } \item{\link[DBI]{dbListTables}}{\code{signature(conn = "PostgreSQLConnection")}: ... } \item{\link[DBI]{dbReadTable}}{\code{signature(conn = "PostgreSQLConnection", name = "character")}: ... } \item{\link[DBI]{dbRemoveTable}}{\code{signature(conn = "PostgreSQLConnection", name = "character")}: ... } \item{\link[DBI]{dbRollback}}{\code{signature(conn = "PostgreSQLConnection")}: ... } \item{\link[DBI]{dbSendQuery}}{\code{signature(conn = "PostgreSQLConnection", statement = "character")}: ... } \item{\link[DBI]{dbWriteTable}}{\code{signature(conn = "PostgreSQLConnection", name = "character", value = "data.frame")}: ... } \item{summary}{\code{signature(object = "PostgreSQLConnection")}: ... } } } \references{ See the Database Interface definition document \code{DBI.pdf} in the base directory of this package or \url{http://developer.r-project.org/db}. } \seealso{ DBI base classes: \code{\link[DBI]{DBIObject-class}} \code{\link[DBI]{DBIDriver-class}} \code{\link[DBI]{DBIConnection-class}} \code{\link[DBI]{DBIResult-class}} PostgreSQL classes: \code{\link{PostgreSQLObject-class}} \code{\link{PostgreSQLDriver-class}} \code{\link{PostgreSQLConnection-class}} \code{\link{PostgreSQLResult-class}} } \examples{\dontrun{ drv <- dbDriver("PostgreSQL) con <- dbConnect(drv, dbname = "template1") } } \keyword{database} \keyword{interface} \keyword{classes} % vim: syntax=tex RPostgreSQL/man/postgresqlBuildTableDefinition.Rd0000644000176000001440000000301211667154572021647 0ustar ripleyusers%% TODO: Should we move this to the DBI package? \name{postgresqlBuildTableDefinition} \alias{postgresqlBuildTableDefinition} \title{Build the SQL CREATE TABLE definition as a string} \description{ Build the SQL CREATE TABLE definition as a string for the input data.frame } \usage{ postgresqlBuildTableDefinition(dbObj, name, obj, field.types = NULL, row.names = TRUE, ...) } \arguments{ \item{dbObj}{any DBI object (used only to dispatch according to the engine (e.g., MySQL, Oracle, PostgreSQL, SQLite) } \item{name}{name of the new SQL table} \item{obj}{an R object coerceable to data.frame for which we want to create a table} \item{field.types}{optional named list of the types for each field in \code{obj}} \item{row.names}{logical, should row.name of \code{value} be exported as a \code{row\_names} field? Default is TRUE} \item{\dots}{reserved for future use} } \details{ The output SQL statement is a simple \code{CREATE TABLE} with suitable for \code{dbGetQuery} } \value{ An SQL string } \references{ See the Database Interface definition document \code{DBI.pdf} in the base directory of this package or \url{http://stat.bell-labs.com/RS-DBI}. } \seealso{ \code{\link{PostgreSQL}}, \code{\link[DBI]{dbConnect}}, \code{\link[DBI]{dbSendQuery}}, \code{\link[DBI]{dbGetQuery}}, \code{\link[DBI]{fetch}}, \code{\link[DBI]{dbCommit}}, \code{\link[DBI]{dbGetInfo}}, \code{\link[DBI]{dbReadTable}}. } \keyword{methods} \keyword{interface} \keyword{database} %% vim: syntax=tex RPostgreSQL/man/dbReadTable-methods.Rd0000644000176000001440000001207611455456657017313 0ustar ripleyusers% $Id: dbReadTable-methods.Rd,v 0.1 2008/07/23 02:38:31 psk Exp $ \name{dbReadTable-methods} \docType{methods} \alias{dbReadTable-methods} \alias{dbWriteTable-methods} \alias{dbExistsTable-methods} \alias{dbRemoveTable-methods} \alias{dbReadTable,PostgreSQLConnection,character-method} \alias{dbWriteTable,PostgreSQLConnection,character,character-method} \alias{dbWriteTable,PostgreSQLConnection,character,data.frame-method} \alias{dbExistsTable,PostgreSQLConnection,character-method} \alias{dbRemoveTable,PostgreSQLConnection,character-method} \title{ Convenience functions for Importing/Exporting DBMS tables } \description{ These functions mimic their R/S-Plus counterpart \code{get}, \code{assign}, \code{exists}, \code{remove}, and \code{objects}, except that they generate code that gets remotely executed in a database engine. } \section{Methods}{\describe{ \item{conn}{ an \code{PostgreSQLConnection} database connection object. } \item{name}{ a character string specifying a table name. } \item{value}{ a data.frame (or coercible to data.frame). When the \code{value} is a character string, it is assumed to be a file name containing the data to be loaded; The implementation is INCOMPLETE and should not be used in current state. } \item{row.names}{ UNTESTED; in the case of \code{dbReadTable}, this argument can be a string or an index specifying the column in the DBMS table to be used as \code{row.names} in the output data.frame (a \code{NULL}, \code{""}, or 0 specifies that no column should be used as \code{row.names} in the output). In the case of \code{dbWriteTable}, this argument should be a logical specifying whether the \code{row.names} should be output to the output DBMS table; if \code{TRUE}, an extra field whose name will be whatever the R/S-Plus identifier \code{"row.names"} maps to the DBMS (see \code{\link[DBI]{make.db.names}}). } \item{overwrite}{ a logical specifying whether to overwrite an existing table or not. Its default is \code{FALSE}. } \item{append}{ a logical specifying whether to append to an existing table in the DBMS. Its default is \code{FALSE}. } \item{allow.keywords}{ \code{dbWriteTable} accepts a logical \code{allow.keywords} to allow or prevent PostgreSQL reserved identifiers to be used as column names. By default it is \code{FALSE}. } \item{dots}{ optional arguments. When \code{dbWriteTable} is used to import data from a file, you may optionally specify \code{header=}, \code{row.names=}, \code{col.names=}, \code{sep=}, \code{eol=}, \code{field.types=}, \code{skip=}, and \code{quote=}. NOT FULLY IMPLEMENTED YET. \code{header} is a logical indicating whether the first data line (but see \code{skip}) has a header or not. If missing, it value is determined following \code{\link{read.table}} convention, namely, it is set to TRUE if and only if the first row has one fewer field that the number of columns. \code{row.names} is a logical to specify whether the first column is a set of row names. If missing its default follows the \code{\link{read.table}} convention. \code{col.names} a character vector with column names; column names are quoted to work as SQL identifiers. Thus, the column names are case sensitive and \code{\link[DBI]{make.db.names}} will NOT be used here. \code{sep=} specifies the field separator, and its default is \code{','}. \code{eol=} specifies the end-of-line delimiter, and its default is \code{'\n'}. \code{skip} specifies number of lines to skip before reading the data, and it defaults to 0. \code{field.types} is a list of named field SQL types where \code{names(field.types)} provide the new table's column names (if missing, field types are inferred using \code{\link[DBI]{dbDataType}}). } } } \value{ A \code{data.frame} in the case of \code{dbReadTable}; otherwise a logical indicating whether the operation was successful. } \note{ dbWriteTable creates additional column in the database, while dbReadTable reads that column by default. So, it is not symmetrical in its current implementation. the backend raw_names may change in future versions. } \references{ See the Database Interface definition document \code{DBI.pdf} in the base directory of this package or \url{http://stat.bell-labs.com/RS-DBI}. } \seealso{ \code{\link{PostgreSQL}}, \code{\link[DBI]{isSQLKeyword}}, \code{\link[DBI]{dbDriver}}, \code{\link[DBI]{dbConnect}}, \code{\link[DBI]{dbSendQuery}}, \code{\link[DBI]{dbGetQuery}}, \code{\link[DBI]{fetch}}, \code{\link[DBI]{dbCommit}}, \code{\link[DBI]{dbGetInfo}}, \code{\link[DBI]{dbListTables}}, \code{\link[DBI]{dbReadTable}}. } \examples{\dontrun{ conn <- dbConnect("PostgreSQL", dbname = "wireless") if(dbExistsTable(con, "frame_fuel")){ dbRemoveTable(conn, "frame_fuel") dbWriteTable(conn, "frame_fuel", fuel.frame) } if(dbExistsTable(conn, "RESULTS")){ dbWriteTable(conn, "RESULTS", results2000, append = T) else dbWriteTable(conn, "RESULTS", results2000) } } } \keyword{methods} \keyword{interface} \keyword{database} % vim: syntax=tex RPostgreSQL/man/summary-methods.Rd0000644000176000001440000000265311455242163016640 0ustar ripleyusers% $Id: summary-methods.Rd,v 0.1 2008/08/10 15:09:01 psk $ \name{summary-methods} \docType{methods} \alias{coerce-methods} \alias{summary-methods} \alias{format-methods} \alias{show-methods} \alias{coerce,dbObjectId,integer-method} \alias{coerce,dbObjectId,numeric-method} \alias{coerce,dbObjectId,character-method} \alias{coerce,PostgreSQLObject,PostgreSQLDriver-method} \alias{coerce,PostgreSQLConnection,PostgreSQLResult-method} \alias{coerce,PostgreSQLConnection,PostgreSQLDriver-method} \alias{coerce,PostgreSQLResult,PostgreSQLConnection-method} \alias{coerce,PostgreSQLResult,PostgreSQLDriver-method} \alias{format,dbObjectId-method} \alias{print,dbObjectId-method} \alias{show,dbObjectId-method} \alias{summary,PostgreSQLObject-method} \alias{summary,PostgreSQLDriver-method} \alias{summary,PostgreSQLConnection-method} \alias{summary,PostgreSQLResult-method} \title{Summarize an PostgreSQL object} \description{ These methods are straight-forward implementations of the corresponding generic functions. } \section{Methods}{\describe{ \item{object = "DBIObject"}{ Provides relevant metadata information on \code{object}, for instance, the PostgreSQL server file, the SQL statement associated with a result set, etc. } \item{from}{object to be coerced} \item{to}{coercion class} \item{x}{object to \code{format} or \code{print} or \code{show}} } } \keyword{methods} \keyword{database} \keyword{interface} % vim: syntax=tex RPostgreSQL/man/postgresqlSupport.Rd0000644000176000001440000002774212124517166017312 0ustar ripleyusers% $Id: postgresqlSupport.Rd,v 0.1 2008/07/23 02:23:01 psk Exp $ \name{postgresqlSupport} \alias{postgresqlInitDriver} % driver-related function \alias{postgresqlDriverInfo} \alias{postgresqlDescribeDriver} \alias{postgresqlCloseDriver} % connection-related \alias{postgresqlNewConnection} \alias{postgresqlCloneConnection} \alias{postgresqlConnectionInfo} \alias{postgresqlDescribeConnection} \alias{postgresqlCloseConnection} \alias{postgresqlExecStatement} % result-related \alias{postgresqlFetch} \alias{postgresqlQuickSQL} \alias{postgresqlResultInfo} \alias{postgresqlDescribeResult} \alias{postgresqlCloseResult} \alias{postgresqlDescribeFields} \alias{postgresqlReadTable} \alias{postgresqlWriteTable} % convenience functions \alias{postgresqlpqExec} \alias{postgresqlCopyIn} \alias{postgresqlCopyInDataframe} \alias{postgresqlgetResult} \alias{postgresqlEscapeStrings} \alias{postgresqlQuoteId} \alias{postgresqlTableRef} \alias{postgresqlImportFile} \alias{postgresqlDataType} \alias{postgresqlTransactionStatement} % transaction management \alias{.PostgreSQLPkgName} % constants \alias{.PostgreSQLPkgVersion} \alias{.PostgreSQLPkgRCS} \alias{.PostgreSQL.NA.string} \alias{.PostgreSQLSQLKeywords} \alias{.conflicts.OK} %\non_function{} \title{Support Functions} \description{ These functions are the workhorse behind the RPostgreSQL package, but users need not invoke these directly. For details see \code{\link{PostgreSQL}}. } \usage{ ## PostgreSQLDriver-related postgresqlInitDriver(max.con=16, fetch.default.rec = 500, force.reload=FALSE) postgresqlDriverInfo(obj, what, ...) postgresqlDescribeDriver(obj, verbose = FALSE, ...) postgresqlCloseDriver(drv, ...) ## PostgreSQLConnection-related postgresqlNewConnection(drv, user, password, host, dbname, port, tty, options, forceISOdate = TRUE) postgresqlCloneConnection(con, ...) postgresqlConnectionInfo(obj, what, ...) postgresqlDescribeConnection(obj, verbose = FALSE, ...) postgresqlCloseConnection(con, ...) ## PostgreSQLResult-related postgresqlExecStatement(con, statement, params, ...) postgresqlFetch(res, n=0, ...) postgresqlQuickSQL(con, statement, ...) postgresqlResultInfo(obj, what, ...) postgresqlDescribeResult(obj, verbose = FALSE, ...) postgresqlCloseResult(res, ...) postgresqlDescribeFields(res, ...) ## data mappings, convenience functions, and extensions postgresqlDataType(obj, ...) postgresqlReadTable(con, name, row.names = "row.names", check.names = TRUE, ...) postgresqlWriteTable(con, name, value, field.types, row.names = TRUE, overwrite=FALSE, append=FALSE, ..., allow.keywords = FALSE) postgresqlpqExec(con, statement) postgresqlCopyIn(con, filename) postgresqlgetResult(con) postgresqlEscapeStrings(con, preescapedstring) postgresqlQuoteId(identifiers) postgresqlTableRef(identifiers) postgresqlImportFile(con, name, value, field.types, overwrite=FALSE, append=FALSE, header, row.names, nrows=50, sep=",", eol="\n", skip = 0, quote="\"", ...) ## Transaction Management postgresqlTransactionStatement(con, statement) } \arguments{ \item{max.con}{ positive integer specifying maximum number of open connections. The current default of 10 is hardcoded in the C code. } \item{fetch.default.rec}{ default number of rows to fetch (move to R/S-Plus). This default is used in \code{postgresqlFetch}. The default is 500. } \item{force.reload}{ logical indicating whether to re-initialize the driver. This may be useful if you want to change the defaults (e.g., \code{fetch.default.rec}). Note that the driver is a singleton (subsequent inits just returned the previously initialized driver, thus this argument). } \item{obj}{ any of the PostgreSQL DBI objects (e.g., \code{PostgreSQLConnection}, \code{PostgreSQLResult}). } \item{what}{ character vector of metadata to extract, e.g., "version", "statement", "isSelect". } \item{verbose}{ logical controlling how much information to display. Defaults to \code{FALSE}. } \item{drv}{ an \code{PostgreSQLDriver} object as produced by \code{postgresqlInitDriver}. } \item{con}{ an \code{PostgreSQLConnection} object as produced by \code{postgresqlNewConnection} and \code{postgresqlCloneConnection}. } \item{res}{ an \code{PostgreSQLResult} object as produced by by \code{postgresqlExecStatement} and \code{postgresqlgetResult}. } \item{user}{ a character string with the PostgreSQL's user name. } \item{password}{ character string with the PostgreSQL's password. } \item{dbname}{ character string with the PostgreSQL database name. } \item{host}{ character string with the name (or IP address) of the machine hosting the database. Default is \code{""}, which is interpreted as \code{localhost} by the PostgreSQL's API. } \item{port}{ (optional) positive integer specifying the TCP port number that the PostgreSQL server is listening to. Consult the PostgreSQL documentation for details. } \item{tty}{ Ignored (formerly, this specified where to send server debug output) } \item{options}{ Command-line options to be sent to the server } \item{forceISOdate}{ logical indicating whether "set datestyle to ISO" is issued upon connection. Although this is made as an option, the conversion needs to be ISO style for proper conversion of the date datatype. } \item{force}{ logical indicating whether to close a connection that has open result sets. The default is \code{FALSE}. } \item{statement}{ character string holding one (and only one) SQL statement. } \item{params}{ actual values that is written as parameters in the statement. } \item{n}{ number of rows to fetch from the given result set. A value of -1 indicates to retrieve all the rows. The default of 0 specifies to extract whatever the \code{fetch.default.rec} was specified during driver initialization \code{postgresqlInit}. } \item{name}{ character vector of names (table names, fields, keywords). } \item{value}{ a data.frame. } \item{field.types}{ a list specifying the mapping from R/S-Plus fields in the data.frame \code{value} to SQL data types. The default is \code{sapply(value,SQLDataType)}, see \code{PostgreSQLSQLType}. } \item{header}{ logical, does the input file have a header line? Default is the same heuristic used by \code{read.table}, i.e., TRUE if the first line has one fewer column that the second line. } \item{row.names}{ a logical specifying whether to prepend the \code{value} data.frame row names or not. The default is \code{TRUE}. } \item{check.names}{ a logical specifying whether to convert DBMS field names into legal S names. Default is \code{TRUE}. } \item{overwrite}{ logical indicating whether to replace the table \code{name} with the contents of the data.frame \code{value}. The defauls is \code{FALSE}. } \item{append}{ logical indicating whether to append \code{value} to the existing table \code{name}. } \item{nrows}{ number of lines to rows to import using \code{read.table} from the input file to create the proper table definition. Default is 50. } \item{sep}{field separator character.} \item{eol}{end-of-line separator.} \item{skip}{number of lines to skip before reading data in the input file.} \item{quote}{the quote character used in the input file (defaults to \code{\"}.} \item{allow.keywords}{ logical indicating whether column names that happen to be PostgreSQL keywords be used as column names in the resulting relation (table) being written. Defaults to \code{FALSE}, forcing \code{postgresqlWriteTable} to modify column names to make them legal PostgreSQL identifiers. } \item{preescapedstring}{character string to be escaped} \item{identifiers}{one or more character strings to be used as identfier in SQL statement} \item{filename}{character string indicating the file which contains the data to be copied to the PostgreSQL backend} \item{\dots}{ placeholder for future use. } } \value{ \code{postgresqlInitDriver} returns an \code{PostgreSQLDriver} object. \code{postgresqlDriverInfo} returns a list of name-value metadata pairs. \code{postgresqlDescribeDriver} returns \code{NULL} (displays the object's metadata). \code{postgresqlCloseDriver} returns a logical indicating whether the operation succeeded or not. \code{postgresqlNewConnection} returns an \code{PostgreSQLConnection} object. \code{postgresqlCloneConnection} returns an \code{PostgreSQLConnection} object. \code{postgresqlConnectionInfo}returns a list of name-value metadata pairs. \code{postgresqlDescribeConnection} returns \code{NULL} (displays the object's metadata). \code{postgresqlCloseConnection} returns a logical indicating whether the operation succeeded or not. \code{postgresqlExecStatement} returns an \code{PostgreSQLResult} object. \code{postgresqlFetch} returns a data.frame. \code{postgresqlQuickSQL} returns either a data.frame if the \code{statement} is a \code{select}-like or NULL otherwise. \code{postgresqlDescribeResult} returns \code{NULL} (displays the object's metadata). \code{postgresqlCloseResult} returns a logical indicating whether the operation succeeded or not. \code{postgresqlDescribeFields} returns a data.frame with one row per field with columns \code{name}, \code{Sclass}, \code{type}, \code{len}, \code{precision}, \code{scale}, and \code{nullOK} which fully describe each field in a result set. Except for \code{Sclass} (which shows the mapping of the field type into an R/S-Plus class) all the information pertains to PostgreSQL's data storage attributes. \code{postgresqlReadTable} returns a data.frame with the contents of the DBMS table. \code{postgresqlWriteTable} returns a logical indicating whether the operation succeeded or not. \code{postgresqlpqExec} returns \code{NUL} (executes the statement but does not try to get result. This is called internally from \code{postgresqlWriteTable} before \code{postgresqlCopyInDataframe} \code{postgresqlCopyIn} returns \code{NULL} (copies the content of the file through the socket connection to postgresql backend. This should be used just after COPY tablename FROM STDIN query. This is not used now.) \code{postgresqlCopyInDataframe} returns \code{NULL} (copies the content of the dataframe through the socket connection to postgresql backend. Strings are encoded as UTF-8 for transfer. The client_encoding should be set to UTF-8. This should be used just after COPY tablename FROM STDIN query.) \code{postgresqlgetResult} returns an \code{PostgreSQLResult} object. This is called after completion of execution of \code{postgresqlpqExec}. \code{postgresqlEscapeStrings} returns a character string which is escaped properly so that it can be surrounded with a single quote and used as literal in SQL. The escape procedure is dependent on the character encoding of the connection. \code{postgresqlQuoteId} returns a character string which is quoted as identifier. Returns vector on vector arguemnt. \code{postgresqlTableRef} returns a character string which is quoted as identifier. Reterns a charcter string concatenated with "." so that "dbname"."schemaname"."tablename" reference is created upon c("dbname", "schemaname", "tablename") arguemnt. \code{postgresqlDataType} retuns a character string with the closest \code{postgresqlResultInfo} returns a list of name-value metadata pairs. \code{postgresqlTransactionStatement} returns a logical indicating whether the operation succeeded or not. } \section{Constants}{ \code{.PostgreSQLPkgName} (currently \code{"RPostgreSQL"}), \code{.PostgreSQLPkgVersion} (the R package version), \code{.PostgreSQLPkgRCS} (the RCS revision), \code{.PostgreSQL.NA.string} (character that PostgreSQL uses to denote \code{NULL} on input), \code{.PostgreSQLSQLKeywords} (a lot!) \code{.conflicts.OK}. %\non_function{} } \keyword{datasets} \keyword{interface} \keyword{database} %\keyword{internal} % vim:syntax=tex RPostgreSQL/man/dbApply.Rd0000644000176000001440000000324111455242163015067 0ustar ripleyusers% $Id: dbApply.Rd,v d0.1 2008/08/10 18:04:01 psk Exp $ \name{dbApply} \alias{dbApply} \title{Apply R/S-Plus functions to remote groups of DBMS rows (experimental)} \description{ Applies R/S-Plus functions to groups of remote DBMS rows without bringing an entire result set all at once. The result set is expected to be sorted by the grouping field. } %\usage{ %dbApply(res, ...) %} %\arguments{ % \item{res}{a result set (see \code{\link[DBI]{dbSendQuery}}).} % \item{...}{any additional arguments to be passed to \code{FUN}.} %} \details{ \code{dbApply} This generic is meant to handle somewhat gracefully(?) large amounts of data from the DBMS by bringing into R manageable chunks; the idea is that the data from individual groups can be handled by R, but not all the groups at the same time. Currently, only the \code{\link{PostgreSQL}} driver implements a method (see the helper function \code{\link{postgresqlDBApply}}) for this generic function. } \value{ A list with as many elements as there were groups in the result set. } \seealso{ \code{\link{PostgreSQL}} \code{\link{postgresqlDBApply}} \code{\link[DBI]{dbSendQuery}} \code{\link[DBI]{fetch}} } \examples{\dontrun{ ## compute quantiles for each network agent con <- dbConnect(PostgreSQL(), user= "user", password="passwd", dbname="sample") rs <- dbSendQuery(con, "select Agent, ip_addr, DATA from pseudo_data order by Agent") out <- dbApply(rs, INDEX = "Agent", FUN = function(x, grp) quantile(x$DATA, names=FALSE)) } } \keyword{programming}% at least one, from doc/KEYWORDS \keyword{interface}% __ONLY ONE__ keyword per line \keyword{database} % vim: syntax=tex RPostgreSQL/man/dbGetInfo-methods.Rd0000644000176000001440000000436311455446472017015 0ustar ripleyusers% $Id: dbGetInfo-methods.Rd,v 0.1 2008/08/10 18:04:01 psk Exp $ \name{dbGetInfo-methods} \docType{methods} \alias{dbGetInfo} \alias{dbGetDBIVersion-methods} \alias{dbGetStatement-methods} \alias{dbGetRowCount-methods} \alias{dbGetRowsAffected-methods} \alias{dbColumnInfo-methods} \alias{dbHasCompleted-methods} \alias{dbGetInfo,PostgreSQLObject-method} \alias{dbGetInfo,PostgreSQLDriver-method} % BUG: this is not needed \alias{dbGetInfo,PostgreSQLConnection-method} % BUG: this is not needed \alias{dbGetInfo,PostgreSQLResult-method} % BUG: this is not needed \alias{dbGetStatement,PostgreSQLResult-method} \alias{dbGetRowCount,PostgreSQLResult-method} \alias{dbGetRowsAffected,PostgreSQLResult-method} \alias{dbColumnInfo,PostgreSQLResult-method} \alias{dbHasCompleted,PostgreSQLResult-method} \title{ Database interface meta-data } \description{ These methods are straight-forward implementations of the corresponding generic functions. } \section{Methods}{\describe{ \item{dbObj}{ any object that implements some functionality in the R/S-Plus interface to databases (a driver, a connection or a result set). } \item{res}{ an \code{PostgreSQLResult}.} \item{\dots}{currently not being used.} } } \references{ See the Database Interface definition document \code{DBI.pdf} in the base directory of this package or \url{http://stat.bell-labs.com/RS-DBI}. } \seealso{ \code{\link{PostgreSQL}}, \code{\link[DBI]{dbDriver}}, \code{\link[DBI]{dbConnect}}, \code{\link[DBI]{dbSendQuery}}, \code{\link[DBI]{dbGetQuery}}, \code{\link[DBI]{fetch}}, \code{\link[DBI]{dbCommit}}, \code{\link[DBI]{dbGetInfo}}, \code{\link[DBI]{dbListTables}}, \code{\link[DBI]{dbReadTable}}. } \examples{\dontrun{ drv <- dbDriver("PostgreSQL") con <- dbConnect(drv, user= "user", password="password", dbname="sample") dbListTables(con) rs <- dbSendQuery(con, query.sql) dbGetStatement(rs) dbHasCompleted(rs) info <- dbGetInfo(rs) names(dbGetInfo(drv)) # DBIConnection info names(dbGetInfo(con)) # DBIResult info names(dbGetInfo(rs)) } } \note{nullOk in \code{dbColumnInfo} was changed. Now it may be TRUE, FALSE, or NA; the column may be totally deleted in future releases;} \keyword{methods} \keyword{interface} \keyword{database} % vim: syntax=tex RPostgreSQL/man/PostgreSQL.Rd0000644000176000001440000000742111455242163015503 0ustar ripleyusers% $Id: PostgreSQL.Rd,v 0.1 2008/07/23 03:07:31 psk Exp $ \name{PostgreSQL} \alias{PostgreSQL} \title{ Instantiate a PostgreSQL client from the current R or S-Plus session } \description{ This function creates and initializes a PostgreSQL client. It returns an driver object that allows you to connect to one or several PostgreSQL servers. } \usage{ PostgreSQL(max.con = 16, fetch.default.rec = 500, force.reload = FALSE) } \arguments{ \item{max.con }{ Maximum number of connections that are intended to have open at one time. There's no intrinic limit, since strictly speaking this limit applies to PostgreSQL \emph{servers}, but clients can have (at least in theory) more than this. Typically there are at most a handful of open connections, thus the internal \code{RPostgreSQL} code uses a very simple linear search algorithm to manage its connection table. } \item{fetch.default.rec}{ number of records to fetch at one time from the database. (The \code{\link[DBI]{fetch}} method uses this number as a default.) } \item{force.reload}{ should the client code be reloaded (reinitialize)? Setting this to \code{TRUE} allows you to change default settings. Notice that all connections should be closed before re-loading. } } \value{ An object \code{PostgreSQLDriver} that extends \code{dbDriver} and \code{dbObjectId}. This object is required to create connections to one or several PostgreSQL database engines. } \section{Side Effects}{ The R/S-Plus client part of the database communication is initialized, but note that connecting to the database engine needs to be done through calls to \code{\link[DBI]{dbConnect}}. } \details{ This object is a singleton, that is, on subsequent invocations it returns the same initialized object. This implementation allows you to connect to multiple host servers and run multiple connections on each server simultaneously. } \section{User authentication}{ The passed string can be empty to use all default parameters, or it can contain one or more parameter settings separated by comma. Each parameter setting is in the form parameter = "value". Spaces around the equal sign are optional. The most important parameters are \code{user}, \code{password}, \code{host}, \code{dbname}, \code{port}, \code{tty} and \code{options}. } \author{David A. James} \section{References}{ See \url{stat.bell-labs.com/RS-DBI} for more details on the R/S-Plus database interface. See the documentation at the PostgreSQL Web site \url{http://www.postgresql.org} for details. } \seealso{ On database managers: \code{\link[DBI]{dbDriver}} \code{\link[DBI]{dbUnloadDriver}} On connections, SQL statements and resultSets: \code{\link[DBI]{dbConnect}} \code{\link[DBI]{dbDisconnect}} \code{\link[DBI]{dbSendQuery}} \code{\link[DBI]{dbGetQuery}} \code{\link[DBI]{fetch}} \code{\link[DBI]{dbClearResult}} On transaction management: \code{\link[DBI]{dbCommit}} \code{\link[DBI]{dbRollback}} On meta-data: \code{\link{summary}} \code{\link[DBI]{dbGetInfo}} \code{\link[DBI]{dbGetDBIVersion}} \code{\link[DBI]{dbListTables}} \code{\link[DBI]{dbListConnections}} \code{\link[DBI]{dbListResults}} \code{\link[DBI]{dbColumnInfo}} \code{\link[DBI]{dbGetException}} \code{\link[DBI]{dbGetStatement}} \code{\link[DBI]{dbHasCompleted}} \code{\link[DBI]{dbGetRowCount}} \code{\link[DBI]{dbGetRowsAffected}} } \examples{\dontrun{ # create a PostgreSQL instance and create one connection. > m <- dbDriver("PostgreSQL") > con <- dbConnect(m, user="username", password="passwd", dbname="database_name") > rs <- dbSendQuery(con, "select * sales where price < 10") > df <- fetch(rs, n = 50) > dbHasCompleted(rs) [1] FALSE > df2 <- fetch(rs, n = -1) > dbHasCompleted(rs) [1] TRUE > dbClearResult(rs) > dbListTables(con) } } \keyword{interface} \keyword{database} % vim: syntax=tex RPostgreSQL/man/PostgreSQLResult-class.Rd0000644000176000001440000000513511455242163020005 0ustar ripleyusers% $Id: PostgreSQLResult-class.Rd,v 0.1 2008/07/22 20:56:01 psk Exp $ \name{PostgreSQLResult-class} \docType{class} \alias{PostgreSQLResult-class} \title{Class PostgreSQLResult} \description{ PostgreSQL's query results class. This classes encapsulates the result of an SQL statement (either \code{select} or not). } \section{Generators}{ The main generator is \code{\link[DBI]{dbSendQuery}}. } \section{Extends}{ Class \code{"DBIResult"}, directly. Class \code{"PostgreSQLObject"}, directly. Class \code{"DBIObject"}, by class "DBIResult". Class \code{"dbObjectId"}, by class "PostgreSQLObject". } \section{Methods}{ \describe{ \item{\link{coerce}}{\code{signature(from = "PostgreSQLConnection", to = "PostgreSQLResult")}: ... } \item{\link[DBI]{dbClearResult}}{\code{signature(res = "PostgreSQLResult")}: ... } \item{\link[DBI]{dbColumnInfo}}{\code{signature(res = "PostgreSQLResult")}: ... } \item{\link[DBI]{dbGetException}}{\code{signature(conn = "PostgreSQLResult")}: ... } \item{\link[DBI]{dbGetInfo}}{\code{signature(dbObj = "PostgreSQLResult")}: ... } \item{\link[DBI]{dbGetRowCount}}{\code{signature(res = "PostgreSQLResult")}: ... } \item{\link[DBI]{dbGetRowsAffected}}{\code{signature(res = "PostgreSQLResult")}: ... } \item{\link[DBI]{dbGetStatement}}{\code{signature(res = "PostgreSQLResult")}: ... } \item{\link[DBI]{dbHasCompleted}}{\code{signature(res = "PostgreSQLResult")}: ... } \item{\link[DBI]{dbListFields}}{\code{signature(conn = "PostgreSQLResult", name = "missing")}: ... } \item{\link[DBI]{fetch}}{\code{signature(res = "PostgreSQLResult", n = "numeric")}: ... } \item{\link[DBI]{fetch}}{\code{signature(res = "PostgreSQLResult", n = "missing")}: ... } \item{\link{summary}}{\code{signature(object = "PostgreSQLResult")}: ... } } } \references{ See the Database Interface definition document \code{DBI.pdf} in the base directory of this package or \url{http://developer.r-project.org/db} } \seealso{ DBI base classes: \code{\link[DBI]{DBIObject-class}} \code{\link[DBI]{DBIDriver-class}} \code{\link[DBI]{DBIConnection-class}} \code{\link[DBI]{DBIResult-class}} PostgreSQL classes: \code{\link{PostgreSQLObject-class}} \code{\link{PostgreSQLDriver-class}} \code{\link{PostgreSQLConnection-class}} \code{\link{PostgreSQLResult-class}} } \examples{\dontrun{ drv <- dbDriver("PostgreSQL") con <- dbConnect(drv, dbname = "template1") ## rs is the result set rs <- dbSendQuery(con,"select * from sales") ## display the first three values of result set fetch(rs,n=3) } } \keyword{database} \keyword{interface} \keyword{classes} % vim: syntax=tex RPostgreSQL/man/PostgreSQLObject-class.Rd0000644000176000001440000000317611455242163017740 0ustar ripleyusers% $Id: PostgreSQLObject-class.Rd,v 0.1 2008/07/22 20:56:01 psk Exp $ \name{PostgreSQLObject-class} \docType{class} \alias{PostgreSQLObject-class} \title{Class PostgreSQLObject} \description{ Base class for all PostgreSQL-specific DBI classes } \section{Objects from the Class}{ A virtual Class: No objects may be created from it. } \section{Extends}{ Class \code{"DBIObject"}, directly. Class \code{"dbObjectId"}, directly. } \section{Methods}{ \describe{ \item{\link{coerce}}{\code{signature(from = "PostgreSQLObject", to = "PostgreSQLriver")}: ... } \item{\link[DBI]{dbDataType}}{\code{signature(dbObj = "PostgreSQLObject")}: ... } \item{\link[DBI]{isSQLKeyword}}{\code{signature(dbObj = "PostgreSQLObject", name = "character")}: ... } \item{\link[DBI]{make.db.names}}{\code{signature(dbObj = "PostgreSQLObject", snames = "character")}: ... } \item{\link[DBI]{SQLKeywords}}{\code{signature(dbObj = "PostgreSQLObject")}: ... } } } \references{ See the Database Interface definition document \code{DBI.pdf} in the base directory of this package or \url{http://developer.r-project.org/db}. } \seealso{ DBI base classes: \code{\link[DBI]{DBIObject-class}} \code{\link[DBI]{DBIDriver-class}} \code{\link[DBI]{DBIConnection-class}} \code{\link[DBI]{DBIResult-class}} PostgreSQL classes: \code{\link{PostgreSQLObject-class}} \code{\link{PostgreSQLDriver-class}} \code{\link{PostgreSQLConnection-class}} \code{\link{PostgreSQLResult-class}} } \examples{\dontrun{ drv <- dbDriver("PostgreSQL") con <- dbConnect(drv, dbname = "template1") } } \keyword{database} \keyword{interface} \keyword{classes} % vim: syntax=tex RPostgreSQL/man/dbSendQuery-methods.Rd0000644000176000001440000000346611637765112017401 0ustar ripleyusers% $Id: dbSendQuery-methods.Rd,v 0.1 2008/07/23 02:38:31 psk Exp $ \name{dbSendQuery-methods} \docType{methods} \alias{dbSendQuery-methods} \alias{dbGetQuery-methods} \alias{dbClearResult-methods} \alias{dbGetException-methods} \alias{dbSendQuery,PostgreSQLConnection,character-method} \alias{dbGetQuery,PostgreSQLConnection,character-method} \alias{dbClearResult,PostgreSQLResult-method} \alias{dbGetException,PostgreSQLConnection-method} \alias{dbGetException,PostgreSQLResult-method} \title{ Execute a statement on a given database connection } \description{ These methods are straight-forward implementations of the corresponding generic functions. However, for complex data like array are just transferred as a string instead of the corresponding vector in R. This behavior will change in future releases, and the author is advised not to rely on it. } \section{Methods}{\describe{ \item{conn}{ an \code{PostgreSQLConnection} object. } \item{statement}{a character vector of length 1 with the SQL statement.} \item{res}{an \code{PostgreSQLResult} object.} \item{\dots }{additional parameters.} } } \references{ See the Database Interface definition document \code{DBI.pdf} in the base directory of this package or \url{http://stat.bell-labs.com/RS-DBI}. } \seealso{ \code{\link{PostgreSQL}}, \code{\link[DBI]{dbDriver}}, \code{\link[DBI]{dbConnect}}, \code{\link[DBI]{fetch}}, \code{\link[DBI]{dbCommit}}, \code{\link[DBI]{dbGetInfo}}, \code{\link[DBI]{dbReadTable}}. } \examples{\dontrun{ drv <- dbDriver("PostgreSQL") con <- dbConnect(drv, "usr", "password", "dbname") res <- dbSendQuery(con, "SELECT * from sales") data <- fetch(res, n = -1) # alternatively, use dbGetQuery data <- dbGetQuery(con, "SELECT * from sales") } } \keyword{methods} \keyword{interface} \keyword{database} % vim: syntax=tex RPostgreSQL/man/dbCommit-methods.Rd0000644000176000001440000000315112005446536016675 0ustar ripleyusers% $Id: dbCommit-methods.Rd,v 0.1 2008/08/10 18:04:01 psk Exp $ \name{dbCommit-methods} \docType{methods} \alias{dbCommit-methods} \alias{dbRollback-methods} \alias{PostgreSQLConnection-method} \alias{dbCommit,PostgreSQLConnection-method} \alias{dbRollback,PostgreSQLConnection-method} \title{ DBMS Transaction Management } \description{ Commits or roll backs the current transaction in an PostgreSQL connection. \code{dbCommit} and \code{dbRollback} commit and rollback the transaction, respectively. } \section{Methods}{\describe{ \item{conn}{a \code{PostgreSQLConnection} object, as produced by the function \code{dbConnect}.} \item{\dots }{currently unused.} } } \references{ See the Database Interface definition document \code{DBI.pdf} in the base directory of this package or \url{http://stat.bell-labs.com/RS-DBI}. } \seealso{ \code{\link{PostgreSQL}}, \code{\link[DBI]{dbConnect}}, \code{\link[DBI]{dbSendQuery}}, \code{\link[DBI]{dbGetQuery}}, \code{\link[DBI]{fetch}}, \code{\link[DBI]{dbCommit}}, \code{\link[DBI]{dbGetInfo}}, \code{\link[DBI]{dbReadTable}}. } \examples{\dontrun{ drv <- dbDriver("PostgreSQL") con <- dbConnect(drv, dbname="postgres") dbGetQuery(con, "select count(*) from sales") dbGetQuery(con, "BEGIN TRANSACTION") rs <- dbSendQuery(con, "Delete * from sales as p where p.cost>10") if(dbGetInfo(rs, what = "rowsAffected") > 250){ warning("Rolling back transaction") dbRollback(con) }else{ dbCommit(con) } dbGetQuery(con, "select count(*) from sales") dbDisconnect(con) } } \keyword{methods} \keyword{interface} \keyword{database} % vim: syntax=tex RPostgreSQL/man/dbListTables-methods.Rd0000644000176000001440000000271711455242163017520 0ustar ripleyusers% $Id: dbListTables-methods.Rd,v 0.1 2008/08/10 18:04:01 psk Exp $ \name{dbListTables-methods} \docType{methods} \alias{dbListTables-methods} \alias{dbListFields-methods} \alias{dbListConnections-methods} \alias{dbListResults-methods} \alias{dbListTables,PostgreSQLConnection-method} \alias{dbListFields,PostgreSQLConnection,character-method} \alias{dbListFields,PostgreSQLResult,missing-method} \alias{dbListConnections,PostgreSQLDriver-method} \alias{dbListResults,PostgreSQLConnection-method} \title{ List items from an PostgreSQL DBMS and from objects } \description{ These methods are straight-forward implementations of the corresponding generic functions. } \section{Methods}{\describe{ \item{drv}{an \code{PostgreSQLDriver}.} \item{conn}{an \code{PostgreSQLConnection}.} \item{name}{a character string with the table name.} \item{\dots}{currently not used.} } } \references{ See the Database Interface definition document \code{DBI.pdf} in the base directory of this package or \url{http://stat.bell-labs.com/RS-DBI}. } \seealso{ \code{\link{PostgreSQL}}, \code{\link[DBI]{dbGetInfo}}, \code{\link[DBI]{dbColumnInfo}}, \code{\link[DBI]{dbDriver}}, \code{\link[DBI]{dbConnect}}, \code{\link[DBI]{dbSendQuery}} } \examples{\dontrun{ drv <- dbDriver("PostgreSQL") # after working awhile... for(con in dbListConnections(drv)){ dbGetStatement(dbListResults(con)) } } } \keyword{methods} \keyword{interface} \keyword{database} % vim: syntax=tex RPostgreSQL/R/0000755000176000001440000000000012124517222012626 5ustar ripleyusersRPostgreSQL/R/PostgreSQLSupport.R0000644000176000001440000007054312060130033016350 0ustar ripleyusers ## PostgreSQLSupport.R ## $Id: PostgreSQLSupport.R 243 2012-12-06 14:26:41Z tomoakin@kenroku.kanazawa-u.ac.jp $ ## This package was developed as a part of Summer of Code program organized by Google. ## Thanks to David A. James & Saikat DebRoy, the authors of RMySQL package. ## Code from RMySQL package was reused with the permission from the authors. ## Also Thanks to my GSoC mentor Dirk Eddelbuettel for helping me in the development. ## create a PostgreSQL database connection manager. By default we allow ## up to "max.con" connections and single fetches of up to "fetch.default.rec" ## records. These settings may be changed by re-loading the driver ## using the "force.reload" = T flag (note that this will close all ## currently open connections). ## Returns an object of class "PostgreSQLManger". ## Note: This class is a singleton. postgresqlInitDriver <- function(max.con=16, fetch.default.rec = 500, force.reload=FALSE) { if(fetch.default.rec<=0) stop("default num of records per fetch must be positive") config.params <- as.integer(c(max.con, fetch.default.rec)) force <- as.logical(force.reload) drvId <- .Call("RS_PostgreSQL_init", config.params, force, PACKAGE = .PostgreSQLPkgName) new("PostgreSQLDriver", Id = drvId) } postgresqlCloseDriver <- function(drv, ...) { if(!isPostgresqlIdCurrent(drv)) return(TRUE) drvId <- as(drv, "integer") .Call("RS_PostgreSQL_closeManager", drvId, PACKAGE = .PostgreSQLPkgName) } ## Print out nicely a brief description of the connection Driver postgresqlDescribeDriver <- function(obj, verbose = FALSE, ...) { info <- dbGetInfo(obj) print(obj) cat(" Driver name: ", info$drvName, "\n") cat(" Max connections:", info$length, "\n") cat(" Conn. processed:", info$counter, "\n") cat(" Default records per fetch:", info$"fetch_default_rec", "\n") if(verbose){ cat(" DBI API version: ", dbGetDBIVersion(), "\n") ## cat(" PostgreSQL client version: ", info$clientVersion, "\n") Feature absent } cat(" Open connections:", info$"num_con", "\n") if(verbose && !is.null(info$connectionIds)){ for(i in seq(along = info$connectionIds)){ cat(" ", i, " ") print(info$connectionIds[[i]]) } } invisible(NULL) } postgresqlDriverInfo <- function(obj, what="", ...) { if(!isPostgresqlIdCurrent(obj)) stop(paste("expired", class(obj))) drvId <- as(obj, "integer") info <- .Call("RS_PostgreSQL_managerInfo", drvId, PACKAGE = .PostgreSQLPkgName) ## replace drv/connection id w. actual drv/connection objects conObjs <- vector("list", length = info$"num_con") ids <- info$connectionIds for(i in seq(along = ids)) conObjs[[i]] <- new("PostgreSQLConnection", Id = c(drvId, ids[i])) info$connectionIds <- conObjs info$managerId <- new("PostgreSQLDriver", Id = drvId) if(!missing(what)) info[what] else info } ## note that dbname may be a database name, an empty string "", or NULL. ## The distinction between "" and NULL is that "" is interpreted by ## the PostgreSQL API as the default database (PostgreSQL config specific) ## while NULL means "no database". postgresqlNewConnection <- function(drv, user = "", password = "", host = "", dbname = "", port = "", tty = "", options = "", forceISOdate=TRUE) { if(!isPostgresqlIdCurrent(drv)) stop("expired manager") if(is.null(user)) stop("user argument cannot be NULL") if(is.null(password)) stop("password argument cannot be NULL") if(is.null(dbname)) stop("dbname argument cannot be NULL") if(is.null(port)) stop("port argument cannot be NULL") if(is.null(tty)) stop("tty argument cannot be NULL") con.params <- as.character(c(user, password, host, dbname, port, tty, options)) drvId <- as(drv, "integer") conId <- .Call("RS_PostgreSQL_newConnection", drvId, con.params, PACKAGE = .PostgreSQLPkgName) con <- new("PostgreSQLConnection", Id = conId) if(forceISOdate){ dbGetQuery(con, "set datestyle to ISO") } con } postgresqlCloneConnection <- function(con, ...) { if(!isPostgresqlIdCurrent(con)) stop(paste("expired", class(con))) conId <- as(con, "integer") newId <- .Call("RS_PostgreSQL_cloneConnection", conId, PACKAGE = .PostgreSQLPkgName) new("PostgreSQLConnection", Id = newId) } postgresqlDescribeConnection <- function(obj, verbose = FALSE, ...) { info <- dbGetInfo(obj) print(obj) cat(" User:", info$user, "\n") cat(" Host:", info$host, "\n") cat(" Dbname:", info$dbname, "\n") ## cat(" Connection type:", info$conType, "\n") function absent if(verbose){ cat(" PostgreSQL server version: ", info$serverVersion, "\n") ## cat(" PostgreSQL client version: ", ## dbGetInfo(as(obj, "PostgreSQLDriver"), what="clientVersion")[[1]], "\n") feature absent cat(" PostgreSQL protocol version: ", info$protocolVersion, "\n") cat(" PostgreSQL server thread id: ", info$threadId, "\n") } if (length(info$rsId)>0) { for (i in seq(along = info$rsId)) { cat(" ", i, " ") print(info$rsId[[i]]) } } else { cat(" No resultSet available\n") } invisible(NULL) } postgresqlCloseConnection <- function(con, ...) { if(!isPostgresqlIdCurrent(con)) return(TRUE) rs <- dbListResults(con) if(length(rs)>0){ if(dbHasCompleted(rs[[1]])) dbClearResult(rs[[1]]) else stop("connection has pending rows (close open results set first)") } conId <- as(con, "integer") .Call("RS_PostgreSQL_closeConnection", conId, PACKAGE = .PostgreSQLPkgName) } postgresqlConnectionInfo <- function(obj, what="", ...) { if(!isPostgresqlIdCurrent(obj)) stop(paste("expired", class(obj), deparse(substitute(obj)))) id <- as(obj, "integer") info <- .Call("RS_PostgreSQL_connectionInfo", id, PACKAGE = .PostgreSQLPkgName) rsId <- vector("list", length = length(info$rsId)) for(i in seq(along = info$rsId)) rsId[[i]] <- new("PostgreSQLResult", Id = c(id, info$rsId[i])) info$rsId <- rsId if(!missing(what)) info[what] else info } ## checks for any open resultsets, and closes them if completed. ## the statement is then executed on the connection, and returns ## whether it executed without an error or not. postgresqlTransactionStatement <- function(con, statement) { ## are there resultSets pending on con? if(length(dbListResults(con)) > 0){ res <- dbListResults(con)[[1]] if(!dbHasCompleted(res)){ stop("connection with pending rows, close resultSet before continuing") } dbClearResult(res) } rc <- try(dbGetQuery(con, statement)) !inherits(rc, ErrorClass) } ## submits the sql statement to PostgreSQL and creates a ## dbResult object if the SQL operation does not produce ## output, otherwise it produces a resultSet that can ## be used for fetching rows. postgresqlExecStatement <- function(con, statement, params, ...) { if(!isPostgresqlIdCurrent(con)) stop(paste("expired", class(con))) conId <- as(con, "integer") statement <- as(statement, "character") if(missing(params)){ rsId <- .Call("RS_PostgreSQL_exec", conId, statement, PACKAGE = .PostgreSQLPkgName) }else{ rsId <- .External("RS_PostgreSQL_pqexecparams", conId, statement, as(params, "character"), ..., PACKAGE = .PostgreSQLPkgName) } new("PostgreSQLResult", Id = rsId) } postgresqlEscapeStrings <- function(con, preescapedstring) { conId <- as(con, "integer") preescapedstring <- as(preescapedstring, "character") escapedstring <- .Call("RS_PostgreSQL_escape", conId, preescapedstring, PACKAGE = .PostgreSQLPkgName) return(escapedstring) } postgresqlpqExec <- function(con, statement) { if(!isPostgresqlIdCurrent(con)) stop(paste("expired", class(con))) conId <- as(con, "integer") statement <- as(statement, "character") .Call("RS_PostgreSQL_pqexec", conId, statement, PACKAGE = .PostgreSQLPkgName) } postgresqlpqExecParams <- function(con, statement, ...) { if(!isPostgresqlIdCurrent(con)) stop(paste("expired", class(con))) conId <- as(con, "integer") statement <- as(statement, "character") .External("RS_PostgreSQL_pqexecparams", conId, statement, ..., PACKAGE = .PostgreSQLPkgName) } postgresqlCopyIn <- function(con, filename) { if(!isPostgresqlIdCurrent(con)) stop(paste("expired", class(con))) conId <- as(con, "integer") filename <- as(filename, "character") .Call("RS_PostgreSQL_CopyIn", conId, filename, PACKAGE = .PostgreSQLPkgName) } postgresqlCopyInDataframe <- function(con, dataframe) { if(!isPostgresqlIdCurrent(con)) stop(paste("expired", class(con))) conId <- as(con, "integer") nrow <- nrow(dataframe) p <- ncol(dataframe) .Call("RS_PostgreSQL_CopyInDataframe", conId, dataframe, nrow, p , PACKAGE = .PostgreSQLPkgName) } postgresqlgetResult <- function(con) { if(!isPostgresqlIdCurrent(con)) stop(paste("expired", class(con))) conId <- as(con, "integer") rsId <- .Call("RS_PostgreSQL_getResult", conId, PACKAGE = .PostgreSQLPkgName) new("PostgreSQLResult", Id = rsId) } ## helper function: it exec's *and* retrieves a statement. It should ## be named somehting else. postgresqlQuickSQL <- function(con, statement, ...) { if(!isPostgresqlIdCurrent(con)) stop(paste("expired", class(con))) rsList <- dbListResults(con) if (length(rsList)>0){ # clear results dbClearResult(rsList[[1]]) } rs <- try(dbSendQuery(con, statement, ...)) if (inherits(rs, ErrorClass)){ warning("Could not create execute", statement) return(NULL) } if(dbHasCompleted(rs)){ dbClearResult(rs) ## no records to fetch, we're done invisible() return(NULL) } res <- fetch(rs, n = -1) if(dbHasCompleted(rs)) dbClearResult(rs) else warning("pending rows") res } postgresqlDescribeFields <- function(res, ...) { flds <- dbGetInfo(res, "fieldDescription")[[1]][[1]] if(!is.null(flds)){ flds$Sclass <- .Call("RS_DBI_SclassNames", flds$Sclass, PACKAGE = .PostgreSQLPkgName) ## ------- ## This is actually a bug introduced deliberately. In dbGetInfo, it displays the Sclass for Date/Time datatypes in Pg ## as character. But in dbColumnInfo, it displays it as 'POSIXct'. This is because there is no ## datatype corresponding to Date/Time defined in R-defines.h & R-internals.h for(i in 1:length(flds$type)) { if(flds$type[[i]] == 1114) { flds$Sclass[[i]] = "POSIXct"; } else if(flds$type[[i]] == 1082) { flds$Sclass[[i]] = "Date"; } else if(flds$type[[i]] == 1184) { flds$Sclass[[i]] = "POSIXct"; } } ## ------- flds$type <- .Call("RS_PostgreSQL_typeNames", as.integer(flds$type), PACKAGE = .PostgreSQLPkgName) ## no factors structure(flds, row.names = paste(seq(along=flds$type)), class = "data.frame") } else data.frame(flds) } ## (Experimental) ## This function is meant to handle somewhat gracefully(?) large amounts ## of data from the DBMS by bringing into R manageable chunks (about ## batchSize records at a time, but not more than maxBatch); the idea ## is that the data from individual groups can be handled by R, but ## not all the groups at the same time. ## ## dbApply apply functions to groups of rows coming from a remote ## database resultSet upon the following fetching events: ## begin (prior to fetching the first record) ## group.begin (the record just fetched begins a new group) ## new_record (a new record just fetched) ## group.end (the record just fetched ends the current group) ## end (the record just fetched is the very last record) ## ## The "begin", "begin.group", etc., specify R functions to be ## invoked upon the corresponding events. (For compatibility ## with other apply functions the arg FUN is used to specify the ## most common case where we only specify the "group.end" event.) ## ## The following describes the exact order and form of invocation for the ## various callbacks in the underlying C code. All callback function ## (except FUN) are optional. ## begin() ## group.begin(group.name) ## new.record(df.record) ## FUN(df.group, group.name) (aka group.end) ## end() ## ## TODO: (1) add argument output=F/T to suppress the creation of ## an expensive(?) output list. ## (2) allow INDEX to be a list as in tapply() ## (3) should we implement a simplify argument, as in sapply()? ## (4) should report (instead of just warning) when we're forced ## to handle partial groups (groups larger than maxBatch). ## (5) extend to the case where even individual groups are too ## big for R (as in incrementatl quantiles). ## (6) Highly R-dependent, not sure yet how to port it to S-plus. ## postgresqlDBApply <- function(res, INDEX, FUN = stop("must specify FUN"), begin = NULL, group.begin = NULL, new.record = NULL, end = NULL, batchSize = 100, maxBatch = 1e6, ..., simplify = TRUE) { if(dbHasCompleted(res)) stop("result set has completed") if(is.character(INDEX)){ flds <- tolower(as.character(dbColumnInfo(res)$name)) INDEX <- match(tolower(INDEX[1]), flds, 0) } if(INDEX<1) stop(paste("INDEX field", INDEX, "not in result set")) null.or.fun <- function(fun) { # get fun obj, but a NULL is ok if(is.null(fun)) fun else match.fun(fun) } begin <- null.or.fun(begin) group.begin <- null.or.fun(group.begin) group.end <- null.or.fun(FUN) ## probably this is the most important end <- null.or.fun(end) new.record <- null.or.fun(new.record) rsId <- as(res, "integer") con <- as(res, "PostgreSQLConnection") on.exit({ rc <- dbGetException(con) if(!is.null(rc$errorNum) && rc$errorNum!=0) cat("dbApply aborted with PostgreSQL error ", rc$errorNum, " (", rc$errorMsg, ")\n", sep = "") }) ## BEGIN event handler (re-entrant, only prior to reading first row) if(!is.null(begin) && dbGetRowCount(res)==0) begin() rho <- environment() funs <- list(begin = begin, end = end, group.begin = group.begin, group.end = group.end, new.record = new.record) out <- .Call("RS_PostgreSQL_dbApply", rs = rsId, INDEX = as.integer(INDEX-1), funs, rho, as.integer(batchSize), as.integer(maxBatch), PACKAGE = .PostgreSQLPkgName) if(!is.null(end) && dbHasCompleted(res)) end() out } ## Fetch at most n records from the opened resultSet (n = -1 means ## all records, n=0 means extract as many as "default_fetch_rec", ## as defined by PostgreSQLDriver (see describe(drv, T)). ## The returned object is a data.frame. ## Note: The method dbHasCompleted() on the resultSet tells you whether ## or not there are pending records to be fetched. ## ## TODO: Make sure we don't exhaust all the memory, or generate ## an object whose size exceeds option("object.size"). Also, ## are we sure we want to return a data.frame? postgresqlFetch <- function(res, n=0, ...) { n <- as(n, "integer") rsId <- as(res, "integer") rel <- .Call("RS_PostgreSQL_fetch", rsId, nrec = n, PACKAGE = .PostgreSQLPkgName) if(length(rel)==0 || length(rel[[1]])==0) return(NULL) ## create running row index as of previous fetch (if any) cnt <- dbGetRowCount(res) nrec <- length(rel[[1]]) indx <- seq(from = cnt - nrec + 1, length = nrec) attr(rel, "row.names") <- as.integer(indx) if(usingR()) class(rel) <- "data.frame" else oldClass(rel) <- "data.frame" flds <- dbGetInfo(res)$fieldDescription[[1]]$type for(i in 1:length(flds)) { if(flds[[i]] == 1114) { ## 1114 corresponds to Timestamp without TZ (mapped to POSIXct class) rel[,i] <- as.POSIXct(rel[,i]) } else if(flds[[i]] == 1082) { ## 1082 corresponds to Date (mapped to Date class) rel[,i] <- as.Date(rel[,i]) } else if(flds[[i]] == 1184) { ## 1184 corresponds to Timestamp with TimeZone rel[,i] <- as.POSIXct(sub('([+-]..)$', '\\100', sub(':(..)$','\\1' ,rel[,i])), format="%Y-%m-%d %H:%M:%OS%z") } } rel } ## Note that originally we had only resultSet both for SELECTs ## and INSERTS, ... Later on we created a base class dbResult ## for non-Select SQL and a derived class resultSet for SELECTS. postgresqlResultInfo <- function(obj, what = "", ...) { if(!isPostgresqlIdCurrent(obj)) stop(paste("expired", class(obj), deparse(substitute(obj)))) id <- as(obj, "integer") info <- .Call("RS_PostgreSQL_resultSetInfo", id, PACKAGE = .PostgreSQLPkgName) if(!missing(what)) info[what] else info } postgresqlDescribeResult <- function(obj, verbose = FALSE, ...) { if(!isPostgresqlIdCurrent(obj)){ print(obj) invisible(return(NULL)) } print(obj) cat(" Statement:", dbGetStatement(obj), "\n") cat(" Has completed?", if(dbHasCompleted(obj)) "yes" else "no", "\n") cat(" Affected rows:", dbGetRowsAffected(obj), "\n") cat(" Rows fetched:", dbGetRowCount(obj), "\n") flds <- dbColumnInfo(obj) if(verbose && !is.null(flds)){ cat(" Fields:\n") out <- print(dbColumnInfo(obj)) } invisible(NULL) } postgresqlCloseResult <- function(res, ...) { if(!isPostgresqlIdCurrent(res)) return(TRUE) rsId <- as(res, "integer") .Call("RS_PostgreSQL_closeResultSet", rsId, PACKAGE = .PostgreSQLPkgName) } ## Use NULL, "", or 0 as row.names to prevent using any field as row.names. postgresqlReadTable <- function(con, name, row.names = "row.names", check.names = TRUE, ...) { out <- dbGetQuery(con, paste("SELECT * from", postgresqlTableRef(name))) if(check.names) names(out) <- make.names(names(out), unique = TRUE) ## should we set the row.names of the output data.frame? nms <- names(out) j <- switch(mode(row.names), "character" = if(row.names=="") 0 else match(tolower(row.names), tolower(nms), nomatch = if(missing(row.names)) 0 else -1), "numeric" = row.names, "NULL" = 0, 0) if(j==0) return(out) if(j<0 || j>ncol(out)){ warning("row.names not set on output data.frame (non-existing field)") return(out) } rnms <- as.character(out[,j]) if(all(!duplicated(rnms))){ out <- out[,-j, drop = FALSE] row.names(out) <- rnms } else warning("row.names not set on output (duplicate elements in field)") out } postgresqlImportFile <- function(con, name, value, field.types = NULL, overwrite = FALSE, append = FALSE, header, row.names, nrows = 50, sep = ",", eol="\n", skip = 0, quote = '"', ...) { if(overwrite && append) stop("overwrite and append cannot both be TRUE") new.con <- con if(dbExistsTable(con,name)){ if(overwrite){ if(!dbRemoveTable(con, name)){ warning(paste("table", name, "couldn't be overwritten")) return(FALSE) } } else if(!append){ warning(paste("table", name, "exists in database: aborting dbWriteTable")) return(FALSE) } } ## compute full path name (have R expand ~, etc) fn <- file.path(dirname(value), basename(value)) if(missing(header) || missing(row.names)){ f <- file(fn, open="r") if(skip>0) readLines(f, n=skip) txtcon <- textConnection(readLines(f, n=2)) flds <- count.fields(txtcon, sep) close(txtcon) close(f) nf <- length(unique(flds)) } if(missing(header)){ header <- nf==2 } if(missing(row.names)){ if(header) row.names <- if(nf==2) TRUE else FALSE else row.names <- FALSE } new.table <- !dbExistsTable(con, name) if(new.table){ ## need to init table, say, with the first nrows lines d <- read.table(fn, sep=sep, header=header, skip=skip, nrows=nrows, ...) sql <- postgresqlBuildTableDefinition(new.con, name, obj=d, field.types = field.types, row.names = row.names) rs <- try(dbSendQuery(new.con, sql)) if(inherits(rs, ErrorClass)){ warning("could not create table: aborting postgresqlImportFile") return(FALSE) } else dbClearResult(rs) } else if(!append){ warning(sprintf("table %s already exists -- use append=TRUE?", name)) } fmt <- paste("COPY %s FROM '%s' ","WITH DELIMITER AS '%s' ", if(!is.null(quote)) "CSV QUOTE AS '%s'", sep="") if(is.null(quote)) sql <- sprintf(fmt, name,fn, sep) else sql <- sprintf(fmt, name,fn, sep, quote) rs <- try(dbSendQuery(new.con, sql)) if(inherits(rs, ErrorClass)){ warning("could not load data into table") return(FALSE) } dbClearResult(rs) TRUE } ## Create table "name" (must be an SQL identifier) and populate ## it with the values of the data.frame "value" ## TODO: This function should execute its sql as a single transaction, ## and allow converter functions. ## TODO: In the unlikely event that value has a field called "row_names" ## we could inadvertently overwrite it (here the user should set ## row.names=F) I'm (very) reluctantly adding the code re: row.names, ## because I'm not 100% comfortable using data.frames as the basic ## data for relations. postgresqlWriteTable <- function(con, name, value, field.types, row.names = TRUE, overwrite = FALSE, append = FALSE, ..., allow.keywords = FALSE) { if(overwrite && append) stop("overwrite and append cannot both be TRUE") if(!is.data.frame(value)) value <- as.data.frame(value) if(row.names){ value <- cbind(row.names(value), value) ## can't use row.names= here names(value)[1] <- "row.names" } if(missing(field.types) || is.null(field.types)){ ## the following mapping should be coming from some kind of table ## also, need to use converter functions (for dates, etc.) field.types <- sapply(value, dbDataType, dbObj = con) } i <- match("row.names", names(field.types), nomatch=0) if(i>0) ## did we add a row.names value? If so, it's a text field. ## MODIFIED -- Sameer field.types[i] <- dbDataType(dbObj=con, field.types[row.names]) new.con <- con if(dbExistsTable(con,name)){ if(overwrite){ if(!dbRemoveTable(con, name)){ warning(paste("table", name, "couldn't be overwritten")) return(FALSE) } } else if(!append){ warning(paste("table",name,"exists in database: aborting assignTable")) return(FALSE) } } if(!dbExistsTable(con,name)){ ## need to re-test table for existance ## need to create a new (empty) table sql1 <- paste("create table ", postgresqlTableRef(name), "\n(\n\t", sep="") sql2 <- paste(paste(postgresqlQuoteId(names(field.types)), field.types), collapse=",\n\t", sep="") sql3 <- "\n)\n" sql <- paste(sql1, sql2, sql3, sep="") rs <- try(dbSendQuery(new.con, sql)) if(inherits(rs, ErrorClass)){ warning("could not create table: aborting assignTable") return(FALSE) } else { dbClearResult(rs) } } ## convert columns we can't handle in C code value[] <- lapply(value, function(z) { if(is.object(z) && !is.factor(z)) as.character(z) else z }) oldenc <- dbGetQuery(new.con, "SHOW client_encoding") postgresqlpqExec(new.con, "SET CLIENT_ENCODING TO 'UTF8'") sql4 <- paste("COPY", postgresqlTableRef(name), "FROM STDIN") postgresqlpqExec(new.con, sql4) postgresqlCopyInDataframe(new.con, value) rs<-postgresqlgetResult(new.con) retv <- TRUE if (inherits(rs, ErrorClass)) { warning("could not load data into table") retv <- FALSE } dbClearResult(rs) sql5 <- paste("SET CLIENT_ENCODING TO '", oldenc, "'", sep="") dbGetQuery(new.con, sql5) retv } postgresqlBuildTableDefinition <- function(dbObj, name, obj, field.types = NULL, row.names = TRUE, ...) { if(!is.data.frame(obj)) obj <- as.data.frame(obj) if(!is.null(row.names) && row.names){ obj <- cbind(row.names(obj), obj) ## can't use row.names= here names(obj)[1] <- "row.names" } if(is.null(field.types)){ ## the following mapping should be coming from some kind of table ## also, need to use converter functions (for dates, etc.) field.types <- sapply(obj, dbDataType, dbObj = dbObj) } i <- match("row.names", names(field.types), nomatch=0) if(i>0) ## did we add a row.names value? If so, it's a text field. field.types[i] <- dbDataType(dbObj, field.types$row.names) ## need to create a new (empty) table flds <- paste(postgresqlQuoteId(names(field.types)), field.types) paste("CREATE TABLE", postgresqlTableRef(name), "\n(", paste(flds, collapse=",\n\t"), "\n)") } ## find a suitable SQL data type for the R/S object obj ## TODO: Lots and lots!! (this is a very rough first draft) ## need to register converters, abstract out PostgreSQL and generalize ## to Oracle, Informix, etc. Perhaps this should be table-driven. ## NOTE: PostgreSQL data types differ from the SQL92 (e.g., varchar truncate ## trailing spaces). postgresqlDataType <- function(obj, ...) { rs.class <- data.class(obj) if(rs.class=="numeric"){ sql.type <- if(class(obj)=="integer") "integer" else "float8" } else { sql.type <- switch(rs.class, character = "text", logical = "bool", factor = "text", ordered = "text", Date = "date", POSIXct = "timestamp with time zone", "text") } sql.type } postgresqlQuoteId <- function(identifiers){ ret <- paste('"', gsub('"','""',identifiers), '"', sep="") ret } postgresqlTableRef <- function(identifiers){ ret <- paste('"', gsub('"','""',identifiers), '"', sep="", collapse=".") ret } ## the following reserved words were taken from ["RESERVED" of postgres colomn in ] Table C.1 in Appendix C ## of the PostgreSQL Manual 8.3.1. .PostgreSQLKeywords <- c("ALL", "ANALYSE", "ANALYZE", "AND", "ANY", "ARRAY", "AS", "ASC", "ASYMMETRIC", "AUTHORIZATION", "BETWEEN", "BINARY", "BOTH", "CASE", "CAST", "CHECK", "COLLATE", "COLUMN", "CONSTRAINT", "CREATE", "CROSS", "CURRENT_DATE", "CURRENT_ROLE", "CURRENT_TIME", "CURRENT_TIMESTAMP", "CURRENT_USER", "DEFAULT", "DEFERRABLE", "DESC", "DISTINCT", "DO", "ELSE", "END", "EXCEPT", "FALSE", "FOR", "FOREIGN", "FREEZE", "FROM", "FULL", "GRANT", "GROUP", "HAVING", "ILIKE", "IN", "INITIALLY", "INNER","INTERSECT", "INTO", "IS", "ISNULL", "JOIN", "LEADING", "LEFT", "LIKE", "LIMIT", "LOCALTIME", "LOCALTIMESTAMP", "NATURAL", "NEW", "NOT", "NULL", "OFF", "OFFSET", "OLD", "ON", "ONLY", "OR", "ORDER", "OUTER", "OVERLAPS", "PLACING", "PRIMARY", "REFERENCES", "RESERVED", "SELECT", "SESSION_USER", "SIMILAR", "SOME", "SYMMETRIC", "TABLE", "THEN", "TO", "TRAILING", "TRUE", "UNION", "UNIQUE", "USER", "USING", "VERBOSE", "WHEN", "WHERE", "WITH" ) RPostgreSQL/R/dbObjectId.R0000644000176000001440000000424511667154566014772 0ustar ripleyusers## Class: dbObjectId ## $Id: dbObjectId.R 220 2011-12-03 12:50:46Z tomoakin@kenroku.kanazawa-u.ac.jp $ ## This package was developed as a part of Summer of Code program organized by Google. ## Thanks to David A. James & Saikat DebRoy, the authors of RMySQL package. ## Code from RMySQL package was reused with the permission from the authors. ## Also Thanks to my GSoC mentor Dirk Eddelbuettel for helping me in the development. ## ## This mixin helper class is NOT part of the database interface definition, ## but it is extended by the Oracle, MySQL,PostgreSQL and SQLite implementations ## to allow us to conviniently (and portably) ## implement all database foreign objects methods (i.e., methods for show(), ## print() format() the dbManger, dbConnection, dbResultSet, etc.) ## A dbObjectId is an identifier into an actual remote database objects. ## This class and its derived classes Object need to ## be VIRTUAL to avoid coercion (green book, p.293) during method dispatching. setClass("dbObjectId", representation(Id = "integer", "VIRTUAL")) ## coercion methods setAs("dbObjectId", "integer", def = function(from) as(slot(from,"Id"), "integer") ) setAs("dbObjectId", "numeric", def = function(from) as(slot(from, "Id"), "integer") ) setAs("dbObjectId", "character", def = function(from) as(slot(from, "Id"), "character") ) ## formating, showing, printing,... setMethod("format", "dbObjectId", def = function(x, ...) { paste("(", paste(as(x, "integer"), collapse=","), ")", sep="") }, valueClass = "character" ) setMethod("show", "dbObjectId", def = function(object) print(object)) setMethod("print", "dbObjectId", def = function(x, ...){ expired <- if(isPostgresqlIdCurrent(x)) "" else "Expired " str <- paste("<", expired, class(x), ":", format(x), ">", sep="") cat(str, "\n") invisible(NULL) } ) ## verify that obj refers to a currently open/loaded database isPostgresqlIdCurrent <- function(obj) { obj <- as(obj, "integer") .Call("RS_DBI_validHandle", obj, PACKAGE = .PostgreSQLPkgName) } RPostgreSQL/R/S4R.R0000644000176000001440000000137111642043011013355 0ustar ripleyusers## R/S-Plus compatibility ## $Id: S4R.R 189 2011-10-01 13:16:39Z dirk.eddelbuettel $ ## This package was developed as a part of Summer of Code program organized by Google. ## Thanks to David A. James & Saikat DebRoy, the authors of RMySQL package. ## Code from RMySQL package was reused with the permission from the authors. ## Also Thanks to my GSoC mentor Dirk Eddelbuettel for helping me in the development. usingR <- function(major=0, minor=0){ if(is.null(version$language)) return(FALSE) if(version$language!="R") return(FALSE) version$major>=major && version$minor>=minor } ## constant holding the appropriate error class returned by try() if(usingR()){ ErrorClass <- "try-error" } else { ErrorClass <- "Error" } RPostgreSQL/R/PostgreSQL.R0000644000176000001440000003275011677047676015012 0ustar ripleyusers## PostgreSQL.R ## $Id: PostgreSQL.R 223 2011-12-29 11:31:45Z tomoakin@kenroku.kanazawa-u.ac.jp $ ## This package was developed as a part of Summer of Code program organized by Google. ## Thanks to David A. James & Saikat DebRoy, the authors of RMySQL package. ## Code from RMySQL package was reused with the permission from the authors. ## Also Thanks to my GSoC mentor Dirk Eddelbuettel for helping me in the development. ## ## Constants ## ##.PostgreSQLRCS <- "$Id: PostgreSQL.R,v 0.1 2008/06/10 14:00:00$" .PostgreSQLPkgName <- "RPostgreSQL" .PostgreSQLVersion <- "0.3-0" ##package.description(.PostgreSQLPkgName, fields = "Version") .PostgreSQL.NA.string <- "\\N" ## on input, PostgreSQL interprets \N as NULL (NA) setOldClass("data.frame") ## to appease setMethod's signature warnings... ## ## Class: DBIObject ## setClass("PostgreSQLObject", representation("DBIObject", "dbObjectId", "VIRTUAL")) ## ## Class: dbDriver ## PostgreSQL <- function(max.con=16, fetch.default.rec = 500, force.reload=FALSE) { postgresqlInitDriver(max.con = max.con, fetch.default.rec = fetch.default.rec, force.reload = force.reload) } ## ## Class: DBIDriver ## setClass("PostgreSQLDriver", representation("DBIDriver", "PostgreSQLObject")) ## coerce (extract) any PostgreSQLObject into a PostgreSQLDriver setAs("PostgreSQLObject", "PostgreSQLDriver", def = function(from) new("PostgreSQLDriver", Id = as(from, "integer")[1:2]) ) setMethod("dbUnloadDriver", "PostgreSQLDriver", def = function(drv, ...) postgresqlCloseDriver(drv, ...), valueClass = "logical" ) setMethod("dbGetInfo", "PostgreSQLDriver", def = function(dbObj, ...) postgresqlDriverInfo(dbObj, ...) ) setMethod("dbListConnections", "PostgreSQLDriver", def = function(drv, ...) dbGetInfo(drv, "connectionIds")[[1]] ) setMethod("summary", "PostgreSQLDriver", def = function(object, ...) postgresqlDescribeDriver(object, ...) ) ## ## Class: DBIConnection ## setClass("PostgreSQLConnection", representation("DBIConnection", "PostgreSQLObject")) setMethod("dbConnect", "PostgreSQLDriver", def = function(drv, ...) postgresqlNewConnection(drv, ...), valueClass = "PostgreSQLConnection" ) setMethod("dbConnect", "character", def = function(drv, ...) postgresqlNewConnection(dbDriver(drv), ...), valueClass = "PostgreSQLConnection" ) ## clone a connection setMethod("dbConnect", "PostgreSQLConnection", def = function(drv, ...) postgresqlCloneConnection(drv, ...), valueClass = "PostgreSQLConnection" ) setMethod("dbDisconnect", "PostgreSQLConnection", def = function(conn, ...) postgresqlCloseConnection(conn, ...), valueClass = "logical" ) setGeneric("dbEscapeStrings", def = function(conn, string, ...) standardGeneric("dbEscapeStrings")) setMethod("dbEscapeStrings", signature(conn="PostgreSQLConnection", string="character"), def = function(conn, string, ...) postgresqlEscapeStrings(conn, string, ...), valueClass = "character" ) setMethod("dbSendQuery", signature(conn = "PostgreSQLConnection", statement = "character"), def = function(conn, statement,...) postgresqlExecStatement(conn, statement,...), valueClass = "PostgreSQLResult" ) setMethod("dbGetQuery", signature(conn = "PostgreSQLConnection", statement = "character"), def = function(conn, statement, ...) postgresqlQuickSQL(conn, statement, ...) ) setMethod("dbGetException", "PostgreSQLConnection", def = function(conn, ...){ if(!isPostgresqlIdCurrent(conn)) stop(paste("expired", class(conn))) .Call("RS_PostgreSQL_getException", as(conn, "integer"), PACKAGE = .PostgreSQLPkgName) }, valueClass = "list" ) setMethod("dbGetInfo", "PostgreSQLConnection", def = function(dbObj, ...) postgresqlConnectionInfo(dbObj, ...) ) setMethod("dbListResults", "PostgreSQLConnection", def = function(conn, ...) dbGetInfo(conn, "rsId")[[1]] ) setMethod("summary", "PostgreSQLConnection", def = function(object, ...) postgresqlDescribeConnection(object, ...) ) ## convenience methods setMethod("dbListTables", "PostgreSQLConnection", def = function(conn, ...){ out <- dbGetQuery(conn, paste("select tablename from pg_tables where schemaname !='information_schema'", "and schemaname !='pg_catalog'", ...)) if (is.null(out) || nrow(out) == 0) out <- character(0) else out <- out[, 1] out }, valueClass = "character" ) setMethod("dbReadTable", signature(conn="PostgreSQLConnection", name="character"), def = function(conn, name, ...) postgresqlReadTable(conn, name, ...), valueClass = "data.frame" ) setMethod("dbWriteTable", signature(conn="PostgreSQLConnection", name="character", value="data.frame"), def = function(conn, name, value, ...){ postgresqlWriteTable(conn, name, value, ...) }, valueClass = "logical" ) ## write table from filename (TODO: connections) setMethod("dbWriteTable", signature(conn="PostgreSQLConnection", name="character", value="character"), def = function(conn, name, value, ...){ postgresqlImportFile(conn, name, value, ...) }, valueClass = "logical" ) setMethod("dbExistsTable", signature(conn="PostgreSQLConnection", name="character"), def = function(conn, name, ...){ qlength <- length(name) if(qlength == 1){ currentschema <- dbGetQuery(conn, "SELECT current_schema()") res <- dbGetQuery(conn, paste("select tablename from pg_tables where ", "schemaname !='information_schema' and schemaname !='pg_catalog' ", "and schemaname='", postgresqlEscapeStrings(conn, currentschema[[1]]), "' ", "and tablename='", postgresqlEscapeStrings(conn, name), "'", sep="")) } else{ if(qlength == 2){ res <- dbGetQuery(conn, paste("select tablename from pg_tables where ", "schemaname !='information_schema' and schemaname !='pg_catalog' ", "and schemaname='", postgresqlEscapeStrings(conn, name[1]), "' ", "and tablename='", postgresqlEscapeStrings(conn, name[2]), "'", sep="")) } } return(as.logical(dim(res)[1])) }, valueClass = "logical" ) setMethod("dbRemoveTable", signature(conn="PostgreSQLConnection", name="character"), def = function(conn, name, ...){ if(dbExistsTable(conn, name)){ rc <- try(dbGetQuery(conn, paste("DROP TABLE", postgresqlTableRef(name)))) !inherits(rc, ErrorClass) } else FALSE }, valueClass = "logical" ) ## return field names (no metadata) setMethod("dbListFields", signature(conn="PostgreSQLConnection", name="character"), def = function(conn, name, ...){ qlength <- length(name) if(qlength == 1){ currentschema <- dbGetQuery(conn, "SELECT current_schema()") flds <- dbGetQuery(conn, paste("select a.attname from pg_attribute a, pg_class c, pg_tables t, pg_namespace nsp", " where a.attrelid = c.oid and c.relname = tablename and c.relnamespace = nsp.oid and a.attnum > 0 and ", "nspname = current_schema() and schemaname = nspname and ", "tablename = '", postgresqlEscapeStrings(conn, name), "'", sep=""))[,1] } else{ if(qlength == 2){ flds <- dbGetQuery(conn, paste("select a.attname from pg_attribute a, pg_class c, pg_tables t, pg_namespace nsp", " where a.attrelid = c.oid and c.relname = t.tablename and c.relnamespace = nsp.oid and a.attnum > 0 and ", "nspname = schemaname ", "and schemaname = '", postgresqlEscapeStrings(conn, name[1]), "' ", "and tablename = '", postgresqlEscapeStrings(conn, name[2]), "'", sep=""))[,1] } } if(length(flds)==0) flds <- character() flds }, valueClass = "character" ) setMethod("dbCallProc", "PostgreSQLConnection", def = function(conn, ...) .NotYetImplemented() ) setMethod("dbCommit", "PostgreSQLConnection", def = function(conn, ...) postgresqlTransactionStatement(conn, "COMMIT") ) setMethod("dbRollback", "PostgreSQLConnection", def = function(conn, ...) { rsList <- dbListResults(conn) if (length(rsList)) dbClearResult(rsList[[1]]) postgresqlTransactionStatement(conn, "ROLLBACK") } ) ## ## Class: DBIResult ## setClass("PostgreSQLResult", representation("DBIResult", "PostgreSQLObject")) setAs("PostgreSQLResult", "PostgreSQLConnection", def = function(from) new("PostgreSQLConnection", Id = as(from, "integer")[1:3]) ) setAs("PostgreSQLResult", "PostgreSQLDriver", def = function(from) new("PostgreSQLDriver", Id = as(from, "integer")[1:2]) ) setMethod("dbClearResult", "PostgreSQLResult", def = function(res, ...) postgresqlCloseResult(res, ...), valueClass = "logical" ) setMethod("fetch", signature(res="PostgreSQLResult", n="numeric"), def = function(res, n, ...){ out <- postgresqlFetch(res, n, ...) if(is.null(out)) out <- data.frame(out) out }, valueClass = "data.frame" ) setMethod("fetch", signature(res="PostgreSQLResult", n="missing"), def = function(res, n, ...){ out <- postgresqlFetch(res, n=0, ...) if(is.null(out)) out <- data.frame(out) out }, valueClass = "data.frame" ) setMethod("dbGetInfo", "PostgreSQLResult", def = function(dbObj, ...) postgresqlResultInfo(dbObj, ...), valueClass = "list" ) setMethod("dbGetStatement", "PostgreSQLResult", def = function(res, ...){ st <- dbGetInfo(res, "statement")[[1]] if(is.null(st)) st <- character() st }, valueClass = "character" ) setMethod("dbListFields", signature(conn="PostgreSQLResult", name="missing"), def = function(conn, name, ...){ flds <- dbGetInfo(conn, "fields")$fields$name if(is.null(flds)) flds <- character() flds }, valueClass = "character" ) setMethod("dbColumnInfo", "PostgreSQLResult", def = function(res, ...) postgresqlDescribeFields(res, ...), valueClass = "data.frame" ) setMethod("dbGetRowsAffected", "PostgreSQLResult", def = function(res, ...) dbGetInfo(res, "rowsAffected")[[1]], valueClass = "numeric" ) setMethod("dbGetRowCount", "PostgreSQLResult", def = function(res, ...) dbGetInfo(res, "rowCount")[[1]], valueClass = "numeric" ) setMethod("dbHasCompleted", "PostgreSQLResult", def = function(res, ...) dbGetInfo(res, "completed")[[1]] == 1, valueClass = "logical" ) setMethod("dbGetException", "PostgreSQLResult", def = function(conn, ...){ id <- as(conn, "integer")[1:2] .Call("RS_PostgreSQL_getException", id, PACKAGE = .PostgreSQLPkgName) }, valueClass = "list" ## TODO: should be a DBIException? ) setMethod("summary", "PostgreSQLResult", def = function(object, ...) postgresqlDescribeResult(object, ...) ) setMethod("dbDataType", signature(dbObj = "PostgreSQLObject", obj = "ANY"), def = function(dbObj, obj, ...) postgresqlDataType(obj, ...), valueClass = "character" ) ## MODIFIED : -- sameer setMethod("make.db.names", signature(dbObj="PostgreSQLObject", snames = "character"), def = function(dbObj, snames,keywords,unique, allow.keywords,...){ postgresqlQuoteId(snames) }, valueClass = "character" ) setMethod("SQLKeywords", "PostgreSQLObject", def = function(dbObj, ...) .PostgreSQLKeywords, valueClass = "character" ) setMethod("isSQLKeyword", signature(dbObj="PostgreSQLObject", name="character"), def = function(dbObj, name,keywords,case, ...){ isSQLKeyword.default(name, keywords = .PostgreSQLKeywords) }, valueClass = "character" ) ## extension to the DBI 0.1-4 setGeneric("dbApply", def = function(res, ...) standardGeneric("dbApply")) setMethod("dbApply", "PostgreSQLResult", def = function(res, ...) postgresqlDBApply(res, ...), ) RPostgreSQL/R/zzz.R0000644000176000001440000000073411642043011013604 0ustar ripleyusers## zzz.R ## $Id: zzz.R 189 2011-10-01 13:16:39Z dirk.eddelbuettel $ ## This package was developed as a part of Summer of Code program organized by Google. ## Thanks to David A. James & Saikat DebRoy, the authors of RMySQL package. ## Code from RMySQL package was reused with the permission from the authors. ## Also Thanks to my GSoC mentor Dirk Eddelbuettel for helping me in the development. .onLoad <- function(lib, pkg) { library.dynam("RPostgreSQL", pkg, lib) } RPostgreSQL/config.guess0000755000176000001440000012674511663676122015000 0ustar ripleyusers#! /bin/sh # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, # 2011 Free Software Foundation, Inc. timestamp='2011-10-19' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA # 02110-1301, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Per Bothner. Please send patches (context # diff format) to and include a ChangeLog # entry. # # This script attempts to guess a canonical system name similar to # config.sub. If it succeeds, it prints the system name on stdout, and # exits with 0. Otherwise, it exits with 1. # # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ; set_cc_for_build= ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; *:SolidBSD:*:*) echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} exit ;; macppc:MirBSD:*:*) echo powerpc-unknown-mirbsd${UNAME_RELEASE} exit ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE="alpha" ;; "EV4.5 (21064)") UNAME_MACHINE="alpha" ;; "LCA4 (21066/21068)") UNAME_MACHINE="alpha" ;; "EV5 (21164)") UNAME_MACHINE="alphaev5" ;; "EV5.6 (21164A)") UNAME_MACHINE="alphaev56" ;; "EV5.6 (21164PC)") UNAME_MACHINE="alphapca56" ;; "EV5.7 (21164PC)") UNAME_MACHINE="alphapca57" ;; "EV6 (21264)") UNAME_MACHINE="alphaev6" ;; "EV6.7 (21264A)") UNAME_MACHINE="alphaev67" ;; "EV6.8CB (21264C)") UNAME_MACHINE="alphaev68" ;; "EV6.8AL (21264B)") UNAME_MACHINE="alphaev68" ;; "EV6.8CX (21264D)") UNAME_MACHINE="alphaev68" ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE="alphaev69" ;; "EV7 (21364)") UNAME_MACHINE="alphaev7" ;; "EV7.9 (21364A)") UNAME_MACHINE="alphaev79" ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` # Reset EXIT trap before exiting to avoid spurious non-zero exit code. exitcode=$? trap '' 0 exit $exitcode ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit ;; arm:riscos:*:*|arm:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; s390x:SunOS:*:*) echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) echo i386-pc-auroraux${UNAME_RELEASE} exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) eval $set_cc_for_build SUN_ARCH="i386" # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH="x86_64" fi fi echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`$dummy $dummyarg` && { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos${UNAME_RELEASE} exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` then echo "$SYSTEM_NAME" else echo rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit ;; *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = "hppa2.0w" ] then eval $set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH="hppa2.0w" else HP_ARCH="hppa64" fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`/usr/bin/uname -p` case ${UNAME_PROCESSOR} in amd64) echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; *) echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; esac exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; i*:windows32*:*) # uname -m includes "-pc" on this system. echo ${UNAME_MACHINE}-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; *:Interix*:*) case ${UNAME_MACHINE} in x86) echo i586-pc-interix${UNAME_RELEASE} exit ;; authenticamd | genuineintel | EM64T) echo x86_64-unknown-interix${UNAME_RELEASE} exit ;; IA64) echo ia64-unknown-interix${UNAME_RELEASE} exit ;; esac ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit ;; 8664:Windows_NT:*) echo x86_64-pc-mks exit ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; *:GNU:*:*) # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} exit ;; arm*:Linux:*:*) eval $set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then echo ${UNAME_MACHINE}-unknown-linux-gnu else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then echo ${UNAME_MACHINE}-unknown-linux-gnueabi else echo ${UNAME_MACHINE}-unknown-linux-gnueabihf fi fi exit ;; avr32*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; cris:Linux:*:*) echo cris-axis-linux-gnu exit ;; crisv32:Linux:*:*) echo crisv32-axis-linux-gnu exit ;; frv:Linux:*:*) echo frv-unknown-linux-gnu exit ;; hexagon:Linux:*:*) echo hexagon-unknown-linux-gnu exit ;; i*86:Linux:*:*) LIBC=gnu eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __dietlibc__ LIBC=dietlibc #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` echo "${UNAME_MACHINE}-pc-linux-${LIBC}" exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; mips:Linux:*:* | mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef ${UNAME_MACHINE} #undef ${UNAME_MACHINE}el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=${UNAME_MACHINE}el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=${UNAME_MACHINE} #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } ;; or32:Linux:*:*) echo or32-unknown-linux-gnu exit ;; padre:Linux:*:*) echo sparc-unknown-linux-gnu exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-gnu exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-gnu ;; PA8*) echo hppa2.0-unknown-linux-gnu ;; *) echo hppa-unknown-linux-gnu ;; esac exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-gnu exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-gnu exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux exit ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; tile*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; vax:Linux:*:*) echo ${UNAME_MACHINE}-dec-linux-gnu exit ;; x86_64:Linux:*:*) echo x86_64-unknown-linux-gnu exit ;; xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit ;; i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configury will decide that # this is a cross-build. echo i586-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. echo ${UNAME_MACHINE}-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. echo i586-pc-haiku exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit ;; SX-7:SUPER-UX:*:*) echo sx7-nec-superux${UNAME_RELEASE} exit ;; SX-8:SUPER-UX:*:*) echo sx8-nec-superux${UNAME_RELEASE} exit ;; SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux${UNAME_RELEASE} exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown case $UNAME_PROCESSOR in i386) eval $set_cc_for_build if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then UNAME_PROCESSOR="x86_64" fi fi ;; unknown) UNAME_PROCESSOR=powerpc ;; esac echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; NEO-?:NONSTOP_KERNEL:*:*) echo neo-tandem-nsk${UNAME_RELEASE} exit ;; NSE-?:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit ;; i*86:skyos:*:*) echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' exit ;; i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos exit ;; i*86:AROS:*:*) echo ${UNAME_MACHINE}-pc-aros exit ;; esac #echo '(No uname command or uname output not recognized.)' 1>&2 #echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 eval $set_cc_for_build cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix\n"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) # if !defined (ultrix) # include # if defined (BSD) # if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); # else # if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); # else printf ("vax-dec-bsd\n"); exit (0); # endif # endif # else printf ("vax-dec-bsd\n"); exit (0); # endif # else printf ("vax-dec-ultrix\n"); exit (0); # endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; c34*) echo c34-convex-bsd exit ;; c38*) echo c38-convex-bsd exit ;; c4*) echo c4-convex-bsd exit ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: RPostgreSQL/configure.in0000644000176000001440000000657212124512710014745 0ustar ripleyusers# Process this file with autoconf to produce a configure script. # # Configure.in for RPostgreSQL # Copyright (C) 2008 Dirk Eddelbuettel and licensed under GNU GPL # # This file draws heavily on configure.in files from littler, RMySQL, and RdbiPgSQL # Set the name and version -- the version set here will propagate to other files from here AC_INIT(RPostgreSQL, 0.2) # Checks for common programs using default macros AC_PROG_CC AC_CANONICAL_HOST AC_CANONICAL_TARGET case "${host_os}" in darwin*) R_OS_TYPE="darwin" ;; esac # Check for non-standard programs: pg_config(1) to configure PostgreSQL builds AC_PATH_PROG([PG_CONFIG], [pg_config]) # By default, we will not use the accompanied libpq ENABLE_LIBPQ= # If pg_config was found, let's use it if test "${PG_CONFIG}" != ""; then # Use pg_config for header and linker arguments PG_INCDIR=`${PG_CONFIG} --includedir` PG_LIBDIR=`${PG_CONFIG} --libdir` else # let's look around -- code copied from RdbuiPgSQL but modified to use test -f # added fink standard install location Neil 8/30/2009 AC_MSG_NOTICE([checking for PostgreSQL header files]) if ! test $PG_INCDIR then for dir in \ /usr/include \ /usr/include/pgsql \ /usr/include/postgresql \ /usr/local/include \ /usr/local/include/pgsql \ /usr/local/include/postgresql \ /usr/local/pgsql/include \ /usr/local/postgresql/include \ /opt/include \ /opt/include/pgsql \ /opt/include/postgresql \ /opt/local/include \ /opt/local/include/postgresql \ /opt/local/include/postgresql84 \ /sw/opt/postgresql-8.4/include \ /Library/PostgresPlus/8.4SS/include \ /sw/include/postgresql do AC_MSG_NOTICE([Checking include ${dir}.]) if test -f ${dir}/libpq-fe.h then PG_INCDIR=${dir} break fi done fi # likewise, let's look around for libpq.so if ! test $PG_LIBDIR then for dir in \ /usr/lib \ /usr/lib/pgsql \ /usr/lib/postgresql \ /usr/local/lib \ /usr/local/lib/pgsql \ /usr/local/lib/postgresql \ /usr/local/pgsql/lib \ /usr/local/postgresql/lib \ /opt/lib \ /opt/lib/pgsql \ /opt/lib/postgresql \ /opt/local/lib \ /opt/local/lib/postgresql \ /opt/local/lib/postgresql84 \ /sw/opt/postgresql-8.4/lib \ /Library/PostgresPlus/8.4SS/lib \ /sw/lib do AC_MSG_NOTICE([Checking lib ${dir}.]) if test -f ${dir}/libpq.so then PG_LIBDIR=${dir} break fi if test -f ${dir}/libpq.dylib then PG_LIBDIR=${dir} break fi done fi if ! test $PG_LIBDIR then if test "$R_OS_TYPE" = "darwin" ; then # in case we cannot find any libpq library we will use the accompanied libpq # This content would be written into src/Makevars at the end of this script ENABLE_LIBPQ=' PKG_CPPFLAGS=-Ilibpq PKG_LIBS=libpq/libpq.a .PHONY: all all: $(SHLIB) $(SHLIB): libpq/libpq.5.dylib libpq/libpq.5.dylib: (cd libpq; $(MAKE) CC="$(CC)" CFLAGS="$(CFLAGS)" -f Makefile.darwin) clean: (cd libpq; $(MAKE) -f Makefile.darwin clean) ' fi fi fi # Expand into arguments PKG_CPPFLAGS="-I${PG_INCDIR}" PKG_LIBS="-L${PG_LIBDIR} -lpq" # Test for sanity by looking for libpq-fe.h, no explicit action on found, error on failure AC_CHECK_FILE(["${PG_INCDIR}/libpq-fe.h"], , AC_SUBST(R_OS_TYPE)) # Now substitute these two variable in src/Makevars.in to create src/Makevars AC_SUBST(PKG_CPPFLAGS) AC_SUBST(PKG_LIBS) AC_SUBST(ENABLE_LIBPQ) AC_OUTPUT(src/Makevars) RPostgreSQL/tests/0000755000176000001440000000000012124517222013567 5ustar ripleyusersRPostgreSQL/tests/dbColumnInfo.R0000644000176000001440000000275412033425425016303 0ustar ripleyusers ## dbWriteTable test ## ## Assumes that ## a) PostgreSQL is running, and ## b) the current user can connect ## both of which are not viable for release but suitable while we test ## ## Dirk Eddelbuettel, 10 Sep 2009 ## only run this if this env.var is set correctly if (Sys.getenv("POSTGRES_USER") != "" & Sys.getenv("POSTGRES_HOST") != "" & Sys.getenv("POSTGRES_DATABASE") != "") { ## try to load our module and abort if this fails stopifnot(require(RPostgreSQL)) ## load the PostgresSQL driver drv <- dbDriver("PostgreSQL") ## connect to the default db con <- dbConnect(drv, user=Sys.getenv("POSTGRES_USER"), password=Sys.getenv("POSTGRES_PASSWD"), host=Sys.getenv("POSTGRES_HOST"), dbname=Sys.getenv("POSTGRES_DATABASE"), port=ifelse((p<-Sys.getenv("POSTGRES_PORT"))!="", p, 5432)) # create a table res <- dbGetQuery(con, "CREATE TABLE aa (pk integer primary key, v1 float not null, v2 float)" ) ## run a simple query and show the query result res <- dbGetQuery(con, "INSERT INTO aa VALUES(3, 2, NULL)" ) res <- dbSendQuery(con, "select pk, v1, v2, v1+v2 from aa") cat("dbColumnInfo\n") gctorture() print(dbColumnInfo(res)) print(dbColumnInfo(res)) cat("SELECT result\n") df <- fetch(res, n=-1) print(df) ## cleanup cat("Removing \"AA\"\n") dbRemoveTable(con, "aa") ## and disconnect dbDisconnect(con) } RPostgreSQL/tests/dbTransactionTests.Rout.save0000644000176000001440000000755212124517166021235 0ustar ripleyusers R version 2.15.2 (2012-10-26) -- "Trick or Treat" Copyright (C) 2012 The R Foundation for Statistical Computing ISBN 3-900051-07-0 Platform: x86_64-unknown-linux-gnu (64-bit) R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. R is a collaborative project with many contributors. Type 'contributors()' for more information and 'citation()' on how to cite R or R packages in publications. Type 'demo()' for some demos, 'help()' for on-line help, or 'help.start()' for an HTML browser interface to help. Type 'q()' to quit R. > > ## dbWriteTable test > ## > ## Assumes that > ## a) PostgreSQL is running, and > ## b) the current user can connect > ## both of which are not viable for release but suitable while we test > ## > ## Dirk Eddelbuettel, 10 Sep 2009 > > ## only run this if this env.var is set correctly > if (Sys.getenv("POSTGRES_USER") != "" & Sys.getenv("POSTGRES_HOST") != "" & Sys.getenv("POSTGRES_DATABASE") != "") { + + ## try to load our module and abort if this fails + stopifnot(require(RPostgreSQL)) + stopifnot(require(datasets)) + + ## load the PostgresSQL driver + drv <- dbDriver("PostgreSQL") + + ## create two independent connections + con1 <- dbConnect(drv, + user=Sys.getenv("POSTGRES_USER"), + password=Sys.getenv("POSTGRES_PASSWD"), + host=Sys.getenv("POSTGRES_HOST"), + dbname=Sys.getenv("POSTGRES_DATABASE"), + port=ifelse((p<-Sys.getenv("POSTGRES_PORT"))!="", p, 5432)) + + con2 <- dbConnect(drv, + user=Sys.getenv("POSTGRES_USER"), + password=Sys.getenv("POSTGRES_PASSWD"), + host=Sys.getenv("POSTGRES_HOST"), + dbname=Sys.getenv("POSTGRES_DATABASE"), + port=ifelse((p<-Sys.getenv("POSTGRES_PORT"))!="", p, 5432)) + + + if (dbExistsTable(con1, "rockdata")) { + cat("Removing rockdata\n") + dbRemoveTable(con1, "rockdata") + } + + cat("begin transaction in con1\n") + dbGetQuery(con1, "BEGIN TRANSACTION") + cat("create table rockdata in con1\n") + dbWriteTable(con1, "rockdata", rock) + if (dbExistsTable(con1, "rockdata")) { + cat("PASS rockdata is visible through con1\n") + }else{ + cat("FAIL rockdata is invisible through con1\n") + } + if (dbExistsTable(con2, "rockdata")) { + cat("FAIL rockdata is visible through con2\n") + }else{ + cat("PASS rockdata is invisible through con2\n") + } + cat("commit in con1\n") + dbCommit(con1) + if (dbExistsTable(con2, "rockdata")) { + cat("PASS rockdata is visible through con2\n") + }else{ + cat("FAIL rockdata is invisible through con2\n") + } + + cat("remove the table from con1\n") + dbRemoveTable(con1, "rockdata") + + if (dbExistsTable(con2, "rockdata")) { + cat("FAIL rockdata is visible through con2\n") + }else{ + cat("PASS rockdata is invisible through con2\n") + } + + cat("begin transaction in con1\n") + dbGetQuery(con1, "BEGIN TRANSACTION") + cat("create table rockdata in con1\n") + dbWriteTable(con1, "rockdata", rock) + if (dbExistsTable(con1, "rockdata")) { + cat("PASS rockdata is visible through con1\n") + }else{ + cat("FAIL rockdata is invisible through con1\n") + } + cat("RollBack con1\n") + dbRollback(con1) + if (dbExistsTable(con1, "rockdata")) { + cat("FAIL rockdata is visible through con1\n") + }else{ + cat("PASS rockdata is invisible through con1\n") + } + + ## and disconnect + dbDisconnect(con2) + dbDisconnect(con1) + } > > proc.time() user system elapsed 0.139 0.020 0.143 RPostgreSQL/tests/datetimestampwrite.Rout.save0000644000176000001440000000664312124517166021333 0ustar ripleyusers R version 2.15.2 (2012-10-26) -- "Trick or Treat" Copyright (C) 2012 The R Foundation for Statistical Computing ISBN 3-900051-07-0 Platform: x86_64-unknown-linux-gnu (64-bit) R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. R is a collaborative project with many contributors. Type 'contributors()' for more information and 'citation()' on how to cite R or R packages in publications. Type 'demo()' for some demos, 'help()' for on-line help, or 'help.start()' for an HTML browser interface to help. Type 'q()' to quit R. > ## Test of data types, based on earlier version in inst/devTests > ## > ## Dirk Eddelbuettel, 21 Oct 2008 > > if ((Sys.getenv("POSTGRES_USER") != "") & + (Sys.getenv("POSTGRES_HOST") != "") & + (Sys.getenv("POSTGRES_DATABASE") != "")) { + + ## try to load our module and abort if this fails + stopifnot(require(RPostgreSQL)) + + ## load the PostgresSQL driver + drv <- dbDriver("PostgreSQL") + ## can't print result as it contains process id which changes print(summary(drv)) + + ## connect to the default db + con <- dbConnect(drv, + user=Sys.getenv("POSTGRES_USER"), + password=Sys.getenv("POSTGRES_PASSWD"), + host=Sys.getenv("POSTGRES_HOST"), + dbname=Sys.getenv("POSTGRES_DATABASE"), + port=ifelse((p<-Sys.getenv("POSTGRES_PORT"))!="", p, 5432)) + + if (dbExistsTable(con, "tempostgrestable")) + dbRemoveTable(con, "tempostgrestable") + + ## Test the numeric mapping + dbGetQuery(con, "create table tempostgrestable (intcolumn date, floatcolumn timestamp with time zone);") + + sql <- paste("insert into tempostgrestable ", + "values ('2011-03-07', '2011-03-07 16:30:39') ") + res <- dbGetQuery(con, sql) + + dat <- dbReadTable(con, "tempostgrestable") + dbRemoveTable(con, "tempostgrestable") + cat("Read Date and TIMESTAMP values\n") + + ## now test the types of the colums we got + if( class(dat[1,1]) == "Date" ){ + cat("PASS -- Date type is as expected\n") + }else{ + cat("FAIL -- Date type is other than Date: ") + cat(class(dat[1,1])) + cat("\n") + } + if( class(dat[1,2])[1] == "POSIXct" ){ + cat("PASS -- TIMESTAMP is received as POSIXct\n") + }else{ + cat("FAIL -- TIMESTAMP is other than POSIXct: ") + cat(class(dat[1,2])) + cat("\n") + } + + dbWriteTable(con, "tempostgrestable2", dat) + dat2 <- dbReadTable(con, "tempostgrestable2") + dbRemoveTable(con, "tempostgrestable2") + cat("Check that read after write gets the same data types\n") + + ## now test the types of the colums we got + if( class(dat2[1,1]) == "Date" ){ + cat("PASS -- Date type is as expected\n") + }else{ + cat("FAIL -- Date type is other than Date: ") + cat(class(dat2[1,1])) + cat("\n") + } + if( class(dat2[1,2])[1] == "POSIXct" ){ + cat("PASS -- TIMESTAMP is received as POSIXct\n") + }else{ + cat("FAIL -- TIMESTAMP is other than POSIXct: ") + cat(class(dat2[1,2])) + cat("\n") + } + + + dbDisconnect(con) + dbUnloadDriver(drv) + + cat("DONE\n") + } > > proc.time() user system elapsed 0.137 0.017 0.138 RPostgreSQL/tests/dataTypeTests.Rout.save0000644000176000001440000001074011637765112020212 0ustar ripleyusers R version 2.13.1 (2011-07-08) Copyright (C) 2011 The R Foundation for Statistical Computing ISBN 3-900051-07-0 Platform: x86_64-pc-linux-gnu (64-bit) R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. R is a collaborative project with many contributors. Type 'contributors()' for more information and 'citation()' on how to cite R or R packages in publications. Type 'demo()' for some demos, 'help()' for on-line help, or 'help.start()' for an HTML browser interface to help. Type 'q()' to quit R. > ## Test of data types, based on earlier version in inst/devTests > ## > ## Dirk Eddelbuettel, 21 Oct 2008 > > if ((Sys.getenv("POSTGRES_USER") != "") & + (Sys.getenv("POSTGRES_HOST") != "") & + (Sys.getenv("POSTGRES_DATABASE") != "")) { + + ## try to load our module and abort if this fails + stopifnot(require(RPostgreSQL)) + + ## load the PostgresSQL driver + drv <- dbDriver("PostgreSQL") + ## can't print result as it contains process id which changes print(summary(drv)) + + ## connect to the default db + con <- dbConnect(drv, + user=Sys.getenv("POSTGRES_USER"), + password=Sys.getenv("POSTGRES_PASSWD"), + host=Sys.getenv("POSTGRES_HOST"), + dbname=Sys.getenv("POSTGRES_DATABASE"), + port=ifelse((p<-Sys.getenv("POSTGRES_PORT"))!="", p, 5432)) + + if (dbExistsTable(con, "tempostgrestable")) + dbRemoveTable(con, "tempostgrestable") + + ## Test the numeric mapping + dbGetQuery(con, "create table tempostgrestable (intcolumn integer, floatcolumn float);") + + i <- as.integer(10) + j <- as.numeric(56.6) + + sql <- paste("insert into tempostgrestable ", + "values (",i, "," ,j ,") ", sep="") + res <- dbGetQuery(con, sql) + + + dat <- dbReadTable(con, "tempostgrestable") + dbRemoveTable(con, "tempostgrestable") + cat("Read Numeric values\n") + + ## now test the types of the colums we got + stopifnot( class(dat[,1]) == "integer" ) + stopifnot( class(dat[,2]) == "numeric" ) + cat("GOOD -- all numeric types are as expected\n") + + ## and test the values + stopifnot( identical( dat[1,1], i)) + stopifnot( identical( dat[1,2], j)) + cat("GOOD -- all numeric values are as expected\n") + + ## Test the logical mapping + if (dbExistsTable(con, "testlogical")) + dbRemoveTable(con, "testlogical") + dbGetQuery(con,"create table testlogical (col1 boolean, col2 boolean)") + + i <- as.logical(TRUE) + j <- as.logical(FALSE) + + sql <- paste("insert into testlogical ", + "values (",i, "," ,j ,") ", sep="") + res <- dbGetQuery(con, sql); + + dat <- dbReadTable(con, "testlogical") + dbRemoveTable(con, "testlogical") + cat("Read Logical values\n") + + ## now test the types of the colums we got + stopifnot( class(dat[,1]) == "logical" ) + stopifnot( class(dat[,2]) == "logical" ) + cat("GOOD -- all logical types are as expected\n") + + ## and test the values + stopifnot( identical( dat[1,1], i)) + stopifnot( identical( dat[1,2], j)) + cat("GOOD -- all logical values are as expected\n") + + ## Test the character mapping + if (dbExistsTable(con, "testchar")) + dbRemoveTable(con, "testchar") + dbGetQuery(con,"create table testchar (code char(3),city varchar(20),country text);") + + i <- as.character("IN") + j <- as.character("Hyderabad") + k <- as.character("India") + + sql <- paste("insert into testchar ", + "values ('",i,"' , '",j ,"' , '",k,"') ", sep="") + res <- dbGetQuery(con, sql); + + dat <- dbReadTable(con, "testchar") + cat("Read Character values\n") + + ## now test the types of the colums we got + stopifnot( class(dat[,1]) == "character" ) + stopifnot( class(dat[,2]) == "character" ) + stopifnot( class(dat[,3]) == "character" ) + cat("GOOD -- all character types are as expected\n") + + ## and test the values + ##stopifnot( identical( dat[1,1], i)) + stopifnot( identical( dat[1,2], j)) + stopifnot( identical( dat[1,3], k)) + cat("GOOD -- all character values are as expected\n") + + dbRemoveTable(con, "testchar") + dbRemoveTable(con, "tempostgrestable") + + dbDisconnect(con) + dbUnloadDriver(drv) + + cat("DONE\n") + } > RPostgreSQL/tests/selectWithAlias.Rout.save0000644000176000001440000000440711455443410020474 0ustar ripleyusers R version 2.11.1 (2010-05-31) Copyright (C) 2010 The R Foundation for Statistical Computing ISBN 3-900051-07-0 R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. R is a collaborative project with many contributors. Type 'contributors()' for more information and 'citation()' on how to cite R or R packages in publications. Type 'demo()' for some demos, 'help()' for on-line help, or 'help.start()' for an HTML browser interface to help. Type 'q()' to quit R. > > ## selectWithAlias test > ## > ## test for the 'Issue 1' on the Google Code issue log > ## this was reported in June and fixed by Joe Conway (svr committ r100) > ## > ## Assumes that > ## a) PostgreSQL is running, and > ## b) the current user can connect > ## both of which are not viable for release but suitable while we test > ## > ## Dirk Eddelbuettel, 03 Oct 2009 > > ## only run this if this env.var is set correctly > if (Sys.getenv("POSTGRES_USER") != "" & Sys.getenv("POSTGRES_HOST") != "" & Sys.getenv("POSTGRES_DATABASE") != "") { + + ## try to load our module and abort if this fails + stopifnot(require(RPostgreSQL)) + stopifnot(require(datasets)) + + ## load the PostgresSQL driver + drv <- dbDriver("PostgreSQL") + + ## connect to the default db + con <- dbConnect(drv, + user=Sys.getenv("POSTGRES_USER"), + password=Sys.getenv("POSTGRES_PASSWD"), + host=Sys.getenv("POSTGRES_HOST"), + dbname=Sys.getenv("POSTGRES_DATABASE"), + port=ifelse((p<-Sys.getenv("POSTGRES_PORT"))!="", p, 5432)) + + if (dbExistsTable(con, "rockdata")) { + print("Removing rockdata\n") + dbRemoveTable(con, "rockdata") + } + + dbWriteTable(con, "rockdata", rock) + + ## run a simple query and show the query result + res <- dbGetQuery(con, "select area as ar, peri as pe, shape as sh, perm as pr from rockdata limit 10") + print(res) + + ## cleanup + if (dbExistsTable(con, "rockdata")) { + print("Removing rockdata\n") + dbRemoveTable(con, "rockdata") + } + + ## and disconnect + dbDisconnect(con) + } > RPostgreSQL/tests/selectWithAlias.R0000644000176000001440000000312011455242162016777 0ustar ripleyusers ## selectWithAlias test ## ## test for the 'Issue 1' on the Google Code issue log ## this was reported in June and fixed by Joe Conway (svr committ r100) ## ## Assumes that ## a) PostgreSQL is running, and ## b) the current user can connect ## both of which are not viable for release but suitable while we test ## ## Dirk Eddelbuettel, 03 Oct 2009 ## only run this if this env.var is set correctly if (Sys.getenv("POSTGRES_USER") != "" & Sys.getenv("POSTGRES_HOST") != "" & Sys.getenv("POSTGRES_DATABASE") != "") { ## try to load our module and abort if this fails stopifnot(require(RPostgreSQL)) stopifnot(require(datasets)) ## load the PostgresSQL driver drv <- dbDriver("PostgreSQL") ## connect to the default db con <- dbConnect(drv, user=Sys.getenv("POSTGRES_USER"), password=Sys.getenv("POSTGRES_PASSWD"), host=Sys.getenv("POSTGRES_HOST"), dbname=Sys.getenv("POSTGRES_DATABASE"), port=ifelse((p<-Sys.getenv("POSTGRES_PORT"))!="", p, 5432)) if (dbExistsTable(con, "rockdata")) { print("Removing rockdata\n") dbRemoveTable(con, "rockdata") } dbWriteTable(con, "rockdata", rock) ## run a simple query and show the query result res <- dbGetQuery(con, "select area as ar, peri as pe, shape as sh, perm as pr from rockdata limit 10") print(res) ## cleanup if (dbExistsTable(con, "rockdata")) { print("Removing rockdata\n") dbRemoveTable(con, "rockdata") } ## and disconnect dbDisconnect(con) } RPostgreSQL/tests/dbExistsq.Rout.save0000644000176000001440000000473311455443410017357 0ustar ripleyusers R version 2.12.0 RC (2010-10-07 r53227) Copyright (C) 2010 The R Foundation for Statistical Computing ISBN 3-900051-07-0 Platform: x86_64-pc-linux-gnu (64-bit) R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. R is a collaborative project with many contributors. Type 'contributors()' for more information and 'citation()' on how to cite R or R packages in publications. Type 'demo()' for some demos, 'help()' for on-line help, or 'help.start()' for an HTML browser interface to help. Type 'q()' to quit R. > > ## dbExists test with schema name: reported as Issue 3 at > ## http://code.google.com/p/rpostgresql/issues/detail?id=3 > ## and based on an earlier email by Prasenjit Kapat > ## > ## Assumes that > ## a) PostgreSQL is running, and > ## b) the current user can connect > ## both of which are not viable for release but suitable while we test > ## > ## Dirk Eddelbuettel, 10 Sep 2009 > > ## only run this if this env.var is set correctly > if (Sys.getenv("POSTGRES_USER") != "" & Sys.getenv("POSTGRES_HOST") != "" & Sys.getenv("POSTGRES_DATABASE") != "") { + + ## try to load our module and abort if this fails + stopifnot(require(RPostgreSQL)) + stopifnot(require(datasets)) + + ## load the PostgresSQL driver + drv <- dbDriver("PostgreSQL") + + ## connect to the default db + con <- dbConnect(drv, + user=Sys.getenv("POSTGRES_USER"), + password=Sys.getenv("POSTGRES_PASSWD"), + host=Sys.getenv("POSTGRES_HOST"), + dbname=Sys.getenv("POSTGRES_DATABASE"), + port=ifelse((p<-Sys.getenv("POSTGRES_PORT"))!="", p, 5432)) + + if (dbExistsTable(con, "rock'data")) { + cat("Removing rock'data\n") + dbRemoveTable(con, "rock'data") + } + + cat("Write rock'data\n") + dbWriteTable(con, "rock'data", rock) + + ## run a simple dbExists + cat("Does rock'data exist? ") + print(res <- dbExistsTable(con, "rock'data")) + + ## this should return TRUE but did not -- does now after patch + cat("Does \"public.rock'data\" exist? ") + print(res <- dbExistsTable(con, "public.rock'data")) + + ## cleanup + if (dbExistsTable(con, "rock'data")) { + cat("Removing rock'data\n") + dbRemoveTable(con, "rock'data") + } + + ## and disconnect + dbDisconnect(con) + } > RPostgreSQL/tests/dbExistsIssue.R0000644000176000001440000000330311455305062016512 0ustar ripleyusers ## dbExists test with schema name: reported as Issue 3 at ## http://code.google.com/p/rpostgresql/issues/detail?id=3 ## and based on an earlier email by Prasenjit Kapat ## ## Assumes that ## a) PostgreSQL is running, and ## b) the current user can connect ## both of which are not viable for release but suitable while we test ## ## Dirk Eddelbuettel, 10 Sep 2009 ## only run this if this env.var is set correctly if (Sys.getenv("POSTGRES_USER") != "" & Sys.getenv("POSTGRES_HOST") != "" & Sys.getenv("POSTGRES_DATABASE") != "") { ## try to load our module and abort if this fails stopifnot(require(RPostgreSQL)) stopifnot(require(datasets)) ## load the PostgresSQL driver drv <- dbDriver("PostgreSQL") ## connect to the default db con <- dbConnect(drv, user=Sys.getenv("POSTGRES_USER"), password=Sys.getenv("POSTGRES_PASSWD"), host=Sys.getenv("POSTGRES_HOST"), dbname=Sys.getenv("POSTGRES_DATABASE"), port=ifelse((p<-Sys.getenv("POSTGRES_PORT"))!="", p, 5432)) if (dbExistsTable(con, "rockdata")) { print("Removing rockdata\n") dbRemoveTable(con, "rockdata") } dbWriteTable(con, "rockdata", rock) ## run a simple dbExists cat("Does rockdata exist? ") print(res <- dbExistsTable(con, "rockdata")) ## this should return TRUE but did not -- does now after patch cat("Does public.rockdata exist? ") print(res <- dbExistsTable(con, "public.rockdata")) ## cleanup if (dbExistsTable(con, "rockdata")) { print("Removing rockdata\n") dbRemoveTable(con, "rockdata") } ## and disconnect dbDisconnect(con) } RPostgreSQL/tests/dbWriteTabletypes.Rout.save0000644000176000001440000002214612124517166021050 0ustar ripleyusers R version 2.15.2 (2012-10-26) -- "Trick or Treat" Copyright (C) 2012 The R Foundation for Statistical Computing ISBN 3-900051-07-0 Platform: x86_64-unknown-linux-gnu (64-bit) R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. R is a collaborative project with many contributors. Type 'contributors()' for more information and 'citation()' on how to cite R or R packages in publications. Type 'demo()' for some demos, 'help()' for on-line help, or 'help.start()' for an HTML browser interface to help. Type 'q()' to quit R. > ## dbWriteTable test > ## > ## Assumes that > ## a) PostgreSQL is running, and > ## b) the current user can connect > ## both of which are not viable for release but suitable while we test > ## > ## Dirk Eddelbuettel, 10 Sep 2009 > > ## only run this if this env.var is set correctly > if (Sys.getenv("POSTGRES_USER") != "" & Sys.getenv("POSTGRES_HOST") != "" & Sys.getenv("POSTGRES_DATABASE") != "") { + + ## try to load our module and abort if this fails + stopifnot(require(RPostgreSQL)) + + ## load the PostgresSQL driver + drv <- dbDriver("PostgreSQL") + + ## connect to the default db + con <- dbConnect(drv, + user=Sys.getenv("POSTGRES_USER"), + password=Sys.getenv("POSTGRES_PASSWD"), + host=Sys.getenv("POSTGRES_HOST"), + dbname=Sys.getenv("POSTGRES_DATABASE"), + port=ifelse((p<-Sys.getenv("POSTGRES_PORT"))!="", p, 5432)) + + + if (dbExistsTable(con, "rockdata")) { + print("Removing rockdata\n") + dbRemoveTable(con, "rockdata") + } + + dbGetQuery(con, "set client_encoding to 'UTF-8'") + difficultstrings <- c("normal", "t\tab", "v\vertical tab", "n\newline", "r carriage \retern", "back \\ slash", "f\form feed") + df <- data.frame(strings=difficultstrings) + + dbWriteTable(con, "rockdata", df) + + ## run a simple query and show the query result + res <- dbGetQuery(con, "select * from rockdata") + print(res) + print("Removing rockdata\n") + dbRemoveTable(con, "rockdata") + + difficultstringe <- c("normal", "m\u00fc\u00df") + df <- data.frame(strings=difficultstringe) + tryres <- try({dbWriteTable(con, "rockdata", df) + res <- dbGetQuery(con, "select * from rockdata") + for(n in 1:2){ + cat(paste(as.character(n), "\t")) + cat(res[n,2]) + cat("\n") + } + print("Removing rockdata\n") + dbRemoveTable(con, "rockdata") + }) + if(tryres != TRUE){ + cat("FAIL: could not write small umlaut u and ligature sz.\n") + cat(" This might be no problem for you if you don't use those special characters.\n") + cat(" Otherwise, please check for the server encoding.\n") + cat(" Database encoding is usually set at the time of createdb.\n") + cat(" You can see for more information on how to setup at \n") + cat(" http://www.postgresql.org/docs/9.1/static/multibyte.html\n\n") + }else{ + cat("PASS: could write small umlaut u and ligature sz\n") + } + + difficultstringk <- c("normal", "kanji\u6f22\u5b57") + df <- data.frame(strings=difficultstringk) + tryres <- try({dbWriteTable(con, "rockdata", df) + res <- dbGetQuery(con, "select * from rockdata") + for(n in 1:2){ + cat(paste(as.character(n), "\t")) + cat(res[n,2]) + cat("\n") + } + print("Removing rockdata\n") + dbRemoveTable(con, "rockdata") + }) + if(tryres != TRUE){ + cat("FAIL: could not write kanji.\n") + cat(" This might be no problem for you if you don't use multibyte characters.\n") + cat(" Otherwise, please check for the server encoding.\n") + cat(" Database encoding is usually set at the time of createdb.\n") + cat(" You can see for more information on how to setup at \n") + cat(" http://www.postgresql.org/docs/9.1/static/multibyte.html\n\n") + }else{ + cat("PASS: could write kanji\n") + } + + ## cleanup + if (dbExistsTable(con, "rockdata")) { + print("Removing rockdata\n") + dbRemoveTable(con, "rockdata") + } + + if (dbExistsTable(con, "tempostgrestable")) + dbRemoveTable(con, "tempostgrestable") + + ## Test the numeric mapping + dbGetQuery(con, "create table tempostgrestable (intcolumn integer, floatcolumn float);") + + i <- as.integer(10) + j <- as.numeric(56.6) + + sql <- paste("insert into tempostgrestable ", + "values (",i, "," ,j ,") ", sep="") + res <- dbGetQuery(con, sql) + + dat <- dbReadTable(con, "tempostgrestable") + dbRemoveTable(con, "tempostgrestable") + res <- dbWriteTable(con, "numerictable", dat) + dat <- dbReadTable(con, "numerictable") + dbRemoveTable(con, "numerictable") + cat("Read Numeric values\n") + + ## now test the types of the colums we got + if( class(dat[,1]) == "integer" ) { + cat("PASS -- all integer is as expected\n") + }else{ + cat(paste("FAIL -- an integer became ", class(dat[,1]), "\n")) + } + stopifnot( class(dat[,2]) == "numeric" ) + + ## and test the values + if( identical( dat[1,1], i)){ + cat("PASS integer value is preserved") + }else{ + cat(paste("FAIL:", i, "changed to", dat[1,1], "\n")) + } + stopifnot( identical( dat[1,2], j)) + cat("GOOD -- all numeric values are as expected\n") + + ## Test the logical mapping + if (dbExistsTable(con, "testlogical")) + dbRemoveTable(con, "testlogical") + dbGetQuery(con,"create table testlogical (col1 boolean, col2 boolean)") + + i <- as.logical(TRUE) + j <- as.logical(FALSE) + + sql <- paste("insert into testlogical ", + "values (",i, "," ,j ,") ", sep="") + res <- dbGetQuery(con, sql); + + dat <- dbReadTable(con, "testlogical") + res <- dbWriteTable(con, "logicaltable", dat) + dbRemoveTable(con, "testlogical") + dat2 <- dbReadTable(con,"logicaltable") + dbRemoveTable(con, "logicaltable") + cat("Read Logical values\n") + + ## now test the types of the colums we got + stopifnot( class(dat2[,1]) == "logical" ) + stopifnot( class(dat2[,2]) == "logical" ) + cat("GOOD -- all logical types are as expected\n") + + ## and test the values + stopifnot( identical( dat2[1,1], i)) + stopifnot( identical( dat2[1,2], j)) + cat("GOOD -- all logical values are as expected\n") + + ## Test the character mapping + if (dbExistsTable(con, "testchar")) + dbRemoveTable(con, "testchar") + dbGetQuery(con,"create table testchar (code char(3),city varchar(20),country text);") + + i <- as.character("IN") + j <- as.character("Hyderabad") + k <- as.character("India") + + sql <- paste("insert into testchar ", + "values ('",i,"' , '",j ,"' , '",k,"') ", sep="") + res <- dbGetQuery(con, sql); + + dat <- dbReadTable(con, "testchar") + dbRemoveTable(con, "testchar") + dbWriteTable(con, "testchar", dat) + dat <- dbReadTable(con, "testchar") + cat("Read Character values\n") + + ## now test the types of the colums we got + stopifnot( class(dat[,1]) == "character" ) + stopifnot( class(dat[,2]) == "character" ) + stopifnot( class(dat[,3]) == "character" ) + cat("GOOD -- all character types are as expected\n") + + ## and test the values + ##stopifnot( identical( dat[1,1], i)) + stopifnot( identical( dat[1,2], j)) + stopifnot( identical( dat[1,3], k)) + cat("GOOD -- all character values are as expected\n") + + dbRemoveTable(con, "testchar") + dbRemoveTable(con, "tempostgrestable") + + ## Test the numeric mapping + dbGetQuery(con, "create table tempostgrestable (intcolumn date, floatcolumn timestamp with time zone);") + + sql <- paste("insert into tempostgrestable ", + "values ('2011-03-07', '2011-03-07 16:30:39') ") + res <- dbGetQuery(con, sql) + + dat <- dbReadTable(con, "tempostgrestable") + dbRemoveTable(con, "tempostgrestable") + dbWriteTable(con, "tempostgrestable2", dat) + dat2 <- dbReadTable(con, "tempostgrestable2") + dbRemoveTable(con, "tempostgrestable2") + cat("Check that read after write gets the same data types\n") + + ## now test the types of the colums we got + if( class(dat2[1,1]) == "Date" ){ + cat("PASS -- Date type is as expected\n") + }else{ + cat("FAIL -- Date type is other than Date: ") + cat(class(dat2[1,1])) + cat("\n") + } + if( class(dat2[1,2])[1] == "POSIXct" ){ + cat("PASS -- TIMESTAMP is received as POSIXct\n") + }else{ + cat("FAIL -- TIMESTAMP is other than POSIXct: ") + cat(class(dat2[1,2])) + cat("\n") + } + + + dbDisconnect(con) + dbUnloadDriver(drv) + + cat("DONE\n") + } > > > proc.time() user system elapsed 0.217 0.020 0.221 RPostgreSQL/tests/datetimestampwrite.R0000644000176000001440000000506211535162225017635 0ustar ripleyusers## Test of data types, based on earlier version in inst/devTests ## ## Dirk Eddelbuettel, 21 Oct 2008 if ((Sys.getenv("POSTGRES_USER") != "") & (Sys.getenv("POSTGRES_HOST") != "") & (Sys.getenv("POSTGRES_DATABASE") != "")) { ## try to load our module and abort if this fails stopifnot(require(RPostgreSQL)) ## load the PostgresSQL driver drv <- dbDriver("PostgreSQL") ## can't print result as it contains process id which changes print(summary(drv)) ## connect to the default db con <- dbConnect(drv, user=Sys.getenv("POSTGRES_USER"), password=Sys.getenv("POSTGRES_PASSWD"), host=Sys.getenv("POSTGRES_HOST"), dbname=Sys.getenv("POSTGRES_DATABASE"), port=ifelse((p<-Sys.getenv("POSTGRES_PORT"))!="", p, 5432)) if (dbExistsTable(con, "tempostgrestable")) dbRemoveTable(con, "tempostgrestable") ## Test the numeric mapping dbGetQuery(con, "create table tempostgrestable (intcolumn date, floatcolumn timestamp with time zone);") sql <- paste("insert into tempostgrestable ", "values ('2011-03-07', '2011-03-07 16:30:39') ") res <- dbGetQuery(con, sql) dat <- dbReadTable(con, "tempostgrestable") dbRemoveTable(con, "tempostgrestable") cat("Read Date and TIMESTAMP values\n") ## now test the types of the colums we got if( class(dat[1,1]) == "Date" ){ cat("PASS -- Date type is as expected\n") }else{ cat("FAIL -- Date type is other than Date: ") cat(class(dat[1,1])) cat("\n") } if( class(dat[1,2])[1] == "POSIXct" ){ cat("PASS -- TIMESTAMP is received as POSIXct\n") }else{ cat("FAIL -- TIMESTAMP is other than POSIXct: ") cat(class(dat[1,2])) cat("\n") } dbWriteTable(con, "tempostgrestable2", dat) dat2 <- dbReadTable(con, "tempostgrestable2") dbRemoveTable(con, "tempostgrestable2") cat("Check that read after write gets the same data types\n") ## now test the types of the colums we got if( class(dat2[1,1]) == "Date" ){ cat("PASS -- Date type is as expected\n") }else{ cat("FAIL -- Date type is other than Date: ") cat(class(dat2[1,1])) cat("\n") } if( class(dat2[1,2])[1] == "POSIXct" ){ cat("PASS -- TIMESTAMP is received as POSIXct\n") }else{ cat("FAIL -- TIMESTAMP is other than POSIXct: ") cat(class(dat2[1,2])) cat("\n") } dbDisconnect(con) dbUnloadDriver(drv) cat("DONE\n") } RPostgreSQL/tests/dbColumnInfo.Rout.save0000644000176000001440000000444312060117375017767 0ustar ripleyusers R version 2.15.1 (2012-06-22) -- "Roasted Marshmallows" Copyright (C) 2012 The R Foundation for Statistical Computing ISBN 3-900051-07-0 Platform: x86_64-unknown-linux-gnu (64-bit) R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. R is a collaborative project with many contributors. Type 'contributors()' for more information and 'citation()' on how to cite R or R packages in publications. Type 'demo()' for some demos, 'help()' for on-line help, or 'help.start()' for an HTML browser interface to help. Type 'q()' to quit R. > > ## dbWriteTable test > ## > ## Assumes that > ## a) PostgreSQL is running, and > ## b) the current user can connect > ## both of which are not viable for release but suitable while we test > ## > ## Dirk Eddelbuettel, 10 Sep 2009 > > ## only run this if this env.var is set correctly > if (Sys.getenv("POSTGRES_USER") != "" & Sys.getenv("POSTGRES_HOST") != "" & Sys.getenv("POSTGRES_DATABASE") != "") { + + ## try to load our module and abort if this fails + stopifnot(require(RPostgreSQL)) + + ## load the PostgresSQL driver + drv <- dbDriver("PostgreSQL") + + ## connect to the default db + con <- dbConnect(drv, + user=Sys.getenv("POSTGRES_USER"), + password=Sys.getenv("POSTGRES_PASSWD"), + host=Sys.getenv("POSTGRES_HOST"), + dbname=Sys.getenv("POSTGRES_DATABASE"), + port=ifelse((p<-Sys.getenv("POSTGRES_PORT"))!="", p, 5432)) + + + # create a table + res <- dbGetQuery(con, "CREATE TABLE aa (pk integer primary key, v1 float not null, v2 float)" ) + + ## run a simple query and show the query result + res <- dbGetQuery(con, "INSERT INTO aa VALUES(3, 2, NULL)" ) + res <- dbSendQuery(con, "select pk, v1, v2, v1+v2 from aa") + cat("dbColumnInfo\n") + gctorture() + print(dbColumnInfo(res)) + print(dbColumnInfo(res)) + cat("SELECT result\n") + df <- fetch(res, n=-1) + print(df) + + ## cleanup + cat("Removing \"AA\"\n") + dbRemoveTable(con, "aa") + ## and disconnect + dbDisconnect(con) + } > > proc.time() user system elapsed 0.127 0.016 0.132 RPostgreSQL/tests/dbWriteTableTest.Rout.save0000644000176000001440000000417311637765112020627 0ustar ripleyusers R version 2.13.1 (2011-07-08) Copyright (C) 2011 The R Foundation for Statistical Computing ISBN 3-900051-07-0 Platform: x86_64-pc-linux-gnu (64-bit) R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. R is a collaborative project with many contributors. Type 'contributors()' for more information and 'citation()' on how to cite R or R packages in publications. Type 'demo()' for some demos, 'help()' for on-line help, or 'help.start()' for an HTML browser interface to help. Type 'q()' to quit R. > > ## dbWriteTable test > ## > ## Assumes that > ## a) PostgreSQL is running, and > ## b) the current user can connect > ## both of which are not viable for release but suitable while we test > ## > ## Dirk Eddelbuettel, 10 Sep 2009 > > ## only run this if this env.var is set correctly > if (Sys.getenv("POSTGRES_USER") != "" & Sys.getenv("POSTGRES_HOST") != "" & Sys.getenv("POSTGRES_DATABASE") != "") { + + ## try to load our module and abort if this fails + stopifnot(require(RPostgreSQL)) + stopifnot(require(datasets)) + + ## load the PostgresSQL driver + drv <- dbDriver("PostgreSQL") + + ## connect to the default db + con <- dbConnect(drv, + user=Sys.getenv("POSTGRES_USER"), + password=Sys.getenv("POSTGRES_PASSWD"), + host=Sys.getenv("POSTGRES_HOST"), + dbname=Sys.getenv("POSTGRES_DATABASE"), + port=ifelse((p<-Sys.getenv("POSTGRES_PORT"))!="", p, 5432)) + + + if (dbExistsTable(con, "rockdata")) { + print("Removing rockdata\n") + dbRemoveTable(con, "rockdata") + } + + dbWriteTable(con, "rockdata", rock) + + ## run a simple query and show the query result + res <- dbGetQuery(con, "select * from rockdata limit 10") + print(res) + + + ## cleanup + if (dbExistsTable(con, "rockdata")) { + print("Removing rockdata\n") + dbRemoveTable(con, "rockdata") + } + + ## and disconnect + dbDisconnect(con) + } > RPostgreSQL/tests/dbWriteTableFailTest.R0000644000176000001440000000407511525156517017736 0ustar ripleyusers ## dbWriteTable test ## ## Assumes that ## a) PostgreSQL is running, and ## b) the current user can connect ## both of which are not viable for release but suitable while we test ## ## Dirk Eddelbuettel, 10 Sep 2009 ## only run this if this env.var is set correctly if (Sys.getenv("POSTGRES_USER") != "" & Sys.getenv("POSTGRES_HOST") != "" & Sys.getenv("POSTGRES_DATABASE") != "") { ## try to load our module and abort if this fails stopifnot(require(RPostgreSQL)) stopifnot(require(datasets)) ## load the PostgresSQL driver drv <- dbDriver("PostgreSQL") ## connect to the default db con <- dbConnect(drv, user=Sys.getenv("POSTGRES_USER"), password=Sys.getenv("POSTGRES_PASSWD"), host=Sys.getenv("POSTGRES_HOST"), dbname=Sys.getenv("POSTGRES_DATABASE"), port=ifelse((p<-Sys.getenv("POSTGRES_PORT"))!="", p, 5432)) if (dbExistsTable(con, "rockdata")) { print("Removing rockdata\n") dbRemoveTable(con, "rockdata") } cat("create incompatible table rockdata\n") dbGetQuery(con, "CREATE TABLE rockdata (a int, b varchar(5))") cat("write table to rockdata with append=TRUE\n") try({res <-dbWriteTable(con, 'rockdata', rock, append=TRUE, overwrite=FALSE) print(res) if(res == FALSE){ cat("PASS as the return value is false\n") }else{ cat("FAIL as the return value is true\n") } }) cat("write table to rockdata\n") try({res <- dbWriteTable(con, 'rockdata', rock) if(res == FALSE){ print(res) cat("PASS as the return value is false\n") }else{ cat("FAIL as the return value is true\n") } }) ## run a simple query and show the query result res <- dbGetQuery(con, "select * from rockdata limit 10") print(res) ## cleanup if (dbExistsTable(con, "rockdata")) { print("Removing rockdata\n") dbRemoveTable(con, "rockdata") } ## and disconnect dbDisconnect(con) } RPostgreSQL/tests/dbWriteTabletypes.R0000644000176000001440000001770311642552526017371 0ustar ripleyusers## dbWriteTable test ## ## Assumes that ## a) PostgreSQL is running, and ## b) the current user can connect ## both of which are not viable for release but suitable while we test ## ## Dirk Eddelbuettel, 10 Sep 2009 ## only run this if this env.var is set correctly if (Sys.getenv("POSTGRES_USER") != "" & Sys.getenv("POSTGRES_HOST") != "" & Sys.getenv("POSTGRES_DATABASE") != "") { ## try to load our module and abort if this fails stopifnot(require(RPostgreSQL)) ## load the PostgresSQL driver drv <- dbDriver("PostgreSQL") ## connect to the default db con <- dbConnect(drv, user=Sys.getenv("POSTGRES_USER"), password=Sys.getenv("POSTGRES_PASSWD"), host=Sys.getenv("POSTGRES_HOST"), dbname=Sys.getenv("POSTGRES_DATABASE"), port=ifelse((p<-Sys.getenv("POSTGRES_PORT"))!="", p, 5432)) if (dbExistsTable(con, "rockdata")) { print("Removing rockdata\n") dbRemoveTable(con, "rockdata") } dbGetQuery(con, "set client_encoding to 'UTF-8'") difficultstrings <- c("normal", "t\tab", "v\vertical tab", "n\newline", "r carriage \retern", "back \\ slash", "f\form feed") df <- data.frame(strings=difficultstrings) dbWriteTable(con, "rockdata", df) ## run a simple query and show the query result res <- dbGetQuery(con, "select * from rockdata") print(res) print("Removing rockdata\n") dbRemoveTable(con, "rockdata") difficultstringe <- c("normal", "m\u00fc\u00df") df <- data.frame(strings=difficultstringe) tryres <- try({dbWriteTable(con, "rockdata", df) res <- dbGetQuery(con, "select * from rockdata") for(n in 1:2){ cat(paste(as.character(n), "\t")) cat(res[n,2]) cat("\n") } print("Removing rockdata\n") dbRemoveTable(con, "rockdata") }) if(tryres != TRUE){ cat("FAIL: could not write small umlaut u and ligature sz.\n") cat(" This might be no problem for you if you don't use those special characters.\n") cat(" Otherwise, please check for the server encoding.\n") cat(" Database encoding is usually set at the time of createdb.\n") cat(" You can see for more information on how to setup at \n") cat(" http://www.postgresql.org/docs/9.1/static/multibyte.html\n\n") }else{ cat("PASS: could write small umlaut u and ligature sz\n") } difficultstringk <- c("normal", "kanji\u6f22\u5b57") df <- data.frame(strings=difficultstringk) tryres <- try({dbWriteTable(con, "rockdata", df) res <- dbGetQuery(con, "select * from rockdata") for(n in 1:2){ cat(paste(as.character(n), "\t")) cat(res[n,2]) cat("\n") } print("Removing rockdata\n") dbRemoveTable(con, "rockdata") }) if(tryres != TRUE){ cat("FAIL: could not write kanji.\n") cat(" This might be no problem for you if you don't use multibyte characters.\n") cat(" Otherwise, please check for the server encoding.\n") cat(" Database encoding is usually set at the time of createdb.\n") cat(" You can see for more information on how to setup at \n") cat(" http://www.postgresql.org/docs/9.1/static/multibyte.html\n\n") }else{ cat("PASS: could write kanji\n") } ## cleanup if (dbExistsTable(con, "rockdata")) { print("Removing rockdata\n") dbRemoveTable(con, "rockdata") } if (dbExistsTable(con, "tempostgrestable")) dbRemoveTable(con, "tempostgrestable") ## Test the numeric mapping dbGetQuery(con, "create table tempostgrestable (intcolumn integer, floatcolumn float);") i <- as.integer(10) j <- as.numeric(56.6) sql <- paste("insert into tempostgrestable ", "values (",i, "," ,j ,") ", sep="") res <- dbGetQuery(con, sql) dat <- dbReadTable(con, "tempostgrestable") dbRemoveTable(con, "tempostgrestable") res <- dbWriteTable(con, "numerictable", dat) dat <- dbReadTable(con, "numerictable") dbRemoveTable(con, "numerictable") cat("Read Numeric values\n") ## now test the types of the colums we got if( class(dat[,1]) == "integer" ) { cat("PASS -- all integer is as expected\n") }else{ cat(paste("FAIL -- an integer became ", class(dat[,1]), "\n")) } stopifnot( class(dat[,2]) == "numeric" ) ## and test the values if( identical( dat[1,1], i)){ cat("PASS integer value is preserved") }else{ cat(paste("FAIL:", i, "changed to", dat[1,1], "\n")) } stopifnot( identical( dat[1,2], j)) cat("GOOD -- all numeric values are as expected\n") ## Test the logical mapping if (dbExistsTable(con, "testlogical")) dbRemoveTable(con, "testlogical") dbGetQuery(con,"create table testlogical (col1 boolean, col2 boolean)") i <- as.logical(TRUE) j <- as.logical(FALSE) sql <- paste("insert into testlogical ", "values (",i, "," ,j ,") ", sep="") res <- dbGetQuery(con, sql); dat <- dbReadTable(con, "testlogical") res <- dbWriteTable(con, "logicaltable", dat) dbRemoveTable(con, "testlogical") dat2 <- dbReadTable(con,"logicaltable") dbRemoveTable(con, "logicaltable") cat("Read Logical values\n") ## now test the types of the colums we got stopifnot( class(dat2[,1]) == "logical" ) stopifnot( class(dat2[,2]) == "logical" ) cat("GOOD -- all logical types are as expected\n") ## and test the values stopifnot( identical( dat2[1,1], i)) stopifnot( identical( dat2[1,2], j)) cat("GOOD -- all logical values are as expected\n") ## Test the character mapping if (dbExistsTable(con, "testchar")) dbRemoveTable(con, "testchar") dbGetQuery(con,"create table testchar (code char(3),city varchar(20),country text);") i <- as.character("IN") j <- as.character("Hyderabad") k <- as.character("India") sql <- paste("insert into testchar ", "values ('",i,"' , '",j ,"' , '",k,"') ", sep="") res <- dbGetQuery(con, sql); dat <- dbReadTable(con, "testchar") dbRemoveTable(con, "testchar") dbWriteTable(con, "testchar", dat) dat <- dbReadTable(con, "testchar") cat("Read Character values\n") ## now test the types of the colums we got stopifnot( class(dat[,1]) == "character" ) stopifnot( class(dat[,2]) == "character" ) stopifnot( class(dat[,3]) == "character" ) cat("GOOD -- all character types are as expected\n") ## and test the values ##stopifnot( identical( dat[1,1], i)) stopifnot( identical( dat[1,2], j)) stopifnot( identical( dat[1,3], k)) cat("GOOD -- all character values are as expected\n") dbRemoveTable(con, "testchar") dbRemoveTable(con, "tempostgrestable") ## Test the numeric mapping dbGetQuery(con, "create table tempostgrestable (intcolumn date, floatcolumn timestamp with time zone);") sql <- paste("insert into tempostgrestable ", "values ('2011-03-07', '2011-03-07 16:30:39') ") res <- dbGetQuery(con, sql) dat <- dbReadTable(con, "tempostgrestable") dbRemoveTable(con, "tempostgrestable") dbWriteTable(con, "tempostgrestable2", dat) dat2 <- dbReadTable(con, "tempostgrestable2") dbRemoveTable(con, "tempostgrestable2") cat("Check that read after write gets the same data types\n") ## now test the types of the colums we got if( class(dat2[1,1]) == "Date" ){ cat("PASS -- Date type is as expected\n") }else{ cat("FAIL -- Date type is other than Date: ") cat(class(dat2[1,1])) cat("\n") } if( class(dat2[1,2])[1] == "POSIXct" ){ cat("PASS -- TIMESTAMP is received as POSIXct\n") }else{ cat("FAIL -- TIMESTAMP is other than POSIXct: ") cat(class(dat2[1,2])) cat("\n") } dbDisconnect(con) dbUnloadDriver(drv) cat("DONE\n") } RPostgreSQL/tests/escape.Rout.save0000644000176000001440000000403411455443410016643 0ustar ripleyusers R version 2.12.0 RC (2010-10-07 r53227) Copyright (C) 2010 The R Foundation for Statistical Computing ISBN 3-900051-07-0 Platform: x86_64-pc-linux-gnu (64-bit) R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. R is a collaborative project with many contributors. Type 'contributors()' for more information and 'citation()' on how to cite R or R packages in publications. Type 'demo()' for some demos, 'help()' for on-line help, or 'help.start()' for an HTML browser interface to help. Type 'q()' to quit R. > > ## connectWithNull test > ## > ## test for the 'Issue 2' on the Google Code issue log > ## reported in April 2009, still open ? > ## > ## Assumes that > ## a) PostgreSQL is running, and > ## b) the current user can connect > ## both of which are not viable for release but suitable while we test > ## > ## Dirk Eddelbuettel, 03 Oct 2009 > > ## only run this if this env.var is set correctly > if (Sys.getenv("POSTGRES_USER") != "" & Sys.getenv("POSTGRES_HOST") != "" & Sys.getenv("POSTGRES_DATABASE") != "") { + + ## try to load our module and abort if this fails + stopifnot(require(RPostgreSQL)) + stopifnot(require(datasets)) + + ## load the PostgresSQL driver + drv <- dbDriver("PostgreSQL") + + ## connect to the default db -- replacing any of these with NULL will lead to + ## a stop() call and a return to the R prompt rather than a segfault + con <- dbConnect(drv, + user=Sys.getenv("POSTGRES_USER"), + password=Sys.getenv("POSTGRES_PASSWD"), + host=Sys.getenv("POSTGRES_HOST"), + dbname=Sys.getenv("POSTGRES_DATABASE"), + port=ifelse((p<-Sys.getenv("POSTGRES_PORT"))!="", p, 5432)) + + st <- (postgresqlEscapeStrings(con,"aaa")) + print(st) + st2 <- (postgresqlEscapeStrings(con,"aa'a")) + print(st2) + + ## and disconnect + dbDisconnect(con) + } > RPostgreSQL/tests/loadDriverAndConnect.R0000644000176000001440000000256311455242162017754 0ustar ripleyusers ## First rough version of a test script ## ## Assumes that ## a) PostgreSQL is running, and ## b) the current user can connect ## both of which are not viable for release but suitable while we test ## ## Dirk Eddelbuettel, 02 Jul 2008 ## 21 Oct 2008 make conditional on environment variables ## only run this if this env.var is set correctly if (Sys.getenv("POSTGRES_USER") != "" & Sys.getenv("POSTGRES_HOST") != "" & Sys.getenv("POSTGRES_DATABASE") != "") { ## try to load our module and abort if this fails stopifnot(require(RPostgreSQL)) ## load the PostgresSQL driver drv <- dbDriver("PostgreSQL") ## can't print result as it contains process id which changes print(summary(drv)) ## connect to the default db con <- dbConnect(drv, user=Sys.getenv("POSTGRES_USER"), password=Sys.getenv("POSTGRES_PASSWD"), host=Sys.getenv("POSTGRES_HOST"), dbname=Sys.getenv("POSTGRES_DATABASE"), port=ifelse((p<-Sys.getenv("POSTGRES_PORT"))!="", p, 5432)) ## run a simple query and show the query result res <- dbGetQuery(con, paste("select datname,encoding,datallowconn from pg_database", "where datname like 'template%' order by datname")) print(res) ## and disconnect dbDisconnect(con) } RPostgreSQL/tests/dbWriteTableFailTest.Rout.save0000644000176000001440000000563212124517166021420 0ustar ripleyusers R version 2.15.2 (2012-10-26) -- "Trick or Treat" Copyright (C) 2012 The R Foundation for Statistical Computing ISBN 3-900051-07-0 Platform: x86_64-unknown-linux-gnu (64-bit) R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. R is a collaborative project with many contributors. Type 'contributors()' for more information and 'citation()' on how to cite R or R packages in publications. Type 'demo()' for some demos, 'help()' for on-line help, or 'help.start()' for an HTML browser interface to help. Type 'q()' to quit R. > > ## dbWriteTable test > ## > ## Assumes that > ## a) PostgreSQL is running, and > ## b) the current user can connect > ## both of which are not viable for release but suitable while we test > ## > ## Dirk Eddelbuettel, 10 Sep 2009 > > ## only run this if this env.var is set correctly > if (Sys.getenv("POSTGRES_USER") != "" & Sys.getenv("POSTGRES_HOST") != "" & Sys.getenv("POSTGRES_DATABASE") != "") { + + ## try to load our module and abort if this fails + stopifnot(require(RPostgreSQL)) + stopifnot(require(datasets)) + + ## load the PostgresSQL driver + drv <- dbDriver("PostgreSQL") + + ## connect to the default db + con <- dbConnect(drv, + user=Sys.getenv("POSTGRES_USER"), + password=Sys.getenv("POSTGRES_PASSWD"), + host=Sys.getenv("POSTGRES_HOST"), + dbname=Sys.getenv("POSTGRES_DATABASE"), + port=ifelse((p<-Sys.getenv("POSTGRES_PORT"))!="", p, 5432)) + + + if (dbExistsTable(con, "rockdata")) { + print("Removing rockdata\n") + dbRemoveTable(con, "rockdata") + } + cat("create incompatible table rockdata\n") + dbGetQuery(con, "CREATE TABLE rockdata (a int, b varchar(5))") + + cat("write table to rockdata with append=TRUE\n") + try({res <-dbWriteTable(con, 'rockdata', rock, append=TRUE, overwrite=FALSE) + print(res) + if(res == FALSE){ + cat("PASS as the return value is false\n") + }else{ + cat("FAIL as the return value is true\n") + } + }) + + cat("write table to rockdata\n") + try({res <- dbWriteTable(con, 'rockdata', rock) + if(res == FALSE){ + print(res) + cat("PASS as the return value is false\n") + }else{ + cat("FAIL as the return value is true\n") + } + }) + + ## run a simple query and show the query result + res <- dbGetQuery(con, "select * from rockdata limit 10") + print(res) + + + ## cleanup + if (dbExistsTable(con, "rockdata")) { + print("Removing rockdata\n") + dbRemoveTable(con, "rockdata") + } + + ## and disconnect + dbDisconnect(con) + } > > proc.time() user system elapsed 0.139 0.018 0.141 RPostgreSQL/tests/selectWhereZero.R0000644000176000001440000000323111455327527017040 0ustar ripleyusers ## selectWhereZero test ## ## test for the 'Issue 1' on the Google Code issue log ## this was reported in June and fixed by Joe Conway (svr committ r100) ## ## Assumes that ## a) PostgreSQL is running, and ## b) the current user can connect ## both of which are not viable for release but suitable while we test ## ## Dirk Eddelbuettel, 03 Oct 2009 ## only run this if this env.var is set correctly if (Sys.getenv("POSTGRES_USER") != "" & Sys.getenv("POSTGRES_HOST") != "" & Sys.getenv("POSTGRES_DATABASE") != "") { ## try to load our module and abort if this fails stopifnot(require(RPostgreSQL)) stopifnot(require(datasets)) ## load the PostgresSQL driver drv <- dbDriver("PostgreSQL") ## connect to the default db con <- dbConnect(drv, user=Sys.getenv("POSTGRES_USER"), password=Sys.getenv("POSTGRES_PASSWD"), host=Sys.getenv("POSTGRES_HOST"), dbname=Sys.getenv("POSTGRES_DATABASE"), port=ifelse((p<-Sys.getenv("POSTGRES_PORT"))!="", p, 5432)) if (dbExistsTable(con, "tmpirisdata")) { print("Removing tmpirisdata\n") dbRemoveTable(con, "tmpirisdata") } dbWriteTable(con, "tmpirisdata", iris) ## run a simple query and show the query result res <- dbGetQuery(con, "select * from tmpirisdata where \"Species\"=0") print(res) ## cleanup if (dbExistsTable(con, "tmpirisdata")) { print("Removing tmpirisdata\n") dbRemoveTable(con, "tmpirisdata") } ## and disconnect dbDisconnect(con) cat("PASS: reached to the end of the test code without segmentation fault\n") } RPostgreSQL/tests/loadDriverAndConnect.Rout.save0000644000176000001440000000401611455242162021434 0ustar ripleyusers R version 2.11.1 (2010-05-31) Copyright (C) 2010 The R Foundation for Statistical Computing ISBN 3-900051-07-0 R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. R is a collaborative project with many contributors. Type 'contributors()' for more information and 'citation()' on how to cite R or R packages in publications. Type 'demo()' for some demos, 'help()' for on-line help, or 'help.start()' for an HTML browser interface to help. Type 'q()' to quit R. > > ## First rough version of a test script > ## > ## Assumes that > ## a) PostgreSQL is running, and > ## b) the current user can connect > ## both of which are not viable for release but suitable while we test > ## > ## Dirk Eddelbuettel, 02 Jul 2008 > ## 21 Oct 2008 make conditional on environment variables > > ## only run this if this env.var is set correctly > if (Sys.getenv("POSTGRES_USER") != "" & Sys.getenv("POSTGRES_HOST") != "" & Sys.getenv("POSTGRES_DATABASE") != "") { + + ## try to load our module and abort if this fails + stopifnot(require(RPostgreSQL)) + + ## load the PostgresSQL driver + drv <- dbDriver("PostgreSQL") + ## can't print result as it contains process id which changes print(summary(drv)) + + ## connect to the default db + con <- dbConnect(drv, + user=Sys.getenv("POSTGRES_USER"), + password=Sys.getenv("POSTGRES_PASSWD"), + host=Sys.getenv("POSTGRES_HOST"), + dbname=Sys.getenv("POSTGRES_DATABASE"), + port=ifelse((p<-Sys.getenv("POSTGRES_PORT"))!="", p, 5432)) + + ## run a simple query and show the query result + res <- dbGetQuery(con, paste("select datname,encoding,datallowconn from pg_database", + "where datname like 'template%' order by datname")) + print(res) + + ## and disconnect + dbDisconnect(con) + } > RPostgreSQL/tests/dbWriteTableSchema.R0000644000176000001440000000274711534641277017431 0ustar ripleyusers ## dbWriteTable test ## ## Assumes that ## a) PostgreSQL is running, and ## b) the current user can connect ## both of which are not viable for release but suitable while we test ## ## Dirk Eddelbuettel, 10 Sep 2009 ## only run this if this env.var is set correctly if (Sys.getenv("POSTGRES_USER") != "" & Sys.getenv("POSTGRES_HOST") != "" & Sys.getenv("POSTGRES_DATABASE") != "") { ## try to load our module and abort if this fails stopifnot(require(RPostgreSQL)) stopifnot(require(datasets)) ## load the PostgresSQL driver drv <- dbDriver("PostgreSQL") ## connect to the default db con <- dbConnect(drv, user=Sys.getenv("POSTGRES_USER"), password=Sys.getenv("POSTGRES_PASSWD"), host=Sys.getenv("POSTGRES_HOST"), dbname=Sys.getenv("POSTGRES_DATABASE"), port=ifelse((p<-Sys.getenv("POSTGRES_PORT"))!="", p, 5432)) if (dbExistsTable(con, c("public", "rockdata"))) { print("Removing rockdata\n") dbRemoveTable(con, c("public", "rockdata")) } dbWriteTable(con, c("public", "rockdata"), rock) ## run a simple query and show the query result res <- dbGetQuery(con, "select * from public.rockdata limit 10") print(res) ## cleanup if (dbExistsTable(con, c("public", "rockdata"))) { print("Removing rockdata\n") dbRemoveTable(con, c("public", "rockdata")) } ## and disconnect dbDisconnect(con) } RPostgreSQL/tests/dbtemptable.Rout.save0000644000176000001440000000417411637765112017703 0ustar ripleyusers R version 2.13.1 (2011-07-08) Copyright (C) 2011 The R Foundation for Statistical Computing ISBN 3-900051-07-0 Platform: x86_64-pc-linux-gnu (64-bit) R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. R is a collaborative project with many contributors. Type 'contributors()' for more information and 'citation()' on how to cite R or R packages in publications. Type 'demo()' for some demos, 'help()' for on-line help, or 'help.start()' for an HTML browser interface to help. Type 'q()' to quit R. > > ## dbWriteTable test > ## > ## Assumes that > ## a) PostgreSQL is running, and > ## b) the current user can connect > ## both of which are not viable for release but suitable while we test > ## > ## Dirk Eddelbuettel, 10 Sep 2009 > > ## only run this if this env.var is set correctly > if (Sys.getenv("POSTGRES_USER") != "" & Sys.getenv("POSTGRES_HOST") != "" & Sys.getenv("POSTGRES_DATABASE") != "") { + + ## try to load our module and abort if this fails + stopifnot(require(RPostgreSQL)) + stopifnot(require(datasets)) + + ## load the PostgresSQL driver + drv <- dbDriver("PostgreSQL") + + ## connect to the default db + con <- dbConnect(drv, + user=Sys.getenv("POSTGRES_USER"), + password=Sys.getenv("POSTGRES_PASSWD"), + host=Sys.getenv("POSTGRES_HOST"), + dbname=Sys.getenv("POSTGRES_DATABASE"), + port=ifelse((p<-Sys.getenv("POSTGRES_PORT"))!="", p, 5432)) + + + + a <- dbGetQuery(con, "CREATE TABLE foo (name text)") + b <- dbGetQuery(con, "INSERT INTO foo VALUES ('bar')") + + ## run a simple query and show the query result + x <- dbSendQuery(con, "CREATE TEMPORARY TABLE xyz ON COMMIT DROP AS select * from foo limit 1; select * from xyz;") + res <- fetch(x, n=-1) + print(res) + a <- dbGetQuery(con, "DROP TABLE foo") + + + ## cleanup + + ## and disconnect + dbDisconnect(con) + cat("PASS -- ended without segmentation fault\n") + } > RPostgreSQL/tests/dateTZ.R0000644000176000001440000000607012060117375015114 0ustar ripleyusers ## Test of date and datetime types, based on earlier version in inst/devTests ## ## Dirk Eddelbuettel, 21 Oct 2008 dbTypeTests <- function(con, dateclass="timestamp without time zone", tz="UTC") { cat("\n\n**** Trying with ", dateclass, "\n") if (dbExistsTable(con, "tempostgrestable")) dbRemoveTable(con, "tempostgrestable") dbGetQuery(con, paste("create table tempostgrestable (tt ", dateclass, ", zz integer);", sep="")) insstring <- '2008-07-01 14:15:16.123+00' cat(paste('inserted string 1:', insstring)) cat("\n") dbGetQuery(con, paste("insert into tempostgrestable values('", insstring, "', 1);", sep="")) # now <- ISOdatetime(2000,1,2,3,4,5.678) insstring <- '2000-01-02 03:04:05.678+00' cat(paste('inserted string 2:', insstring)) cat("\n") dbGetQuery(con, paste("insert into tempostgrestable values('", insstring, "', 2);", sep="")) tt<-as.POSIXct(c("2008-07-01 23:45:16.123+0930","2000-01-02 13:34:05.678+1030"), format="%Y-%m-%d %H:%M:%OS%z") print(tt) dbGetQuery(con, paste("SET TIMEZONE TO '", tz, "'", sep="")) data <- dbGetQuery(con, "select tt from tempostgrestable;") times <- data[,1] print(times) if(as.double(tt[1]) == as.double(times[1])){ cat('PASS\n') }else{ cat('FAIL\n') } if(as.double(tt[2]) == as.double(times[2])){ cat('PASS\n') }else{ cat('FAIL\n') } dbRemoveTable(con, "tempostgrestable") invisible(NULL) } ## only run this if this env.var is set correctly if ((Sys.getenv("POSTGRES_USER") != "") & (Sys.getenv("POSTGRES_HOST") != "") & (Sys.getenv("POSTGRES_DATABASE") != "")) { ## try to load our module and abort if this fails stopifnot(require(RPostgreSQL)) ## Force a timezone to make the tests comparable at different locations Sys.setenv("TZ"="UTC") tt<-as.POSIXct(c("2008-07-01 23:45:16.123+0930","2000-01-02 13:34:05.678+1030"), format="%Y-%m-%d %H:%M:%OS%z") print(tt) ## load the PostgresSQL driver drv <- dbDriver("PostgreSQL") ## can't print result as it contains process id which changes print(summary(drv)) ## connect to the default db con <- dbConnect(drv, user=Sys.getenv("POSTGRES_USER"), password=Sys.getenv("POSTGRES_PASSWD"), host=Sys.getenv("POSTGRES_HOST"), dbname=Sys.getenv("POSTGRES_DATABASE"), port=ifelse((p<-Sys.getenv("POSTGRES_PORT"))!="", p, 5432)) cat('testing UTC') dbTypeTests(con, "timestamp") dbTypeTests(con, "timestamp with time zone") cat('testing Asia/Tokyo') dbTypeTests(con, "timestamp", tz="Asia/Tokyo") dbTypeTests(con, "timestamp with time zone", tz="Asia/Tokyo") cat('testing Australlia/South') dbTypeTests(con, "timestamp", tz="Australia/South") dbTypeTests(con, "timestamp with time zone", tz="Australia/South") cat('testing America/New_York') dbTypeTests(con, "timestamp", tz="America/New_York") dbTypeTests(con, "timestamp with time zone", tz="America/New_York") dbDisconnect(con) } RPostgreSQL/tests/dbGetQueryParams.Rout.save0000644000176000001440000000452712124517166020635 0ustar ripleyusers R version 2.15.2 (2012-10-26) -- "Trick or Treat" Copyright (C) 2012 The R Foundation for Statistical Computing ISBN 3-900051-07-0 Platform: x86_64-unknown-linux-gnu (64-bit) R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. R is a collaborative project with many contributors. Type 'contributors()' for more information and 'citation()' on how to cite R or R packages in publications. Type 'demo()' for some demos, 'help()' for on-line help, or 'help.start()' for an HTML browser interface to help. Type 'q()' to quit R. > ## dbGetQuery test with optional parameters > ## > ## Assumes that > ## a) PostgreSQL is running, and > ## b) the current user can connect > ## both of which are not viable for release but suitable while we test > > ## only run this if this env.var is set correctly > if (Sys.getenv("POSTGRES_USER") != "" & Sys.getenv("POSTGRES_HOST") != "" & Sys.getenv("POSTGRES_DATABASE") != "") { + + ## try to load our module and abort if this fails + stopifnot(require(RPostgreSQL)) + stopifnot(require(datasets)) + + ## load the PostgresSQL driver + drv <- dbDriver("PostgreSQL") + + ## connect to the default db + con <- dbConnect(drv, + user=Sys.getenv("POSTGRES_USER"), + password=Sys.getenv("POSTGRES_PASSWD"), + host=Sys.getenv("POSTGRES_HOST"), + dbname=Sys.getenv("POSTGRES_DATABASE"), + port=ifelse((p<-Sys.getenv("POSTGRES_PORT"))!="", p, 5432)) + + + if (dbExistsTable(con, "rockdata")) { + print("Removing rockdata\n") + dbRemoveTable(con, "rockdata") + } + + dbWriteTable(con, "rockdata", rock) + + ## run a simple query and show the query result + res <- dbGetQuery(con, "SELECT * FROM rockdata WHERE peri > $1 LIMIT 10", 4000) + print(res) + res <- dbGetQuery(con, "SELECT * FROM rockdata WHERE peri > $1 AND shape < $2 LIMIT $3", c(4000, 0.2, 10)) + print(res) + + + ## cleanup + if (dbExistsTable(con, "rockdata")) { + print("Removing rockdata\n") + dbRemoveTable(con, "rockdata") + } + + ## and disconnect + dbDisconnect(con) + } > > proc.time() user system elapsed 0.127 0.022 0.133 RPostgreSQL/tests/createTableMixedCaseTest.Rout.save0000644000176000001440000000603611637765112022255 0ustar ripleyusers R version 2.13.1 (2011-07-08) Copyright (C) 2011 The R Foundation for Statistical Computing ISBN 3-900051-07-0 Platform: x86_64-pc-linux-gnu (64-bit) R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. R is a collaborative project with many contributors. Type 'contributors()' for more information and 'citation()' on how to cite R or R packages in publications. Type 'demo()' for some demos, 'help()' for on-line help, or 'help.start()' for an HTML browser interface to help. Type 'q()' to quit R. > > ## createTableMixedCaseTest test > ## > ## > ## Assumes that > ## a) PostgreSQL is running, and > ## b) the current user can connect > ## both of which are not viable for release but suitable while we test > ## > ## Neil Tiffin, 30 Oct 2009 > > ## only run this if this env.var is set correctly > if (Sys.getenv("POSTGRES_USER") != "" & Sys.getenv("POSTGRES_HOST") != "" & Sys.getenv("POSTGRES_DATABASE") != "") { + + ## try to load our module and abort if this fails + stopifnot(require(RPostgreSQL)) + + ## load the PostgresSQL driver + drv <- dbDriver("PostgreSQL") + + ## connect to the default db + con <- dbConnect(drv, + user=Sys.getenv("POSTGRES_USER"), + password=Sys.getenv("POSTGRES_PASSWD"), + host=Sys.getenv("POSTGRES_HOST"), + dbname=Sys.getenv("POSTGRES_DATABASE"), + port=Sys.getenv("POSTGRES_PORT")) + + + + res <- dbGetQuery(con, "create table Foo1 (f1 int)") + res <- dbGetQuery(con, "create table \"Foo2\" (f1 int)") + + cat("Test should create foo1 and Foo2 tables\n") + ## res <- dbGetQuery(con, "SELECT * FROM information_schema.tables WHERE table_schema = 'public'") + ## print res + + if (dbExistsTable(con, "Foo1")) { + cat("FAIL - Foo1 Table exists.\n") + } + else { + cat("Pass - Foo1 Table does not exist.\n") + } + + if (dbExistsTable(con, "foo1")) { + cat("Pass - foo1 Table exists.\n") + } + else { + cat("FAIL - foo1 Table does not exist.\n") + } + + if (dbExistsTable(con, "Foo2")) { + cat("Pass - Foo2 Table exists.\n") + } + else { + cat("FAIL - Foo2 Table does not exist.\n") + } + + if (dbExistsTable(con, "foo2")) { + cat("FAIL - foo2 Table exists.\n") + } + else { + cat("Pass - foo2 Table does not exist.\n") + } + + if (dbExistsTable(con, "\"Foo2\"")) { + cat("FAIL - \"Foo2\" Table exists.\n") + } + else { + cat("Pass - \"Foo2\" Table does not exist.\n") + } + + if (dbExistsTable(con, "\"foo2\"")) { + cat("FAIL - \"foo2\" Table exists.\n") + } + else { + cat("Pass - \"foo2\" Table does not exist.\n") + } + + res <- dbGetQuery(con, "drop table Foo1") + res <- dbGetQuery(con, "drop table \"Foo2\"") + ## and disconnect + dbDisconnect(con) + } > RPostgreSQL/tests/dbExistsIssue.Rout.save0000644000176000001440000000460011455443410020200 0ustar ripleyusers R version 2.11.1 (2010-05-31) Copyright (C) 2010 The R Foundation for Statistical Computing ISBN 3-900051-07-0 R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. R is a collaborative project with many contributors. Type 'contributors()' for more information and 'citation()' on how to cite R or R packages in publications. Type 'demo()' for some demos, 'help()' for on-line help, or 'help.start()' for an HTML browser interface to help. Type 'q()' to quit R. > > ## dbExists test with schema name: reported as Issue 3 at > ## http://code.google.com/p/rpostgresql/issues/detail?id=3 > ## and based on an earlier email by Prasenjit Kapat > ## > ## Assumes that > ## a) PostgreSQL is running, and > ## b) the current user can connect > ## both of which are not viable for release but suitable while we test > ## > ## Dirk Eddelbuettel, 10 Sep 2009 > > ## only run this if this env.var is set correctly > if (Sys.getenv("POSTGRES_USER") != "" & Sys.getenv("POSTGRES_HOST") != "" & Sys.getenv("POSTGRES_DATABASE") != "") { + + ## try to load our module and abort if this fails + stopifnot(require(RPostgreSQL)) + stopifnot(require(datasets)) + + ## load the PostgresSQL driver + drv <- dbDriver("PostgreSQL") + + ## connect to the default db + con <- dbConnect(drv, + user=Sys.getenv("POSTGRES_USER"), + password=Sys.getenv("POSTGRES_PASSWD"), + host=Sys.getenv("POSTGRES_HOST"), + dbname=Sys.getenv("POSTGRES_DATABASE"), + port=ifelse((p<-Sys.getenv("POSTGRES_PORT"))!="", p, 5432)) + + if (dbExistsTable(con, "rockdata")) { + print("Removing rockdata\n") + dbRemoveTable(con, "rockdata") + } + + dbWriteTable(con, "rockdata", rock) + + ## run a simple dbExists + cat("Does rockdata exist? ") + print(res <- dbExistsTable(con, "rockdata")) + + ## this should return TRUE but did not -- does now after patch + cat("Does public.rockdata exist? ") + print(res <- dbExistsTable(con, "public.rockdata")) + + ## cleanup + if (dbExistsTable(con, "rockdata")) { + print("Removing rockdata\n") + dbRemoveTable(con, "rockdata") + } + + ## and disconnect + dbDisconnect(con) + } > RPostgreSQL/tests/createTableMixedCaseTest.R0000644000176000001440000000437611535162225020566 0ustar ripleyusers ## createTableMixedCaseTest test ## ## ## Assumes that ## a) PostgreSQL is running, and ## b) the current user can connect ## both of which are not viable for release but suitable while we test ## ## Neil Tiffin, 30 Oct 2009 ## only run this if this env.var is set correctly if (Sys.getenv("POSTGRES_USER") != "" & Sys.getenv("POSTGRES_HOST") != "" & Sys.getenv("POSTGRES_DATABASE") != "") { ## try to load our module and abort if this fails stopifnot(require(RPostgreSQL)) ## load the PostgresSQL driver drv <- dbDriver("PostgreSQL") ## connect to the default db con <- dbConnect(drv, user=Sys.getenv("POSTGRES_USER"), password=Sys.getenv("POSTGRES_PASSWD"), host=Sys.getenv("POSTGRES_HOST"), dbname=Sys.getenv("POSTGRES_DATABASE"), port=Sys.getenv("POSTGRES_PORT")) res <- dbGetQuery(con, "create table Foo1 (f1 int)") res <- dbGetQuery(con, "create table \"Foo2\" (f1 int)") cat("Test should create foo1 and Foo2 tables\n") ## res <- dbGetQuery(con, "SELECT * FROM information_schema.tables WHERE table_schema = 'public'") ## print res if (dbExistsTable(con, "Foo1")) { cat("FAIL - Foo1 Table exists.\n") } else { cat("Pass - Foo1 Table does not exist.\n") } if (dbExistsTable(con, "foo1")) { cat("Pass - foo1 Table exists.\n") } else { cat("FAIL - foo1 Table does not exist.\n") } if (dbExistsTable(con, "Foo2")) { cat("Pass - Foo2 Table exists.\n") } else { cat("FAIL - Foo2 Table does not exist.\n") } if (dbExistsTable(con, "foo2")) { cat("FAIL - foo2 Table exists.\n") } else { cat("Pass - foo2 Table does not exist.\n") } if (dbExistsTable(con, "\"Foo2\"")) { cat("FAIL - \"Foo2\" Table exists.\n") } else { cat("Pass - \"Foo2\" Table does not exist.\n") } if (dbExistsTable(con, "\"foo2\"")) { cat("FAIL - \"foo2\" Table exists.\n") } else { cat("Pass - \"foo2\" Table does not exist.\n") } res <- dbGetQuery(con, "drop table Foo1") res <- dbGetQuery(con, "drop table \"Foo2\"") ## and disconnect dbDisconnect(con) } RPostgreSQL/tests/dbExistsq.R0000644000176000001440000000335311455242162015670 0ustar ripleyusers ## dbExists test with schema name: reported as Issue 3 at ## http://code.google.com/p/rpostgresql/issues/detail?id=3 ## and based on an earlier email by Prasenjit Kapat ## ## Assumes that ## a) PostgreSQL is running, and ## b) the current user can connect ## both of which are not viable for release but suitable while we test ## ## Dirk Eddelbuettel, 10 Sep 2009 ## only run this if this env.var is set correctly if (Sys.getenv("POSTGRES_USER") != "" & Sys.getenv("POSTGRES_HOST") != "" & Sys.getenv("POSTGRES_DATABASE") != "") { ## try to load our module and abort if this fails stopifnot(require(RPostgreSQL)) stopifnot(require(datasets)) ## load the PostgresSQL driver drv <- dbDriver("PostgreSQL") ## connect to the default db con <- dbConnect(drv, user=Sys.getenv("POSTGRES_USER"), password=Sys.getenv("POSTGRES_PASSWD"), host=Sys.getenv("POSTGRES_HOST"), dbname=Sys.getenv("POSTGRES_DATABASE"), port=ifelse((p<-Sys.getenv("POSTGRES_PORT"))!="", p, 5432)) if (dbExistsTable(con, "rock'data")) { cat("Removing rock'data\n") dbRemoveTable(con, "rock'data") } cat("Write rock'data\n") dbWriteTable(con, "rock'data", rock) ## run a simple dbExists cat("Does rock'data exist? ") print(res <- dbExistsTable(con, "rock'data")) ## this should return TRUE but did not -- does now after patch cat("Does \"public.rock'data\" exist? ") print(res <- dbExistsTable(con, "public.rock'data")) ## cleanup if (dbExistsTable(con, "rock'data")) { cat("Removing rock'data\n") dbRemoveTable(con, "rock'data") } ## and disconnect dbDisconnect(con) } RPostgreSQL/tests/dbTransactionTests.R0000644000176000001440000000573712005446536017553 0ustar ripleyusers ## dbWriteTable test ## ## Assumes that ## a) PostgreSQL is running, and ## b) the current user can connect ## both of which are not viable for release but suitable while we test ## ## Dirk Eddelbuettel, 10 Sep 2009 ## only run this if this env.var is set correctly if (Sys.getenv("POSTGRES_USER") != "" & Sys.getenv("POSTGRES_HOST") != "" & Sys.getenv("POSTGRES_DATABASE") != "") { ## try to load our module and abort if this fails stopifnot(require(RPostgreSQL)) stopifnot(require(datasets)) ## load the PostgresSQL driver drv <- dbDriver("PostgreSQL") ## create two independent connections con1 <- dbConnect(drv, user=Sys.getenv("POSTGRES_USER"), password=Sys.getenv("POSTGRES_PASSWD"), host=Sys.getenv("POSTGRES_HOST"), dbname=Sys.getenv("POSTGRES_DATABASE"), port=ifelse((p<-Sys.getenv("POSTGRES_PORT"))!="", p, 5432)) con2 <- dbConnect(drv, user=Sys.getenv("POSTGRES_USER"), password=Sys.getenv("POSTGRES_PASSWD"), host=Sys.getenv("POSTGRES_HOST"), dbname=Sys.getenv("POSTGRES_DATABASE"), port=ifelse((p<-Sys.getenv("POSTGRES_PORT"))!="", p, 5432)) if (dbExistsTable(con1, "rockdata")) { cat("Removing rockdata\n") dbRemoveTable(con1, "rockdata") } cat("begin transaction in con1\n") dbGetQuery(con1, "BEGIN TRANSACTION") cat("create table rockdata in con1\n") dbWriteTable(con1, "rockdata", rock) if (dbExistsTable(con1, "rockdata")) { cat("PASS rockdata is visible through con1\n") }else{ cat("FAIL rockdata is invisible through con1\n") } if (dbExistsTable(con2, "rockdata")) { cat("FAIL rockdata is visible through con2\n") }else{ cat("PASS rockdata is invisible through con2\n") } cat("commit in con1\n") dbCommit(con1) if (dbExistsTable(con2, "rockdata")) { cat("PASS rockdata is visible through con2\n") }else{ cat("FAIL rockdata is invisible through con2\n") } cat("remove the table from con1\n") dbRemoveTable(con1, "rockdata") if (dbExistsTable(con2, "rockdata")) { cat("FAIL rockdata is visible through con2\n") }else{ cat("PASS rockdata is invisible through con2\n") } cat("begin transaction in con1\n") dbGetQuery(con1, "BEGIN TRANSACTION") cat("create table rockdata in con1\n") dbWriteTable(con1, "rockdata", rock) if (dbExistsTable(con1, "rockdata")) { cat("PASS rockdata is visible through con1\n") }else{ cat("FAIL rockdata is invisible through con1\n") } cat("RollBack con1\n") dbRollback(con1) if (dbExistsTable(con1, "rockdata")) { cat("FAIL rockdata is visible through con1\n") }else{ cat("PASS rockdata is invisible through con1\n") } ## and disconnect dbDisconnect(con2) dbDisconnect(con1) } RPostgreSQL/tests/dbListFields.Rout.save0000644000176000001440000000511512124517166017760 0ustar ripleyusers R version 2.15.2 (2012-10-26) -- "Trick or Treat" Copyright (C) 2012 The R Foundation for Statistical Computing ISBN 3-900051-07-0 Platform: x86_64-unknown-linux-gnu (64-bit) R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. R is a collaborative project with many contributors. Type 'contributors()' for more information and 'citation()' on how to cite R or R packages in publications. Type 'demo()' for some demos, 'help()' for on-line help, or 'help.start()' for an HTML browser interface to help. Type 'q()' to quit R. > ## dbListFields test > ## > ## Assumes that > ## a) PostgreSQL is running, and > ## b) the current user can connect > ## both of which are not viable for release but suitable while we test > ## > > ## only run this if this env.var is set correctly > if (Sys.getenv("POSTGRES_USER") != "" & Sys.getenv("POSTGRES_HOST") != "" & Sys.getenv("POSTGRES_DATABASE") != "") { + + ## try to load our module and abort if this fails + stopifnot(require(RPostgreSQL)) + + ## load the PostgresSQL driver + drv <- dbDriver("PostgreSQL") + + ## connect to the default db + con <- dbConnect(drv, + user=Sys.getenv("POSTGRES_USER"), + password=Sys.getenv("POSTGRES_PASSWD"), + host=Sys.getenv("POSTGRES_HOST"), + dbname=Sys.getenv("POSTGRES_DATABASE"), + port=ifelse((p<-Sys.getenv("POSTGRES_PORT"))!="", p, 5432)) + + + # create a table + res <- dbGetQuery(con, "CREATE SCHEMA testschema") + res <- dbGetQuery(con, "CREATE TABLE testschema.aa (pid integer, name text)") + res <- dbGetQuery(con, "CREATE TABLE aa (pk integer, v1 float not null, v2 float)" ) + + ## run a simple query and show the query result + df <- dbListFields(con, "aa") + print(df) + if (length(df) == 3){ + cat("PASS: 3 fields returned\n") + }else{ + cat(paste("FAIL:", length(df), "fields returned\n")) + } + + df <- dbListFields(con, c("testschema", "aa")) + print(df) + if (length(df) == 2){ + cat("PASS: 2 fields returned\n") + }else{ + cat(paste("FAIL:", length(df), "fields returned\n")) + } + + + ## cleanup + cat("Removing \"AA\"\n") + dbRemoveTable(con, "aa") + dbGetQuery(con, "DROP TABLE testschema.aa") + dbGetQuery(con, "DROP SCHEMA testschema") + ## and disconnect + dbDisconnect(con) + } > > proc.time() user system elapsed 0.134 0.018 0.136 RPostgreSQL/tests/dbWriteTableTest.R0000644000176000001440000000263711455305076017142 0ustar ripleyusers ## dbWriteTable test ## ## Assumes that ## a) PostgreSQL is running, and ## b) the current user can connect ## both of which are not viable for release but suitable while we test ## ## Dirk Eddelbuettel, 10 Sep 2009 ## only run this if this env.var is set correctly if (Sys.getenv("POSTGRES_USER") != "" & Sys.getenv("POSTGRES_HOST") != "" & Sys.getenv("POSTGRES_DATABASE") != "") { ## try to load our module and abort if this fails stopifnot(require(RPostgreSQL)) stopifnot(require(datasets)) ## load the PostgresSQL driver drv <- dbDriver("PostgreSQL") ## connect to the default db con <- dbConnect(drv, user=Sys.getenv("POSTGRES_USER"), password=Sys.getenv("POSTGRES_PASSWD"), host=Sys.getenv("POSTGRES_HOST"), dbname=Sys.getenv("POSTGRES_DATABASE"), port=ifelse((p<-Sys.getenv("POSTGRES_PORT"))!="", p, 5432)) if (dbExistsTable(con, "rockdata")) { print("Removing rockdata\n") dbRemoveTable(con, "rockdata") } dbWriteTable(con, "rockdata", rock) ## run a simple query and show the query result res <- dbGetQuery(con, "select * from rockdata limit 10") print(res) ## cleanup if (dbExistsTable(con, "rockdata")) { print("Removing rockdata\n") dbRemoveTable(con, "rockdata") } ## and disconnect dbDisconnect(con) } RPostgreSQL/tests/dbExistsqc.R0000644000176000001440000000532111534641277016040 0ustar ripleyusers ## dbExistsq test with schema name: reported as Issue 28 at ## http://code.google.com/p/rpostgresql/issues/detail?id=28 ## ## Assumes that ## a) PostgreSQL is running, and ## b) the current user can connect ## both of which are not viable for release but suitable while we test ## ## Dirk Eddelbuettel, 10 Sep 2009 ## only run this if this env.var is set correctly if (Sys.getenv("POSTGRES_USER") != "" & Sys.getenv("POSTGRES_HOST") != "" & Sys.getenv("POSTGRES_DATABASE") != "") { ## try to load our module and abort if this fails stopifnot(require(RPostgreSQL)) stopifnot(require(datasets)) ## load the PostgresSQL driver drv <- dbDriver("PostgreSQL") ## connect to the default db con <- dbConnect(drv, user=Sys.getenv("POSTGRES_USER"), password=Sys.getenv("POSTGRES_PASSWD"), host=Sys.getenv("POSTGRES_HOST"), dbname=Sys.getenv("POSTGRES_DATABASE"), port=ifelse((p<-Sys.getenv("POSTGRES_PORT"))!="", p, 5432)) if (dbExistsTable(con, "rock.data")) { cat("Removing rock'data\n") dbRemoveTable(con, "rock.data") } dbWriteTable(con, "rock.data", rock) ## run a simple dbExists cat("Does rock.data exist? \n") res <- dbExistsTable(con, "rock.data") if(res){ cat("PASS: true\n") }else{ cat("FAIL: false\n") } ## cat("create schema testschema and change the search_path\n") dbGetQuery(con, 'CREATE SCHEMA testschema') dbGetQuery(con, 'SET search_path TO testschema') cat("Does rock.data exist? \n") res <- dbExistsTable(con, "rock.data") if(res){ cat("FAIL: true despite search_path change\n") }else{ cat("PASS: false as the search_path changed\n") } cat("Does testschema.\"rock.data\" exist? \n") res <- dbExistsTable(con, c('testschema', "rock.data")) if(res){ cat("FAIL: true despite testschema specified\n") }else{ cat("PASS: false as the testschema specified\n") } cat("Does public.\"rock.data\" exist? \n") res <- dbExistsTable(con, c('public', "rock.data")) if(res){ cat("PASS: true despite search_path change\n") }else{ cat("FAIL: false as the search_path changed\n") } cat("write in current schema\n") dbWriteTable(con, "rock.data", rock) cat("Does rock.data exist? \n") res <- dbExistsTable(con, "rock.data") if(res){ cat("PASS: true\n") }else{ cat("FAIL: false\n") } ## cleanup dbGetQuery(con, 'DROP TABLE "public"."rock.data"') dbGetQuery(con, 'DROP TABLE "testschema"."rock.data"') dbGetQuery(con, 'DROP schema "testschema"') ## and disconnect dbDisconnect(con) } RPostgreSQL/tests/datetimeTests.Rout.save0000644000176000001440000000560712124517166020235 0ustar ripleyusers R version 2.15.2 (2012-10-26) -- "Trick or Treat" Copyright (C) 2012 The R Foundation for Statistical Computing ISBN 3-900051-07-0 Platform: x86_64-unknown-linux-gnu (64-bit) R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. R is a collaborative project with many contributors. Type 'contributors()' for more information and 'citation()' on how to cite R or R packages in publications. Type 'demo()' for some demos, 'help()' for on-line help, or 'help.start()' for an HTML browser interface to help. Type 'q()' to quit R. > > ## Test of date and datetime types, based on earlier version in inst/devTests > ## > ## Dirk Eddelbuettel, 21 Oct 2008 > > dbTypeTests <- function(con, dateclass="timestamp without time zone") { + cat("\n\n**** Trying with ", dateclass, "\n") + + if (dbExistsTable(con, "tempostgrestable")) + dbRemoveTable(con, "tempostgrestable") + + dbGetQuery(con, paste("create table tempostgrestable (tt ", dateclass, ", zz integer);", sep="")) + dbGetQuery(con, "insert into tempostgrestable values('2008-07-01 14:15:16.123', 1);") + + now <- ISOdatetime(2000,1,2,3,4,5.678) + dbGetQuery(con, paste("insert into tempostgrestable values('", format(now), "', 2);", sep="")) + + res <- dbReadTable(con, "tempostgrestable") + print(res) + + res <- dbSendQuery(con, "select tt from tempostgrestable;") + data <- fetch(res, n=-1) + print(dbColumnInfo(res)) + + times <- data[,1] + print(times) + print(class(times[1])) + + print(diff(times)) + + dbRemoveTable(con, "tempostgrestable") + invisible(NULL) + } > > ## only run this if this env.var is set correctly > if ((Sys.getenv("POSTGRES_USER") != "") & + (Sys.getenv("POSTGRES_HOST") != "") & + (Sys.getenv("POSTGRES_DATABASE") != "")) { + + ## try to load our module and abort if this fails + stopifnot(require(RPostgreSQL)) + + ## Force a timezone to make the tests comparable at different locations + Sys.setenv("PGDATESTYLE"="German") + Sys.setenv("TZ"="UTC") + + ## load the PostgresSQL driver + drv <- dbDriver("PostgreSQL") + ## can't print result as it contains process id which changes print(summary(drv)) + + ## connect to the default db + con <- dbConnect(drv, + user=Sys.getenv("POSTGRES_USER"), + password=Sys.getenv("POSTGRES_PASSWD"), + host=Sys.getenv("POSTGRES_HOST"), + dbname=Sys.getenv("POSTGRES_DATABASE"), + port=ifelse((p<-Sys.getenv("POSTGRES_PORT"))!="", p, 5432)) + + dbTypeTests(con, "timestamp") + dbTypeTests(con, "timestamp with time zone") + dbTypeTests(con, "date") + + dbDisconnect(con) + } > > > proc.time() user system elapsed 0.130 0.022 0.134 RPostgreSQL/tests/dbWriteTableSchema.Rout.save0000644000176000001440000000443412124517166021104 0ustar ripleyusers R version 2.15.2 (2012-10-26) -- "Trick or Treat" Copyright (C) 2012 The R Foundation for Statistical Computing ISBN 3-900051-07-0 Platform: x86_64-unknown-linux-gnu (64-bit) R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. R is a collaborative project with many contributors. Type 'contributors()' for more information and 'citation()' on how to cite R or R packages in publications. Type 'demo()' for some demos, 'help()' for on-line help, or 'help.start()' for an HTML browser interface to help. Type 'q()' to quit R. > > ## dbWriteTable test > ## > ## Assumes that > ## a) PostgreSQL is running, and > ## b) the current user can connect > ## both of which are not viable for release but suitable while we test > ## > ## Dirk Eddelbuettel, 10 Sep 2009 > > ## only run this if this env.var is set correctly > if (Sys.getenv("POSTGRES_USER") != "" & Sys.getenv("POSTGRES_HOST") != "" & Sys.getenv("POSTGRES_DATABASE") != "") { + + ## try to load our module and abort if this fails + stopifnot(require(RPostgreSQL)) + stopifnot(require(datasets)) + + ## load the PostgresSQL driver + drv <- dbDriver("PostgreSQL") + + ## connect to the default db + con <- dbConnect(drv, + user=Sys.getenv("POSTGRES_USER"), + password=Sys.getenv("POSTGRES_PASSWD"), + host=Sys.getenv("POSTGRES_HOST"), + dbname=Sys.getenv("POSTGRES_DATABASE"), + port=ifelse((p<-Sys.getenv("POSTGRES_PORT"))!="", p, 5432)) + + + if (dbExistsTable(con, c("public", "rockdata"))) { + print("Removing rockdata\n") + dbRemoveTable(con, c("public", "rockdata")) + } + + dbWriteTable(con, c("public", "rockdata"), rock) + + ## run a simple query and show the query result + res <- dbGetQuery(con, "select * from public.rockdata limit 10") + print(res) + + + ## cleanup + if (dbExistsTable(con, c("public", "rockdata"))) { + print("Removing rockdata\n") + dbRemoveTable(con, c("public", "rockdata")) + } + + ## and disconnect + dbDisconnect(con) + } > > proc.time() user system elapsed 0.130 0.023 0.136 RPostgreSQL/tests/dataTypeTests.R0000644000176000001440000000720611535162225016521 0ustar ripleyusers## Test of data types, based on earlier version in inst/devTests ## ## Dirk Eddelbuettel, 21 Oct 2008 if ((Sys.getenv("POSTGRES_USER") != "") & (Sys.getenv("POSTGRES_HOST") != "") & (Sys.getenv("POSTGRES_DATABASE") != "")) { ## try to load our module and abort if this fails stopifnot(require(RPostgreSQL)) ## load the PostgresSQL driver drv <- dbDriver("PostgreSQL") ## can't print result as it contains process id which changes print(summary(drv)) ## connect to the default db con <- dbConnect(drv, user=Sys.getenv("POSTGRES_USER"), password=Sys.getenv("POSTGRES_PASSWD"), host=Sys.getenv("POSTGRES_HOST"), dbname=Sys.getenv("POSTGRES_DATABASE"), port=ifelse((p<-Sys.getenv("POSTGRES_PORT"))!="", p, 5432)) if (dbExistsTable(con, "tempostgrestable")) dbRemoveTable(con, "tempostgrestable") ## Test the numeric mapping dbGetQuery(con, "create table tempostgrestable (intcolumn integer, floatcolumn float);") i <- as.integer(10) j <- as.numeric(56.6) sql <- paste("insert into tempostgrestable ", "values (",i, "," ,j ,") ", sep="") res <- dbGetQuery(con, sql) dat <- dbReadTable(con, "tempostgrestable") dbRemoveTable(con, "tempostgrestable") cat("Read Numeric values\n") ## now test the types of the colums we got stopifnot( class(dat[,1]) == "integer" ) stopifnot( class(dat[,2]) == "numeric" ) cat("GOOD -- all numeric types are as expected\n") ## and test the values stopifnot( identical( dat[1,1], i)) stopifnot( identical( dat[1,2], j)) cat("GOOD -- all numeric values are as expected\n") ## Test the logical mapping if (dbExistsTable(con, "testlogical")) dbRemoveTable(con, "testlogical") dbGetQuery(con,"create table testlogical (col1 boolean, col2 boolean)") i <- as.logical(TRUE) j <- as.logical(FALSE) sql <- paste("insert into testlogical ", "values (",i, "," ,j ,") ", sep="") res <- dbGetQuery(con, sql); dat <- dbReadTable(con, "testlogical") dbRemoveTable(con, "testlogical") cat("Read Logical values\n") ## now test the types of the colums we got stopifnot( class(dat[,1]) == "logical" ) stopifnot( class(dat[,2]) == "logical" ) cat("GOOD -- all logical types are as expected\n") ## and test the values stopifnot( identical( dat[1,1], i)) stopifnot( identical( dat[1,2], j)) cat("GOOD -- all logical values are as expected\n") ## Test the character mapping if (dbExistsTable(con, "testchar")) dbRemoveTable(con, "testchar") dbGetQuery(con,"create table testchar (code char(3),city varchar(20),country text);") i <- as.character("IN") j <- as.character("Hyderabad") k <- as.character("India") sql <- paste("insert into testchar ", "values ('",i,"' , '",j ,"' , '",k,"') ", sep="") res <- dbGetQuery(con, sql); dat <- dbReadTable(con, "testchar") cat("Read Character values\n") ## now test the types of the colums we got stopifnot( class(dat[,1]) == "character" ) stopifnot( class(dat[,2]) == "character" ) stopifnot( class(dat[,3]) == "character" ) cat("GOOD -- all character types are as expected\n") ## and test the values ##stopifnot( identical( dat[1,1], i)) stopifnot( identical( dat[1,2], j)) stopifnot( identical( dat[1,3], k)) cat("GOOD -- all character values are as expected\n") dbRemoveTable(con, "testchar") dbRemoveTable(con, "tempostgrestable") dbDisconnect(con) dbUnloadDriver(drv) cat("DONE\n") } RPostgreSQL/tests/dateTZ.Rout.save0000644000176000001440000000767112124517166016614 0ustar ripleyusers R version 2.15.2 (2012-10-26) -- "Trick or Treat" Copyright (C) 2012 The R Foundation for Statistical Computing ISBN 3-900051-07-0 Platform: x86_64-unknown-linux-gnu (64-bit) R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. R is a collaborative project with many contributors. Type 'contributors()' for more information and 'citation()' on how to cite R or R packages in publications. Type 'demo()' for some demos, 'help()' for on-line help, or 'help.start()' for an HTML browser interface to help. Type 'q()' to quit R. > > ## Test of date and datetime types, based on earlier version in inst/devTests > ## > ## Dirk Eddelbuettel, 21 Oct 2008 > > dbTypeTests <- function(con, dateclass="timestamp without time zone", tz="UTC") { + cat("\n\n**** Trying with ", dateclass, "\n") + + if (dbExistsTable(con, "tempostgrestable")) + dbRemoveTable(con, "tempostgrestable") + + dbGetQuery(con, paste("create table tempostgrestable (tt ", dateclass, ", zz integer);", sep="")) + insstring <- '2008-07-01 14:15:16.123+00' + cat(paste('inserted string 1:', insstring)) + cat("\n") + dbGetQuery(con, paste("insert into tempostgrestable values('", insstring, "', 1);", sep="")) + + # now <- ISOdatetime(2000,1,2,3,4,5.678) + insstring <- '2000-01-02 03:04:05.678+00' + cat(paste('inserted string 2:', insstring)) + cat("\n") + dbGetQuery(con, paste("insert into tempostgrestable values('", insstring, "', 2);", sep="")) + tt<-as.POSIXct(c("2008-07-01 23:45:16.123+0930","2000-01-02 13:34:05.678+1030"), format="%Y-%m-%d %H:%M:%OS%z") + print(tt) + + dbGetQuery(con, paste("SET TIMEZONE TO '", tz, "'", sep="")) + + data <- dbGetQuery(con, "select tt from tempostgrestable;") + + times <- data[,1] + print(times) + if(as.double(tt[1]) == as.double(times[1])){ + cat('PASS\n') + }else{ + cat('FAIL\n') + } + if(as.double(tt[2]) == as.double(times[2])){ + cat('PASS\n') + }else{ + cat('FAIL\n') + } + + + dbRemoveTable(con, "tempostgrestable") + invisible(NULL) + } > > ## only run this if this env.var is set correctly > if ((Sys.getenv("POSTGRES_USER") != "") & + (Sys.getenv("POSTGRES_HOST") != "") & + (Sys.getenv("POSTGRES_DATABASE") != "")) { + + ## try to load our module and abort if this fails + stopifnot(require(RPostgreSQL)) + + ## Force a timezone to make the tests comparable at different locations + Sys.setenv("TZ"="UTC") + tt<-as.POSIXct(c("2008-07-01 23:45:16.123+0930","2000-01-02 13:34:05.678+1030"), format="%Y-%m-%d %H:%M:%OS%z") + print(tt) + + ## load the PostgresSQL driver + drv <- dbDriver("PostgreSQL") + ## can't print result as it contains process id which changes print(summary(drv)) + + ## connect to the default db + con <- dbConnect(drv, + user=Sys.getenv("POSTGRES_USER"), + password=Sys.getenv("POSTGRES_PASSWD"), + host=Sys.getenv("POSTGRES_HOST"), + dbname=Sys.getenv("POSTGRES_DATABASE"), + port=ifelse((p<-Sys.getenv("POSTGRES_PORT"))!="", p, 5432)) + + cat('testing UTC') + dbTypeTests(con, "timestamp") + dbTypeTests(con, "timestamp with time zone") + cat('testing Asia/Tokyo') + dbTypeTests(con, "timestamp", tz="Asia/Tokyo") + dbTypeTests(con, "timestamp with time zone", tz="Asia/Tokyo") + cat('testing Australlia/South') + dbTypeTests(con, "timestamp", tz="Australia/South") + dbTypeTests(con, "timestamp with time zone", tz="Australia/South") + cat('testing America/New_York') + dbTypeTests(con, "timestamp", tz="America/New_York") + dbTypeTests(con, "timestamp with time zone", tz="America/New_York") + + dbDisconnect(con) + } > > > proc.time() user system elapsed 0.131 0.027 0.141 RPostgreSQL/tests/dbListFields.R0000644000176000001440000000341211637765112016275 0ustar ripleyusers## dbListFields test ## ## Assumes that ## a) PostgreSQL is running, and ## b) the current user can connect ## both of which are not viable for release but suitable while we test ## ## only run this if this env.var is set correctly if (Sys.getenv("POSTGRES_USER") != "" & Sys.getenv("POSTGRES_HOST") != "" & Sys.getenv("POSTGRES_DATABASE") != "") { ## try to load our module and abort if this fails stopifnot(require(RPostgreSQL)) ## load the PostgresSQL driver drv <- dbDriver("PostgreSQL") ## connect to the default db con <- dbConnect(drv, user=Sys.getenv("POSTGRES_USER"), password=Sys.getenv("POSTGRES_PASSWD"), host=Sys.getenv("POSTGRES_HOST"), dbname=Sys.getenv("POSTGRES_DATABASE"), port=ifelse((p<-Sys.getenv("POSTGRES_PORT"))!="", p, 5432)) # create a table res <- dbGetQuery(con, "CREATE SCHEMA testschema") res <- dbGetQuery(con, "CREATE TABLE testschema.aa (pid integer, name text)") res <- dbGetQuery(con, "CREATE TABLE aa (pk integer, v1 float not null, v2 float)" ) ## run a simple query and show the query result df <- dbListFields(con, "aa") print(df) if (length(df) == 3){ cat("PASS: 3 fields returned\n") }else{ cat(paste("FAIL:", length(df), "fields returned\n")) } df <- dbListFields(con, c("testschema", "aa")) print(df) if (length(df) == 2){ cat("PASS: 2 fields returned\n") }else{ cat(paste("FAIL:", length(df), "fields returned\n")) } ## cleanup cat("Removing \"AA\"\n") dbRemoveTable(con, "aa") dbGetQuery(con, "DROP TABLE testschema.aa") dbGetQuery(con, "DROP SCHEMA testschema") ## and disconnect dbDisconnect(con) } RPostgreSQL/tests/openSendQuery.Rout.save0000644000176000001440000000603212124517166020210 0ustar ripleyusers R version 2.15.2 (2012-10-26) -- "Trick or Treat" Copyright (C) 2012 The R Foundation for Statistical Computing ISBN 3-900051-07-0 Platform: x86_64-unknown-linux-gnu (64-bit) R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. R is a collaborative project with many contributors. Type 'contributors()' for more information and 'citation()' on how to cite R or R packages in publications. Type 'demo()' for some demos, 'help()' for on-line help, or 'help.start()' for an HTML browser interface to help. Type 'q()' to quit R. > > ## dbWriteTable test > ## > ## Assumes that > ## a) PostgreSQL is running, and > ## b) the current user can connect > ## both of which are not viable for release but suitable while we test > ## > ## Dirk Eddelbuettel, 10 Sep 2009 > > ## only run this if this env.var is set correctly > if (Sys.getenv("POSTGRES_USER") != "" & Sys.getenv("POSTGRES_HOST") != "" & Sys.getenv("POSTGRES_DATABASE") != "") { + + ## try to load our module and abort if this fails + stopifnot(require(RPostgreSQL)) + stopifnot(require(datasets)) + + ## load the PostgresSQL driver + drv <- dbDriver("PostgreSQL") + + ## create two independent connections + con <- dbConnect(drv, + user=Sys.getenv("POSTGRES_USER"), + password=Sys.getenv("POSTGRES_PASSWD"), + host=Sys.getenv("POSTGRES_HOST"), + dbname=Sys.getenv("POSTGRES_DATABASE"), + port=ifelse((p<-Sys.getenv("POSTGRES_PORT"))!="", p, 5432)) + + if (dbExistsTable(con, "tmptest")) { + cat("Removing tmptest\n") + dbRemoveTable(con, "tmptest") + } + # create temporary table (as a copy of any existing one) + # dbGetQuery(con, "BEGIN TRANSACTION") + cat("create temp table tmptest with dbGetQuery\n") + dbGetQuery(con, "CREATE TEMP TABLE tmptest (f1 int)") + + # query temp table + rs<-dbGetQuery(con, "SELECT * from tmptest") + print(rs) + + cat("create temp table tmptest with dbSendQuery\n") + dbSendQuery(con, "CREATE TEMP TABLE tmptest2(f2 int)") + + # query temp table + rs2<-dbGetQuery(con, "SELECT * from tmptest2") + print(rs2) + ## and disconnect + dbDisconnect(con) + + con <- dbConnect(drv, + user=Sys.getenv("POSTGRES_USER"), + password=Sys.getenv("POSTGRES_PASSWD"), + host=Sys.getenv("POSTGRES_HOST"), + dbname=Sys.getenv("POSTGRES_DATABASE"), + port=ifelse((p<-Sys.getenv("POSTGRES_PORT"))!="", p, 5432)) + + if (dbExistsTable(con, "tmptest")) { + cat("FAIL tmptest persisted after disconnection\n") + cat("Removing tmptest\n") + dbRemoveTable(con, "tmptest") + }else{ + cat("PASS tmptest disappeared after disconnection\n") + } + dbDisconnect(con) + } > > proc.time() user system elapsed 0.134 0.019 0.135 RPostgreSQL/tests/unknowntype.R0000644000176000001440000000332712005446536016327 0ustar ripleyusers ## selectWhereZero test ## ## test for the 'Issue 1' on the Google Code issue log ## this was reported in June and fixed by Joe Conway (svr committ r100) ## ## Assumes that ## a) PostgreSQL is running, and ## b) the current user can connect ## both of which are not viable for release but suitable while we test ## ## Dirk Eddelbuettel, 03 Oct 2009 ## only run this if this env.var is set correctly if (Sys.getenv("POSTGRES_USER") != "" & Sys.getenv("POSTGRES_HOST") != "" & Sys.getenv("POSTGRES_DATABASE") != "") { ## try to load our module and abort if this fails stopifnot(require(RPostgreSQL)) ## load the PostgresSQL driver drv <- dbDriver("PostgreSQL") ## connect to the default db con <- dbConnect(drv, user=Sys.getenv("POSTGRES_USER"), password=Sys.getenv("POSTGRES_PASSWD"), host=Sys.getenv("POSTGRES_HOST"), dbname=Sys.getenv("POSTGRES_DATABASE"), port=ifelse((p<-Sys.getenv("POSTGRES_PORT"))!="", p, 5432)) if (dbExistsTable(con, "tmpirisdata")) { print("Removing tmpirisdata\n") dbRemoveTable(con, "tmpirisdata") } ## run a simple query and show the query result res <- dbGetQuery(con, "create table tmpirisdata (ra REAL[])") res <- dbSendQuery(con, "select ra from tmpirisdata") print(res) type <- dbColumnInfo(res) print(type) data <- fetch(res, -1) print(data) ## cleanup if (dbExistsTable(con, "tmpirisdata")) { print("Removing tmpirisdata\n") dbRemoveTable(con, "tmpirisdata") } ## and disconnect dbDisconnect(con) cat("PASS: reached to the end of the test code without segmentation fault\n") } RPostgreSQL/tests/dbGetQueryParams.R0000644000176000001440000000304412060130033017120 0ustar ripleyusers## dbGetQuery test with optional parameters ## ## Assumes that ## a) PostgreSQL is running, and ## b) the current user can connect ## both of which are not viable for release but suitable while we test ## only run this if this env.var is set correctly if (Sys.getenv("POSTGRES_USER") != "" & Sys.getenv("POSTGRES_HOST") != "" & Sys.getenv("POSTGRES_DATABASE") != "") { ## try to load our module and abort if this fails stopifnot(require(RPostgreSQL)) stopifnot(require(datasets)) ## load the PostgresSQL driver drv <- dbDriver("PostgreSQL") ## connect to the default db con <- dbConnect(drv, user=Sys.getenv("POSTGRES_USER"), password=Sys.getenv("POSTGRES_PASSWD"), host=Sys.getenv("POSTGRES_HOST"), dbname=Sys.getenv("POSTGRES_DATABASE"), port=ifelse((p<-Sys.getenv("POSTGRES_PORT"))!="", p, 5432)) if (dbExistsTable(con, "rockdata")) { print("Removing rockdata\n") dbRemoveTable(con, "rockdata") } dbWriteTable(con, "rockdata", rock) ## run a simple query and show the query result res <- dbGetQuery(con, "SELECT * FROM rockdata WHERE peri > $1 LIMIT 10", 4000) print(res) res <- dbGetQuery(con, "SELECT * FROM rockdata WHERE peri > $1 AND shape < $2 LIMIT $3", c(4000, 0.2, 10)) print(res) ## cleanup if (dbExistsTable(con, "rockdata")) { print("Removing rockdata\n") dbRemoveTable(con, "rockdata") } ## and disconnect dbDisconnect(con) } RPostgreSQL/tests/connectWithNull.R0000644000176000001440000000235711455242162017045 0ustar ripleyusers ## connectWithNull test ## ## test for the 'Issue 2' on the Google Code issue log ## reported in April 2009, still open ? ## ## Assumes that ## a) PostgreSQL is running, and ## b) the current user can connect ## both of which are not viable for release but suitable while we test ## ## Dirk Eddelbuettel, 03 Oct 2009 ## only run this if this env.var is set correctly if (Sys.getenv("POSTGRES_USER") != "" & Sys.getenv("POSTGRES_HOST") != "" & Sys.getenv("POSTGRES_DATABASE") != "") { ## try to load our module and abort if this fails stopifnot(require(RPostgreSQL)) stopifnot(require(datasets)) ## load the PostgresSQL driver drv <- dbDriver("PostgreSQL") ## connect to the default db -- replacing any of these with NULL will lead to ## a stop() call and a return to the R prompt rather than a segfault con <- dbConnect(drv, user=Sys.getenv("POSTGRES_USER"), password=Sys.getenv("POSTGRES_PASSWD"), host=Sys.getenv("POSTGRES_HOST"), dbname=Sys.getenv("POSTGRES_DATABASE"), port=ifelse((p<-Sys.getenv("POSTGRES_PORT"))!="", p, 5432)) ## do we get here? print(con) ## and disconnect dbDisconnect(con) } RPostgreSQL/tests/selectWhereZero.Rout.save0000644000176000001440000000460511455443410020521 0ustar ripleyusers R version 2.12.0 RC (2010-10-07 r53227) Copyright (C) 2010 The R Foundation for Statistical Computing ISBN 3-900051-07-0 Platform: x86_64-pc-linux-gnu (64-bit) R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. R is a collaborative project with many contributors. Type 'contributors()' for more information and 'citation()' on how to cite R or R packages in publications. Type 'demo()' for some demos, 'help()' for on-line help, or 'help.start()' for an HTML browser interface to help. Type 'q()' to quit R. > > ## selectWhereZero test > ## > ## test for the 'Issue 1' on the Google Code issue log > ## this was reported in June and fixed by Joe Conway (svr committ r100) > ## > ## Assumes that > ## a) PostgreSQL is running, and > ## b) the current user can connect > ## both of which are not viable for release but suitable while we test > ## > ## Dirk Eddelbuettel, 03 Oct 2009 > > ## only run this if this env.var is set correctly > if (Sys.getenv("POSTGRES_USER") != "" & Sys.getenv("POSTGRES_HOST") != "" & Sys.getenv("POSTGRES_DATABASE") != "") { + + ## try to load our module and abort if this fails + stopifnot(require(RPostgreSQL)) + stopifnot(require(datasets)) + + ## load the PostgresSQL driver + drv <- dbDriver("PostgreSQL") + + ## connect to the default db + con <- dbConnect(drv, + user=Sys.getenv("POSTGRES_USER"), + password=Sys.getenv("POSTGRES_PASSWD"), + host=Sys.getenv("POSTGRES_HOST"), + dbname=Sys.getenv("POSTGRES_DATABASE"), + port=ifelse((p<-Sys.getenv("POSTGRES_PORT"))!="", p, 5432)) + + + if (dbExistsTable(con, "tmpirisdata")) { + print("Removing tmpirisdata\n") + dbRemoveTable(con, "tmpirisdata") + } + + dbWriteTable(con, "tmpirisdata", iris) + + ## run a simple query and show the query result + res <- dbGetQuery(con, "select * from tmpirisdata where \"Species\"=0") + print(res) + + ## cleanup + if (dbExistsTable(con, "tmpirisdata")) { + print("Removing tmpirisdata\n") + dbRemoveTable(con, "tmpirisdata") + } + + ## and disconnect + dbDisconnect(con) + cat("PASS: reached to the end of the test code without segmentation fault\n") + } > RPostgreSQL/tests/openSendQuery.R0000644000176000001440000000430512005446536016524 0ustar ripleyusers ## dbWriteTable test ## ## Assumes that ## a) PostgreSQL is running, and ## b) the current user can connect ## both of which are not viable for release but suitable while we test ## ## Dirk Eddelbuettel, 10 Sep 2009 ## only run this if this env.var is set correctly if (Sys.getenv("POSTGRES_USER") != "" & Sys.getenv("POSTGRES_HOST") != "" & Sys.getenv("POSTGRES_DATABASE") != "") { ## try to load our module and abort if this fails stopifnot(require(RPostgreSQL)) stopifnot(require(datasets)) ## load the PostgresSQL driver drv <- dbDriver("PostgreSQL") ## create two independent connections con <- dbConnect(drv, user=Sys.getenv("POSTGRES_USER"), password=Sys.getenv("POSTGRES_PASSWD"), host=Sys.getenv("POSTGRES_HOST"), dbname=Sys.getenv("POSTGRES_DATABASE"), port=ifelse((p<-Sys.getenv("POSTGRES_PORT"))!="", p, 5432)) if (dbExistsTable(con, "tmptest")) { cat("Removing tmptest\n") dbRemoveTable(con, "tmptest") } # create temporary table (as a copy of any existing one) # dbGetQuery(con, "BEGIN TRANSACTION") cat("create temp table tmptest with dbGetQuery\n") dbGetQuery(con, "CREATE TEMP TABLE tmptest (f1 int)") # query temp table rs<-dbGetQuery(con, "SELECT * from tmptest") print(rs) cat("create temp table tmptest with dbSendQuery\n") dbSendQuery(con, "CREATE TEMP TABLE tmptest2(f2 int)") # query temp table rs2<-dbGetQuery(con, "SELECT * from tmptest2") print(rs2) ## and disconnect dbDisconnect(con) con <- dbConnect(drv, user=Sys.getenv("POSTGRES_USER"), password=Sys.getenv("POSTGRES_PASSWD"), host=Sys.getenv("POSTGRES_HOST"), dbname=Sys.getenv("POSTGRES_DATABASE"), port=ifelse((p<-Sys.getenv("POSTGRES_PORT"))!="", p, 5432)) if (dbExistsTable(con, "tmptest")) { cat("FAIL tmptest persisted after disconnection\n") cat("Removing tmptest\n") dbRemoveTable(con, "tmptest") }else{ cat("PASS tmptest disappeared after disconnection\n") } dbDisconnect(con) } RPostgreSQL/tests/datetimeTests.R0000644000176000001440000000406412060117375016541 0ustar ripleyusers ## Test of date and datetime types, based on earlier version in inst/devTests ## ## Dirk Eddelbuettel, 21 Oct 2008 dbTypeTests <- function(con, dateclass="timestamp without time zone") { cat("\n\n**** Trying with ", dateclass, "\n") if (dbExistsTable(con, "tempostgrestable")) dbRemoveTable(con, "tempostgrestable") dbGetQuery(con, paste("create table tempostgrestable (tt ", dateclass, ", zz integer);", sep="")) dbGetQuery(con, "insert into tempostgrestable values('2008-07-01 14:15:16.123', 1);") now <- ISOdatetime(2000,1,2,3,4,5.678) dbGetQuery(con, paste("insert into tempostgrestable values('", format(now), "', 2);", sep="")) res <- dbReadTable(con, "tempostgrestable") print(res) res <- dbSendQuery(con, "select tt from tempostgrestable;") data <- fetch(res, n=-1) print(dbColumnInfo(res)) times <- data[,1] print(times) print(class(times[1])) print(diff(times)) dbRemoveTable(con, "tempostgrestable") invisible(NULL) } ## only run this if this env.var is set correctly if ((Sys.getenv("POSTGRES_USER") != "") & (Sys.getenv("POSTGRES_HOST") != "") & (Sys.getenv("POSTGRES_DATABASE") != "")) { ## try to load our module and abort if this fails stopifnot(require(RPostgreSQL)) ## Force a timezone to make the tests comparable at different locations Sys.setenv("PGDATESTYLE"="German") Sys.setenv("TZ"="UTC") ## load the PostgresSQL driver drv <- dbDriver("PostgreSQL") ## can't print result as it contains process id which changes print(summary(drv)) ## connect to the default db con <- dbConnect(drv, user=Sys.getenv("POSTGRES_USER"), password=Sys.getenv("POSTGRES_PASSWD"), host=Sys.getenv("POSTGRES_HOST"), dbname=Sys.getenv("POSTGRES_DATABASE"), port=ifelse((p<-Sys.getenv("POSTGRES_PORT"))!="", p, 5432)) dbTypeTests(con, "timestamp") dbTypeTests(con, "timestamp with time zone") dbTypeTests(con, "date") dbDisconnect(con) } RPostgreSQL/tests/escape.R0000644000176000001440000000251211455242162015156 0ustar ripleyusers ## connectWithNull test ## ## test for the 'Issue 2' on the Google Code issue log ## reported in April 2009, still open ? ## ## Assumes that ## a) PostgreSQL is running, and ## b) the current user can connect ## both of which are not viable for release but suitable while we test ## ## Dirk Eddelbuettel, 03 Oct 2009 ## only run this if this env.var is set correctly if (Sys.getenv("POSTGRES_USER") != "" & Sys.getenv("POSTGRES_HOST") != "" & Sys.getenv("POSTGRES_DATABASE") != "") { ## try to load our module and abort if this fails stopifnot(require(RPostgreSQL)) stopifnot(require(datasets)) ## load the PostgresSQL driver drv <- dbDriver("PostgreSQL") ## connect to the default db -- replacing any of these with NULL will lead to ## a stop() call and a return to the R prompt rather than a segfault con <- dbConnect(drv, user=Sys.getenv("POSTGRES_USER"), password=Sys.getenv("POSTGRES_PASSWD"), host=Sys.getenv("POSTGRES_HOST"), dbname=Sys.getenv("POSTGRES_DATABASE"), port=ifelse((p<-Sys.getenv("POSTGRES_PORT"))!="", p, 5432)) st <- (postgresqlEscapeStrings(con,"aaa")) print(st) st2 <- (postgresqlEscapeStrings(con,"aa'a")) print(st2) ## and disconnect dbDisconnect(con) } RPostgreSQL/tests/dbExistsqc.Rout.save0000644000176000001440000000713412124517166017524 0ustar ripleyusers R version 2.15.2 (2012-10-26) -- "Trick or Treat" Copyright (C) 2012 The R Foundation for Statistical Computing ISBN 3-900051-07-0 Platform: x86_64-unknown-linux-gnu (64-bit) R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. R is a collaborative project with many contributors. Type 'contributors()' for more information and 'citation()' on how to cite R or R packages in publications. Type 'demo()' for some demos, 'help()' for on-line help, or 'help.start()' for an HTML browser interface to help. Type 'q()' to quit R. > > ## dbExistsq test with schema name: reported as Issue 28 at > ## http://code.google.com/p/rpostgresql/issues/detail?id=28 > ## > ## Assumes that > ## a) PostgreSQL is running, and > ## b) the current user can connect > ## both of which are not viable for release but suitable while we test > ## > ## Dirk Eddelbuettel, 10 Sep 2009 > > ## only run this if this env.var is set correctly > if (Sys.getenv("POSTGRES_USER") != "" & Sys.getenv("POSTGRES_HOST") != "" & Sys.getenv("POSTGRES_DATABASE") != "") { + + ## try to load our module and abort if this fails + stopifnot(require(RPostgreSQL)) + stopifnot(require(datasets)) + + ## load the PostgresSQL driver + drv <- dbDriver("PostgreSQL") + + ## connect to the default db + con <- dbConnect(drv, + user=Sys.getenv("POSTGRES_USER"), + password=Sys.getenv("POSTGRES_PASSWD"), + host=Sys.getenv("POSTGRES_HOST"), + dbname=Sys.getenv("POSTGRES_DATABASE"), + port=ifelse((p<-Sys.getenv("POSTGRES_PORT"))!="", p, 5432)) + + if (dbExistsTable(con, "rock.data")) { + cat("Removing rock'data\n") + dbRemoveTable(con, "rock.data") + } + + + dbWriteTable(con, "rock.data", rock) + ## run a simple dbExists + cat("Does rock.data exist? \n") + res <- dbExistsTable(con, "rock.data") + if(res){ + cat("PASS: true\n") + }else{ + cat("FAIL: false\n") + } + + ## + cat("create schema testschema and change the search_path\n") + + dbGetQuery(con, 'CREATE SCHEMA testschema') + dbGetQuery(con, 'SET search_path TO testschema') + cat("Does rock.data exist? \n") + res <- dbExistsTable(con, "rock.data") + if(res){ + cat("FAIL: true despite search_path change\n") + }else{ + cat("PASS: false as the search_path changed\n") + } + + cat("Does testschema.\"rock.data\" exist? \n") + res <- dbExistsTable(con, c('testschema', "rock.data")) + if(res){ + cat("FAIL: true despite testschema specified\n") + }else{ + cat("PASS: false as the testschema specified\n") + } + + cat("Does public.\"rock.data\" exist? \n") + res <- dbExistsTable(con, c('public', "rock.data")) + if(res){ + cat("PASS: true despite search_path change\n") + }else{ + cat("FAIL: false as the search_path changed\n") + } + + + cat("write in current schema\n") + dbWriteTable(con, "rock.data", rock) + cat("Does rock.data exist? \n") + res <- dbExistsTable(con, "rock.data") + if(res){ + cat("PASS: true\n") + }else{ + cat("FAIL: false\n") + } + + ## cleanup + dbGetQuery(con, 'DROP TABLE "public"."rock.data"') + dbGetQuery(con, 'DROP TABLE "testschema"."rock.data"') + dbGetQuery(con, 'DROP schema "testschema"') + + ## and disconnect + dbDisconnect(con) + } > > proc.time() user system elapsed 0.142 0.016 0.142 RPostgreSQL/tests/dbtemptable.R0000644000176000001440000000265011535162225016204 0ustar ripleyusers ## dbWriteTable test ## ## Assumes that ## a) PostgreSQL is running, and ## b) the current user can connect ## both of which are not viable for release but suitable while we test ## ## Dirk Eddelbuettel, 10 Sep 2009 ## only run this if this env.var is set correctly if (Sys.getenv("POSTGRES_USER") != "" & Sys.getenv("POSTGRES_HOST") != "" & Sys.getenv("POSTGRES_DATABASE") != "") { ## try to load our module and abort if this fails stopifnot(require(RPostgreSQL)) stopifnot(require(datasets)) ## load the PostgresSQL driver drv <- dbDriver("PostgreSQL") ## connect to the default db con <- dbConnect(drv, user=Sys.getenv("POSTGRES_USER"), password=Sys.getenv("POSTGRES_PASSWD"), host=Sys.getenv("POSTGRES_HOST"), dbname=Sys.getenv("POSTGRES_DATABASE"), port=ifelse((p<-Sys.getenv("POSTGRES_PORT"))!="", p, 5432)) a <- dbGetQuery(con, "CREATE TABLE foo (name text)") b <- dbGetQuery(con, "INSERT INTO foo VALUES ('bar')") ## run a simple query and show the query result x <- dbSendQuery(con, "CREATE TEMPORARY TABLE xyz ON COMMIT DROP AS select * from foo limit 1; select * from xyz;") res <- fetch(x, n=-1) print(res) a <- dbGetQuery(con, "DROP TABLE foo") ## cleanup ## and disconnect dbDisconnect(con) cat("PASS -- ended without segmentation fault\n") } RPostgreSQL/tests/unknowntype.Rout.save0000644000176000001440000000503012124517166020005 0ustar ripleyusers R version 2.15.2 (2012-10-26) -- "Trick or Treat" Copyright (C) 2012 The R Foundation for Statistical Computing ISBN 3-900051-07-0 Platform: x86_64-unknown-linux-gnu (64-bit) R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. R is a collaborative project with many contributors. Type 'contributors()' for more information and 'citation()' on how to cite R or R packages in publications. Type 'demo()' for some demos, 'help()' for on-line help, or 'help.start()' for an HTML browser interface to help. Type 'q()' to quit R. > > ## selectWhereZero test > ## > ## test for the 'Issue 1' on the Google Code issue log > ## this was reported in June and fixed by Joe Conway (svr committ r100) > ## > ## Assumes that > ## a) PostgreSQL is running, and > ## b) the current user can connect > ## both of which are not viable for release but suitable while we test > ## > ## Dirk Eddelbuettel, 03 Oct 2009 > > ## only run this if this env.var is set correctly > if (Sys.getenv("POSTGRES_USER") != "" & Sys.getenv("POSTGRES_HOST") != "" & Sys.getenv("POSTGRES_DATABASE") != "") { + + ## try to load our module and abort if this fails + stopifnot(require(RPostgreSQL)) + + ## load the PostgresSQL driver + drv <- dbDriver("PostgreSQL") + + ## connect to the default db + con <- dbConnect(drv, + user=Sys.getenv("POSTGRES_USER"), + password=Sys.getenv("POSTGRES_PASSWD"), + host=Sys.getenv("POSTGRES_HOST"), + dbname=Sys.getenv("POSTGRES_DATABASE"), + port=ifelse((p<-Sys.getenv("POSTGRES_PORT"))!="", p, 5432)) + + + if (dbExistsTable(con, "tmpirisdata")) { + print("Removing tmpirisdata\n") + dbRemoveTable(con, "tmpirisdata") + } + + + ## run a simple query and show the query result + res <- dbGetQuery(con, "create table tmpirisdata (ra REAL[])") + res <- dbSendQuery(con, "select ra from tmpirisdata") + print(res) + type <- dbColumnInfo(res) + print(type) + data <- fetch(res, -1) + print(data) + + ## cleanup + if (dbExistsTable(con, "tmpirisdata")) { + print("Removing tmpirisdata\n") + dbRemoveTable(con, "tmpirisdata") + } + + ## and disconnect + dbDisconnect(con) + cat("PASS: reached to the end of the test code without segmentation fault\n") + } > > proc.time() user system elapsed 0.126 0.024 0.134 RPostgreSQL/tests/connectWithNull.Rout.save0000644000176000001440000000361411455242162020527 0ustar ripleyusers R version 2.11.1 (2010-05-31) Copyright (C) 2010 The R Foundation for Statistical Computing ISBN 3-900051-07-0 R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. R is a collaborative project with many contributors. Type 'contributors()' for more information and 'citation()' on how to cite R or R packages in publications. Type 'demo()' for some demos, 'help()' for on-line help, or 'help.start()' for an HTML browser interface to help. Type 'q()' to quit R. > > ## connectWithNull test > ## > ## test for the 'Issue 2' on the Google Code issue log > ## reported in April 2009, still open ? > ## > ## Assumes that > ## a) PostgreSQL is running, and > ## b) the current user can connect > ## both of which are not viable for release but suitable while we test > ## > ## Dirk Eddelbuettel, 03 Oct 2009 > > ## only run this if this env.var is set correctly > if (Sys.getenv("POSTGRES_USER") != "" & Sys.getenv("POSTGRES_HOST") != "" & Sys.getenv("POSTGRES_DATABASE") != "") { + + ## try to load our module and abort if this fails + stopifnot(require(RPostgreSQL)) + stopifnot(require(datasets)) + + ## load the PostgresSQL driver + drv <- dbDriver("PostgreSQL") + + ## connect to the default db -- replacing any of these with NULL will lead to + ## a stop() call and a return to the R prompt rather than a segfault + con <- dbConnect(drv, + user=Sys.getenv("POSTGRES_USER"), + password=Sys.getenv("POSTGRES_PASSWD"), + host=Sys.getenv("POSTGRES_HOST"), + dbname=Sys.getenv("POSTGRES_DATABASE"), + port=ifelse((p<-Sys.getenv("POSTGRES_PORT"))!="", p, 5432)) + + ## do we get here? + print(con) + + ## and disconnect + dbDisconnect(con) + } > RPostgreSQL/config.sub0000644000176000001440000010504211663676122014423 0ustar ripleyusers#! /bin/sh # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, # 2011 Free Software Foundation, Inc. timestamp='2011-10-19' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software # can handle that machine. It does not imply ALL GNU software can. # # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA # 02110-1301, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Please send patches to . Submit a context # diff and a properly formatted GNU ChangeLog entry. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ knetbsd*-gnu* | netbsd*-gnu* | \ kopensolaris*-gnu* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis | -knuth | -cray | -microblaze) os= basic_machine=$1 ;; -bluegene*) os=-cnk ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco6) os=-sco5v6 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5v6*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ | be32 | be64 \ | bfin \ | c4x | clipper \ | d10v | d30v | dlx | dsp16xx \ | epiphany \ | fido | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | hexagon \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ | le32 | le64 \ | lm32 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ | maxq | mb | microblaze | mcore | mep | metag \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64octeon | mips64octeonel \ | mips64orion | mips64orionel \ | mips64r5900 | mips64r5900el \ | mips64vr | mips64vrel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | moxie \ | mt \ | msp430 \ | nds32 | nds32le | nds32be \ | nios | nios2 \ | ns16k | ns32k \ | open8 \ | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle \ | pyramid \ | rx \ | score \ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ | spu \ | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ | ubicom32 \ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ | we32k \ | x86 | xc16x | xstormy16 | xtensa \ | z8k | z80) basic_machine=$basic_machine-unknown ;; c54x) basic_machine=tic54x-unknown ;; c55x) basic_machine=tic55x-unknown ;; c6x) basic_machine=tic6x-unknown ;; m6811 | m68hc11 | m6812 | m68hc12 | picochip) # Motorola 68HC11/12. basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; ms1) basic_machine=mt-unknown ;; strongarm | thumb | xscale) basic_machine=arm-unknown ;; xscaleeb) basic_machine=armeb-unknown ;; xscaleel) basic_machine=armel-unknown ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ | be32-* | be64-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* \ | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | hexagon-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ | le32-* | le64-* \ | lm32-* \ | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64octeon-* | mips64octeonel-* \ | mips64orion-* | mips64orionel-* \ | mips64r5900-* | mips64r5900el-* \ | mips64vr-* | mips64vrel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mips64vr5900-* | mips64vr5900el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | mt-* \ | msp430-* \ | nds32-* | nds32le-* | nds32be-* \ | nios-* | nios2-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | open8-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ | pyramid-* \ | romp-* | rs6000-* | rx-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ | tahoe-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tile*-* \ | tron-* \ | ubicom32-* \ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ | vax-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* \ | xstormy16-* | xtensa*-* \ | ymp-* \ | z8k-* | z80-*) ;; # Recognize the basic CPU types without company name, with glob match. xtensa*) basic_machine=$basic_machine-unknown ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; abacus) basic_machine=abacus-unknown ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amd64) basic_machine=x86_64-pc ;; amd64-*) basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aros) basic_machine=i386-pc os=-aros ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; blackfin) basic_machine=bfin-unknown os=-linux ;; blackfin-*) basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; bluegene*) basic_machine=powerpc-ibm os=-cnk ;; c54x-*) basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c55x-*) basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c6x-*) basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c90) basic_machine=c90-cray os=-unicos ;; cegcc) basic_machine=arm-unknown os=-cegcc ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; craynv) basic_machine=craynv-cray os=-unicosmp ;; cr16 | cr16-*) basic_machine=cr16-unknown os=-elf ;; crds | unos) basic_machine=m68k-crds ;; crisv32 | crisv32-* | etraxfs*) basic_machine=crisv32-axis ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; crx) basic_machine=crx-unknown os=-elf ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dicos) basic_machine=i686-pc os=-dicos ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; # I'm not sure what "Sysv32" means. Should this be sysv3.2? i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m68knommu) basic_machine=m68k-unknown os=-linux ;; m68knommu-*) basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; microblaze) basic_machine=microblaze-xilinx ;; mingw32) basic_machine=i386-pc os=-mingw32 ;; mingw32ce) basic_machine=arm-unknown os=-mingw32ce ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; msdos) basic_machine=i386-pc os=-msdos ;; ms1-*) basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` ;; mvs) basic_machine=i370-ibm os=-mvs ;; nacl) basic_machine=le32-unknown os=-nacl ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; neo-tandem) basic_machine=neo-tandem ;; nse-tandem) basic_machine=nse-tandem ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; openrisc | openrisc-*) basic_machine=or32-unknown ;; os400) basic_machine=powerpc-ibm os=-os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; parisc) basic_machine=hppa-unknown os=-linux ;; parisc-*) basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pc98) basic_machine=i386-pc ;; pc98-*) basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc | ppcbe) basic_machine=powerpc-unknown ;; ppc-* | ppcbe-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rdos) basic_machine=i386-pc os=-rdos ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sde) basic_machine=mipsisa32-sde os=-elf ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sh5el) basic_machine=sh5le-unknown ;; sh64) basic_machine=sh64-unknown ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; strongarm-* | thumb-*) basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tile*) basic_machine=$basic_machine-unknown os=-linux-gnu ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; tpf) basic_machine=s390x-ibm os=-tpf ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xbox) basic_machine=i686-pc os=-mingw32 ;; xps | xps100) basic_machine=xps100-honeywell ;; xscale-* | xscalee[bl]-*) basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; z80-*-coff) basic_machine=z80-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; mmix) basic_machine=mmix-knuth ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -auroraux) os=-auroraux ;; -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ | -sym* | -kopensolaris* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* | -aros* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ | -openbsd* | -solidbsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* | -cegcc* \ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -linux-gnu* | -linux-android* \ | -linux-newlib* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux-dietlibc) os=-linux-dietlibc ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -os400*) os=-os400 ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -syllable*) os=-syllable ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -tpf*) os=-tpf ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -kaos*) os=-kaos ;; -zvmoe) os=-zvmoe ;; -dicos*) os=-dicos ;; -nacl*) ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in score-*) os=-elf ;; spu-*) os=-elf ;; *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; tic54x-*) os=-coff ;; tic55x-*) os=-coff ;; tic6x-*) os=-coff ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 # This also exists in the configure program, but was not the # default. # os=-sunos4 ;; m68*-cisco) os=-aout ;; mep-*) os=-elf ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-haiku) os=-haiku ;; *-ibm) os=-aix ;; *-knuth) os=-mmixware ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -cnk*|-aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -os400*) vendor=ibm ;; -ptx*) vendor=sequent ;; -tpf*) vendor=ibm ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: RPostgreSQL/DESCRIPTION0000644000176000001440000000301712124527403014136 0ustar ripleyusersPackage: RPostgreSQL Version: 0.4 Date: $Date: 2013-03-27 15:32:53 +0900 (Wed, 27 Mar 2013) $ Title: R interface to the PostgreSQL database system Author: Joe Conway, Dirk Eddelbuettel, Tomoaki Nishiyama, Sameer Kumar Prayaga (during 2008), Neil Tiffin Maintainer: Tomoaki Nishiyama Description: Database interface and PostgreSQL driver for R This package provides a Database Interface (DBI) compliant driver for R to access PostgreSQL database systems. . In order to build and install this package from source, PostgreSQL itself must be present your system to provide PostgreSQL functionality via its libraries and header files. These files are provided as postgresql-devel package under some Linux distributions. . On Microsoft Windows system the attached libpq library source will be used. . A wiki and issue tracking system for the package are available at Google Code at https://code.google.com/p/rpostgresql/ . LazyLoad: true Depends: R (>= 2.9.0), methods, DBI (>= 0.1-4) License: GPL-2 | file LICENSE Copyright: Authors listed above, PostgreSQL Global Development Group, and The Regents of the University of California Collate: S4R.R zzz.R PostgreSQLSupport.R dbObjectId.R PostgreSQL.R URL: https://code.google.com/p/rpostgresql/, http://www.stat.bell-labs.com/RS-DBI, http://www.postgresql.org Packaged: 2013-03-27 07:24:02 UTC; tomoaki NeedsCompilation: yes Repository: CRAN Date/Publication: 2013-03-27 09:34:11 RPostgreSQL/install-sh0000644000176000001440000000000011663676122014430 0ustar ripleyusersRPostgreSQL/configure.win0000644000176000001440000000000011660061757015126 0ustar ripleyusersRPostgreSQL/LICENSE0000644000176000001440000000330512033227064013434 0ustar ripleyusersThis package as a whole is distributed under GPL-2 (GNU GENERAL PUBLIC LICENSE version 2). See the file COPYING in the top level of the R directory tree for further details. The files under src/libpq/ and libpq.dll are distributed under the PostgreSQL License (see below). That is, if you take only that part out of the package you may redistribute only under the restriction of PostgreSQL License. Most of this package are distributed under GPL-2 and if you redistribute any part of this, you must follow GPL-2. PostgreSQL License: PostgreSQL Database Management System (formerly known as Postgres, then as Postgres95) Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group Portions Copyright (c) 1994, The Regents of the University of California Permission to use, copy, modify, and distribute this software and its documentation for any purpose, without fee, and without a written agreement is hereby granted, provided that the above copyright notice and this paragraph and the following two paragraphs appear in all copies. IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/ char **fieldName; /* null terminated array of replacement field * names */ } PQprintOpt; /* ---------------- * Structure for the conninfo parameter definitions returned by PQconndefaults * or PQconninfoParse. * * All fields except "val" point at static strings which must not be altered. * "val" is either NULL or a malloc'd current-value string. PQconninfoFree() * will release both the val strings and the PQconninfoOption array itself. * ---------------- */ typedef struct _PQconninfoOption { char *keyword; /* The keyword of the option */ char *envvar; /* Fallback environment variable name */ char *compiled; /* Fallback compiled in default value */ char *val; /* Option's current value, or NULL */ char *label; /* Label for field in connect dialog */ char *dispchar; /* Indicates how to display this field in a * connect dialog. Values are: "" Display * entered value as is "*" Password field - * hide value "D" Debug option - don't show * by default */ int dispsize; /* Field size in characters for dialog */ } PQconninfoOption; /* ---------------- * PQArgBlock -- structure for PQfn() arguments * ---------------- */ typedef struct { int len; int isint; union { int *ptr; /* can't use void (dec compiler barfs) */ int integer; } u; } PQArgBlock; /* ---------------- * PGresAttDesc -- Data about a single attribute (column) of a query result * ---------------- */ typedef struct pgresAttDesc { char *name; /* column name */ Oid tableid; /* source table, if known */ int columnid; /* source column, if known */ int format; /* format code for value (text/binary) */ Oid typid; /* type id */ int typlen; /* type size */ int atttypmod; /* type-specific modifier info */ } PGresAttDesc; /* ---------------- * Exported functions of libpq * ---------------- */ /* === in fe-connect.c === */ /* make a new client connection to the backend */ /* Asynchronous (non-blocking) */ extern PGconn *PQconnectStart(const char *conninfo); extern PGconn *PQconnectStartParams(const char **keywords, const char **values, int expand_dbname); extern PostgresPollingStatusType PQconnectPoll(PGconn *conn); /* Synchronous (blocking) */ extern PGconn *PQconnectdb(const char *conninfo); extern PGconn *PQconnectdbParams(const char **keywords, const char **values, int expand_dbname); extern PGconn *PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions, const char *pgtty, const char *dbName, const char *login, const char *pwd); #define PQsetdb(M_PGHOST,M_PGPORT,M_PGOPT,M_PGTTY,M_DBNAME) \ PQsetdbLogin(M_PGHOST, M_PGPORT, M_PGOPT, M_PGTTY, M_DBNAME, NULL, NULL) /* close the current connection and free the PGconn data structure */ extern void PQfinish(PGconn *conn); /* get info about connection options known to PQconnectdb */ extern PQconninfoOption *PQconndefaults(void); /* parse connection options in same way as PQconnectdb */ extern PQconninfoOption *PQconninfoParse(const char *conninfo, char **errmsg); /* free the data structure returned by PQconndefaults() or PQconninfoParse() */ extern void PQconninfoFree(PQconninfoOption *connOptions); /* * close the current connection and restablish a new one with the same * parameters */ /* Asynchronous (non-blocking) */ extern int PQresetStart(PGconn *conn); extern PostgresPollingStatusType PQresetPoll(PGconn *conn); /* Synchronous (blocking) */ extern void PQreset(PGconn *conn); /* request a cancel structure */ extern PGcancel *PQgetCancel(PGconn *conn); /* free a cancel structure */ extern void PQfreeCancel(PGcancel *cancel); /* issue a cancel request */ extern int PQcancel(PGcancel *cancel, char *errbuf, int errbufsize); /* backwards compatible version of PQcancel; not thread-safe */ extern int PQrequestCancel(PGconn *conn); /* Accessor functions for PGconn objects */ extern char *PQdb(const PGconn *conn); extern char *PQuser(const PGconn *conn); extern char *PQpass(const PGconn *conn); extern char *PQhost(const PGconn *conn); extern char *PQport(const PGconn *conn); extern char *PQtty(const PGconn *conn); extern char *PQoptions(const PGconn *conn); extern ConnStatusType PQstatus(const PGconn *conn); extern PGTransactionStatusType PQtransactionStatus(const PGconn *conn); extern const char *PQparameterStatus(const PGconn *conn, const char *paramName); extern int PQprotocolVersion(const PGconn *conn); extern int PQserverVersion(const PGconn *conn); extern char *PQerrorMessage(const PGconn *conn); extern int PQsocket(const PGconn *conn); extern int PQbackendPID(const PGconn *conn); extern int PQconnectionNeedsPassword(const PGconn *conn); extern int PQconnectionUsedPassword(const PGconn *conn); extern int PQclientEncoding(const PGconn *conn); extern int PQsetClientEncoding(PGconn *conn, const char *encoding); /* Get the OpenSSL structure associated with a connection. Returns NULL for * unencrypted connections or if any other TLS library is in use. */ extern void *PQgetssl(PGconn *conn); /* Tell libpq whether it needs to initialize OpenSSL */ extern void PQinitSSL(int do_init); /* More detailed way to tell libpq whether it needs to initialize OpenSSL */ extern void PQinitOpenSSL(int do_ssl, int do_crypto); /* Set verbosity for PQerrorMessage and PQresultErrorMessage */ extern PGVerbosity PQsetErrorVerbosity(PGconn *conn, PGVerbosity verbosity); /* Enable/disable tracing */ extern void PQtrace(PGconn *conn, FILE *debug_port); extern void PQuntrace(PGconn *conn); /* Override default notice handling routines */ extern PQnoticeReceiver PQsetNoticeReceiver(PGconn *conn, PQnoticeReceiver proc, void *arg); extern PQnoticeProcessor PQsetNoticeProcessor(PGconn *conn, PQnoticeProcessor proc, void *arg); /* * Used to set callback that prevents concurrent access to * non-thread safe functions that libpq needs. * The default implementation uses a libpq internal mutex. * Only required for multithreaded apps that use kerberos * both within their app and for postgresql connections. */ typedef void (*pgthreadlock_t) (int acquire); extern pgthreadlock_t PQregisterThreadLock(pgthreadlock_t newhandler); /* === in fe-exec.c === */ /* Simple synchronous query */ extern PGresult *PQexec(PGconn *conn, const char *query); extern PGresult *PQexecParams(PGconn *conn, const char *command, int nParams, const Oid *paramTypes, const char *const * paramValues, const int *paramLengths, const int *paramFormats, int resultFormat); extern PGresult *PQprepare(PGconn *conn, const char *stmtName, const char *query, int nParams, const Oid *paramTypes); extern PGresult *PQexecPrepared(PGconn *conn, const char *stmtName, int nParams, const char *const * paramValues, const int *paramLengths, const int *paramFormats, int resultFormat); /* Interface for multiple-result or asynchronous queries */ extern int PQsendQuery(PGconn *conn, const char *query); extern int PQsendQueryParams(PGconn *conn, const char *command, int nParams, const Oid *paramTypes, const char *const * paramValues, const int *paramLengths, const int *paramFormats, int resultFormat); extern int PQsendPrepare(PGconn *conn, const char *stmtName, const char *query, int nParams, const Oid *paramTypes); extern int PQsendQueryPrepared(PGconn *conn, const char *stmtName, int nParams, const char *const * paramValues, const int *paramLengths, const int *paramFormats, int resultFormat); extern PGresult *PQgetResult(PGconn *conn); /* Routines for managing an asynchronous query */ extern int PQisBusy(PGconn *conn); extern int PQconsumeInput(PGconn *conn); /* LISTEN/NOTIFY support */ extern PGnotify *PQnotifies(PGconn *conn); /* Routines for copy in/out */ extern int PQputCopyData(PGconn *conn, const char *buffer, int nbytes); extern int PQputCopyEnd(PGconn *conn, const char *errormsg); extern int PQgetCopyData(PGconn *conn, char **buffer, int async); /* Deprecated routines for copy in/out */ extern int PQgetline(PGconn *conn, char *string, int length); extern int PQputline(PGconn *conn, const char *string); extern int PQgetlineAsync(PGconn *conn, char *buffer, int bufsize); extern int PQputnbytes(PGconn *conn, const char *buffer, int nbytes); extern int PQendcopy(PGconn *conn); /* Set blocking/nonblocking connection to the backend */ extern int PQsetnonblocking(PGconn *conn, int arg); extern int PQisnonblocking(const PGconn *conn); extern int PQisthreadsafe(void); extern PGPing PQping(const char *conninfo); extern PGPing PQpingParams(const char **keywords, const char **values, int expand_dbname); /* Force the write buffer to be written (or at least try) */ extern int PQflush(PGconn *conn); /* * "Fast path" interface --- not really recommended for application * use */ extern PGresult *PQfn(PGconn *conn, int fnid, int *result_buf, int *result_len, int result_is_int, const PQArgBlock *args, int nargs); /* Accessor functions for PGresult objects */ extern ExecStatusType PQresultStatus(const PGresult *res); extern char *PQresStatus(ExecStatusType status); extern char *PQresultErrorMessage(const PGresult *res); extern char *PQresultErrorField(const PGresult *res, int fieldcode); extern int PQntuples(const PGresult *res); extern int PQnfields(const PGresult *res); extern int PQbinaryTuples(const PGresult *res); extern char *PQfname(const PGresult *res, int field_num); extern int PQfnumber(const PGresult *res, const char *field_name); extern Oid PQftable(const PGresult *res, int field_num); extern int PQftablecol(const PGresult *res, int field_num); extern int PQfformat(const PGresult *res, int field_num); extern Oid PQftype(const PGresult *res, int field_num); extern int PQfsize(const PGresult *res, int field_num); extern int PQfmod(const PGresult *res, int field_num); extern char *PQcmdStatus(PGresult *res); extern char *PQoidStatus(const PGresult *res); /* old and ugly */ extern Oid PQoidValue(const PGresult *res); /* new and improved */ extern char *PQcmdTuples(PGresult *res); extern char *PQgetvalue(const PGresult *res, int tup_num, int field_num); extern int PQgetlength(const PGresult *res, int tup_num, int field_num); extern int PQgetisnull(const PGresult *res, int tup_num, int field_num); extern int PQnparams(const PGresult *res); extern Oid PQparamtype(const PGresult *res, int param_num); /* Describe prepared statements and portals */ extern PGresult *PQdescribePrepared(PGconn *conn, const char *stmt); extern PGresult *PQdescribePortal(PGconn *conn, const char *portal); extern int PQsendDescribePrepared(PGconn *conn, const char *stmt); extern int PQsendDescribePortal(PGconn *conn, const char *portal); /* Delete a PGresult */ extern void PQclear(PGresult *res); /* For freeing other alloc'd results, such as PGnotify structs */ extern void PQfreemem(void *ptr); /* Exists for backward compatibility. bjm 2003-03-24 */ #define PQfreeNotify(ptr) PQfreemem(ptr) /* Error when no password was given. */ /* Note: depending on this is deprecated; use PQconnectionNeedsPassword(). */ #define PQnoPasswordSupplied "fe_sendauth: no password supplied\n" /* Create and manipulate PGresults */ extern PGresult *PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status); extern PGresult *PQcopyResult(const PGresult *src, int flags); extern int PQsetResultAttrs(PGresult *res, int numAttributes, PGresAttDesc *attDescs); extern void *PQresultAlloc(PGresult *res, size_t nBytes); extern int PQsetvalue(PGresult *res, int tup_num, int field_num, char *value, int len); /* Quoting strings before inclusion in queries. */ extern size_t PQescapeStringConn(PGconn *conn, char *to, const char *from, size_t length, int *error); extern char *PQescapeLiteral(PGconn *conn, const char *str, size_t len); extern char *PQescapeIdentifier(PGconn *conn, const char *str, size_t len); extern unsigned char *PQescapeByteaConn(PGconn *conn, const unsigned char *from, size_t from_length, size_t *to_length); extern unsigned char *PQunescapeBytea(const unsigned char *strtext, size_t *retbuflen); /* These forms are deprecated! */ extern size_t PQescapeString(char *to, const char *from, size_t length); extern unsigned char *PQescapeBytea(const unsigned char *from, size_t from_length, size_t *to_length); /* === in fe-print.c === */ extern void PQprint(FILE *fout, /* output stream */ const PGresult *res, const PQprintOpt *ps); /* option structure */ /* * really old printing routines */ extern void PQdisplayTuples(const PGresult *res, FILE *fp, /* where to send the output */ int fillAlign, /* pad the fields with spaces */ const char *fieldSep, /* field separator */ int printHeader, /* display headers? */ int quiet); extern void PQprintTuples(const PGresult *res, FILE *fout, /* output stream */ int printAttName, /* print attribute names */ int terseOutput, /* delimiter bars */ int width); /* width of column, if 0, use variable width */ /* === in fe-lobj.c === */ /* Large-object access routines */ extern int lo_open(PGconn *conn, Oid lobjId, int mode); extern int lo_close(PGconn *conn, int fd); extern int lo_read(PGconn *conn, int fd, char *buf, size_t len); extern int lo_write(PGconn *conn, int fd, const char *buf, size_t len); extern int lo_lseek(PGconn *conn, int fd, int offset, int whence); extern Oid lo_creat(PGconn *conn, int mode); extern Oid lo_create(PGconn *conn, Oid lobjId); extern int lo_tell(PGconn *conn, int fd); extern int lo_truncate(PGconn *conn, int fd, size_t len); extern int lo_unlink(PGconn *conn, Oid lobjId); extern Oid lo_import(PGconn *conn, const char *filename); extern Oid lo_import_with_oid(PGconn *conn, const char *filename, Oid lobjId); extern int lo_export(PGconn *conn, Oid lobjId, const char *filename); /* === in fe-misc.c === */ /* Get the version of the libpq library in use */ extern int PQlibVersion(void); /* Determine length of multibyte encoded char at *s */ extern int PQmblen(const char *s, int encoding); /* Determine display length of multibyte encoded char at *s */ extern int PQdsplen(const char *s, int encoding); /* Get encoding id from environment variable PGCLIENTENCODING */ extern int PQenv2encoding(void); /* === in fe-auth.c === */ extern char *PQencryptPassword(const char *passwd, const char *user); /* === in encnames.c === */ extern int pg_char_to_encoding(const char *name); extern const char *pg_encoding_to_char(int encoding); extern int pg_valid_server_encoding_id(int encoding); #ifdef __cplusplus } #endif #endif /* LIBPQ_FE_H */ RPostgreSQL/src/libpq/pqexpbuffer.c0000644000176000001440000002135112124517222017020 0ustar ripleyusers/*------------------------------------------------------------------------- * * pqexpbuffer.c * * PQExpBuffer provides an indefinitely-extensible string data type. * It can be used to buffer either ordinary C strings (null-terminated text) * or arbitrary binary data. All storage is allocated with malloc(). * * This module is essentially the same as the backend's StringInfo data type, * but it is intended for use in frontend libpq and client applications. * Thus, it does not rely on palloc() nor elog(). * * It does rely on vsnprintf(); if configure finds that libc doesn't provide * a usable vsnprintf(), then a copy of our own implementation of it will * be linked into libpq. * * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/interfaces/libpq/pqexpbuffer.c * *------------------------------------------------------------------------- */ #include "postgres_fe.h" #include #include "pqexpbuffer.h" #ifdef WIN32 #include "win32.h" #endif /* All "broken" PQExpBuffers point to this string. */ static const char oom_buffer[1] = ""; /* * markPQExpBufferBroken * * Put a PQExpBuffer in "broken" state if it isn't already. */ static void markPQExpBufferBroken(PQExpBuffer str) { if (str->data != oom_buffer) free(str->data); /* * Casting away const here is a bit ugly, but it seems preferable to not * marking oom_buffer const. We want to do that to encourage the compiler * to put oom_buffer in read-only storage, so that anyone who tries to * scribble on a broken PQExpBuffer will get a failure. */ str->data = (char *) oom_buffer; str->len = 0; str->maxlen = 0; } /* * createPQExpBuffer * * Create an empty 'PQExpBufferData' & return a pointer to it. */ PQExpBuffer createPQExpBuffer(void) { PQExpBuffer res; res = (PQExpBuffer) malloc(sizeof(PQExpBufferData)); if (res != NULL) initPQExpBuffer(res); return res; } /* * initPQExpBuffer * * Initialize a PQExpBufferData struct (with previously undefined contents) * to describe an empty string. */ void initPQExpBuffer(PQExpBuffer str) { str->data = (char *) malloc(INITIAL_EXPBUFFER_SIZE); if (str->data == NULL) { str->data = (char *) oom_buffer; /* see comment above */ str->maxlen = 0; str->len = 0; } else { str->maxlen = INITIAL_EXPBUFFER_SIZE; str->len = 0; str->data[0] = '\0'; } } /* * destroyPQExpBuffer(str); * * free()s both the data buffer and the PQExpBufferData. * This is the inverse of createPQExpBuffer(). */ void destroyPQExpBuffer(PQExpBuffer str) { if (str) { termPQExpBuffer(str); free(str); } } /* * termPQExpBuffer(str) * free()s the data buffer but not the PQExpBufferData itself. * This is the inverse of initPQExpBuffer(). */ void termPQExpBuffer(PQExpBuffer str) { if (str->data != oom_buffer) free(str->data); /* just for luck, make the buffer validly empty. */ str->data = (char *) oom_buffer; /* see comment above */ str->maxlen = 0; str->len = 0; } /* * resetPQExpBuffer * Reset a PQExpBuffer to empty * * Note: if possible, a "broken" PQExpBuffer is returned to normal. */ void resetPQExpBuffer(PQExpBuffer str) { if (str) { if (str->data != oom_buffer) { str->len = 0; str->data[0] = '\0'; } else { /* try to reinitialize to valid state */ initPQExpBuffer(str); } } } /* * enlargePQExpBuffer * Make sure there is enough space for 'needed' more bytes in the buffer * ('needed' does not include the terminating null). * * Returns 1 if OK, 0 if failed to enlarge buffer. (In the latter case * the buffer is left in "broken" state.) */ int enlargePQExpBuffer(PQExpBuffer str, size_t needed) { size_t newlen; char *newdata; if (PQExpBufferBroken(str)) return 0; /* already failed */ /* * Guard against ridiculous "needed" values, which can occur if we're fed * bogus data. Without this, we can get an overflow or infinite loop in * the following. */ if (needed >= ((size_t) INT_MAX - str->len)) { markPQExpBufferBroken(str); return 0; } needed += str->len + 1; /* total space required now */ /* Because of the above test, we now have needed <= INT_MAX */ if (needed <= str->maxlen) return 1; /* got enough space already */ /* * We don't want to allocate just a little more space with each append; * for efficiency, double the buffer size each time it overflows. * Actually, we might need to more than double it if 'needed' is big... */ newlen = (str->maxlen > 0) ? (2 * str->maxlen) : 64; while (needed > newlen) newlen = 2 * newlen; /* * Clamp to INT_MAX in case we went past it. Note we are assuming here * that INT_MAX <= UINT_MAX/2, else the above loop could overflow. We * will still have newlen >= needed. */ if (newlen > (size_t) INT_MAX) newlen = (size_t) INT_MAX; newdata = (char *) realloc(str->data, newlen); if (newdata != NULL) { str->data = newdata; str->maxlen = newlen; return 1; } markPQExpBufferBroken(str); return 0; } /* * printfPQExpBuffer * Format text data under the control of fmt (an sprintf-like format string) * and insert it into str. More space is allocated to str if necessary. * This is a convenience routine that does the same thing as * resetPQExpBuffer() followed by appendPQExpBuffer(). */ void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...) { va_list args; size_t avail; int nprinted; resetPQExpBuffer(str); if (PQExpBufferBroken(str)) return; /* already failed */ for (;;) { /* * Try to format the given string into the available space; but if * there's hardly any space, don't bother trying, just fall through to * enlarge the buffer first. */ if (str->maxlen > str->len + 16) { avail = str->maxlen - str->len - 1; va_start(args, fmt); nprinted = vsnprintf(str->data + str->len, avail, fmt, args); va_end(args); /* * Note: some versions of vsnprintf return the number of chars * actually stored, but at least one returns -1 on failure. Be * conservative about believing whether the print worked. */ if (nprinted >= 0 && nprinted < (int) avail - 1) { /* Success. Note nprinted does not include trailing null. */ str->len += nprinted; break; } } /* Double the buffer size and try again. */ if (!enlargePQExpBuffer(str, str->maxlen)) return; /* oops, out of memory */ } } /* * appendPQExpBuffer * * Format text data under the control of fmt (an sprintf-like format string) * and append it to whatever is already in str. More space is allocated * to str if necessary. This is sort of like a combination of sprintf and * strcat. */ void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...) { va_list args; size_t avail; int nprinted; if (PQExpBufferBroken(str)) return; /* already failed */ for (;;) { /* * Try to format the given string into the available space; but if * there's hardly any space, don't bother trying, just fall through to * enlarge the buffer first. */ if (str->maxlen > str->len + 16) { avail = str->maxlen - str->len - 1; va_start(args, fmt); nprinted = vsnprintf(str->data + str->len, avail, fmt, args); va_end(args); /* * Note: some versions of vsnprintf return the number of chars * actually stored, but at least one returns -1 on failure. Be * conservative about believing whether the print worked. */ if (nprinted >= 0 && nprinted < (int) avail - 1) { /* Success. Note nprinted does not include trailing null. */ str->len += nprinted; break; } } /* Double the buffer size and try again. */ if (!enlargePQExpBuffer(str, str->maxlen)) return; /* oops, out of memory */ } } /* * appendPQExpBufferStr * Append the given string to a PQExpBuffer, allocating more space * if necessary. */ void appendPQExpBufferStr(PQExpBuffer str, const char *data) { appendBinaryPQExpBuffer(str, data, strlen(data)); } /* * appendPQExpBufferChar * Append a single byte to str. * Like appendPQExpBuffer(str, "%c", ch) but much faster. */ void appendPQExpBufferChar(PQExpBuffer str, char ch) { /* Make more room if needed */ if (!enlargePQExpBuffer(str, 1)) return; /* OK, append the character */ str->data[str->len] = ch; str->len++; str->data[str->len] = '\0'; } /* * appendBinaryPQExpBuffer * * Append arbitrary binary data to a PQExpBuffer, allocating more space * if necessary. */ void appendBinaryPQExpBuffer(PQExpBuffer str, const char *data, size_t datalen) { /* Make more room if needed */ if (!enlargePQExpBuffer(str, datalen)) return; /* OK, append the data */ memcpy(str->data + str->len, data, datalen); str->len += datalen; /* * Keep a trailing null in place, even though it's probably useless for * binary data... */ str->data[str->len] = '\0'; } RPostgreSQL/src/libpq/pthread-win32.c0000644000176000001440000000176712124517222017071 0ustar ripleyusers/*------------------------------------------------------------------------- * * pthread-win32.c * partial pthread implementation for win32 * * Copyright (c) 2004-2011, PostgreSQL Global Development Group * IDENTIFICATION * src/interfaces/libpq/pthread-win32.c * *------------------------------------------------------------------------- */ #include "postgres_fe.h" #include #include "pthread-win32.h" DWORD pthread_self(void) { return GetCurrentThreadId(); } void pthread_setspecific(pthread_key_t key, void *val) { } void * pthread_getspecific(pthread_key_t key) { return NULL; } int pthread_mutex_init(pthread_mutex_t *mp, void *attr) { *mp = (CRITICAL_SECTION *) malloc(sizeof(CRITICAL_SECTION)); if (!*mp) return 1; InitializeCriticalSection(*mp); return 0; } int pthread_mutex_lock(pthread_mutex_t *mp) { if (!*mp) return 1; EnterCriticalSection(*mp); return 0; } int pthread_mutex_unlock(pthread_mutex_t *mp) { if (!*mp) return 1; LeaveCriticalSection(*mp); return 0; } RPostgreSQL/src/libpq/pgsleep.c0000644000176000001440000000237012124517222016130 0ustar ripleyusers/*------------------------------------------------------------------------- * * pgsleep.c * Portable delay handling. * * * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * * src/port/pgsleep.c * *------------------------------------------------------------------------- */ #include "c.h" #include #include /* * In a Windows backend, we don't use this implementation, but rather * the signal-aware version in src/backend/port/win32/signal.c. */ #if defined(FRONTEND) || !defined(WIN32) /* * pg_usleep --- delay the specified number of microseconds. * * NOTE: although the delay is specified in microseconds, the effective * resolution is only 1/HZ, or 10 milliseconds, on most Unixen. Expect * the requested delay to be rounded up to the next resolution boundary. * * On machines where "long" is 32 bits, the maximum delay is ~2000 seconds. */ void pg_usleep(long microsec) { if (microsec > 0) { #ifndef WIN32 struct timeval delay; delay.tv_sec = microsec / 1000000L; delay.tv_usec = microsec % 1000000L; (void) select(0, NULL, NULL, NULL, &delay); #else SleepEx((microsec < 500 ? 1 : (microsec + 500) / 1000), FALSE); #endif } } #endif /* defined(FRONTEND) || !defined(WIN32) */ RPostgreSQL/src/libpq/pg_config_os.h.win0000644000176000001440000002713411663173071017742 0ustar ripleyusers/* src/include/port/win32.h */ #if defined(_MSC_VER) || defined(__BORLANDC__) #define WIN32_ONLY_COMPILER #endif /* * Make sure _WIN32_WINNT has the minumum required value. * Leave a higher value in place. */ #if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0501 #undef _WIN32_WINNT #endif #ifndef _WIN32_WINNT #define _WIN32_WINNT 0x0501 #endif /* * Always build with SSPI support. Keep it as a #define in case * we want a switch to disable it sometime in the future. */ #ifndef __BORLANDC__ #define ENABLE_SSPI 1 #endif /* undefine and redefine after #include */ #undef mkdir #undef ERROR /* * The Mingw64 headers choke if this is already defined - they * define it themselves. */ #if defined(WIN32_ONLY_COMPILER) #define _WINSOCKAPI_ #endif #include #include #include #undef small #include #include #include #include #ifndef __BORLANDC__ #include /* for non-unicode version */ #endif #undef near /* Must be here to avoid conflicting with prototype in windows.h */ #define mkdir(a,b) mkdir(a) #define ftruncate(a,b) chsize(a,b) /* Windows doesn't have fsync() as such, use _commit() */ #define fsync(fd) _commit(fd) /* * For historical reasons, we allow setting wal_sync_method to * fsync_writethrough on Windows, even though it's really identical to fsync * (both code paths wind up at _commit()). */ #define HAVE_FSYNC_WRITETHROUGH #define FSYNC_WRITETHROUGH_IS_FSYNC #define USES_WINSOCK /* defines for dynamic linking on Win32 platform */ #if defined(WIN32) || defined(__CYGWIN__) #if __GNUC__ && ! defined (__declspec) #error You need egcs 1.1 or newer for compiling! #endif #ifdef BUILDING_DLL #define PGDLLIMPORT __declspec (dllexport) #else /* not BUILDING_DLL */ #define PGDLLIMPORT __declspec (dllimport) #endif #ifdef _MSC_VER #define PGDLLEXPORT __declspec (dllexport) #else #define PGDLLEXPORT #endif #else /* not CYGWIN, not MSVC, not MingW */ #define PGDLLIMPORT #define PGDLLEXPORT #endif /* * IPC defines */ #undef HAVE_UNION_SEMUN #define HAVE_UNION_SEMUN 1 #define IPC_RMID 256 #define IPC_CREAT 512 #define IPC_EXCL 1024 #define IPC_PRIVATE 234564 #define IPC_NOWAIT 2048 #define IPC_STAT 4096 #define EACCESS 2048 #define EIDRM 4096 #define SETALL 8192 #define GETNCNT 16384 #define GETVAL 65536 #define SETVAL 131072 #define GETPID 262144 /* * Signal stuff * * For WIN32, there is no wait() call so there are no wait() macros * to interpret the return value of system(). Instead, system() * return values < 0x100 are used for exit() termination, and higher * values are used to indicated non-exit() termination, which is * similar to a unix-style signal exit (think SIGSEGV == * STATUS_ACCESS_VIOLATION). Return values are broken up into groups: * * http://msdn2.microsoft.com/en-gb/library/aa489609.aspx * * NT_SUCCESS 0 - 0x3FFFFFFF * NT_INFORMATION 0x40000000 - 0x7FFFFFFF * NT_WARNING 0x80000000 - 0xBFFFFFFF * NT_ERROR 0xC0000000 - 0xFFFFFFFF * * Effectively, we don't care on the severity of the return value from * system(), we just need to know if it was because of exit() or generated * by the system, and it seems values >= 0x100 are system-generated. * See this URL for a list of WIN32 STATUS_* values: * * Wine (URL used in our error messages) - * http://source.winehq.org/source/include/ntstatus.h * Descriptions - http://www.comp.nus.edu.sg/~wuyongzh/my_doc/ntstatus.txt * MS SDK - http://www.nologs.com/ntstatus.html * * It seems the exception lists are in both ntstatus.h and winnt.h, but * ntstatus.h has a more comprehensive list, and it only contains * exception values, rather than winnt, which contains lots of other * things: * * http://www.microsoft.com/msj/0197/exception/exception.aspx * * The ExceptionCode parameter is the number that the operating system * assigned to the exception. You can see a list of various exception codes * in WINNT.H by searching for #defines that start with "STATUS_". For * example, the code for the all-too-familiar STATUS_ACCESS_VIOLATION is * 0xC0000005. A more complete set of exception codes can be found in * NTSTATUS.H from the Windows NT DDK. * * Some day we might want to print descriptions for the most common * exceptions, rather than printing an include file name. We could use * RtlNtStatusToDosError() and pass to FormatMessage(), which can print * the text of error values, but MinGW does not support * RtlNtStatusToDosError(). */ #define WIFEXITED(w) (((w) & 0XFFFFFF00) == 0) #define WIFSIGNALED(w) (!WIFEXITED(w)) #define WEXITSTATUS(w) (w) #define WTERMSIG(w) (w) #define sigmask(sig) ( 1 << ((sig)-1) ) /* Signal function return values */ #undef SIG_DFL #undef SIG_ERR #undef SIG_IGN #define SIG_DFL ((pqsigfunc)0) #define SIG_ERR ((pqsigfunc)-1) #define SIG_IGN ((pqsigfunc)1) /* Some extra signals */ #define SIGHUP 1 #define SIGQUIT 3 #define SIGTRAP 5 #define SIGABRT 22 /* Set to match W32 value -- not UNIX value */ #define SIGKILL 9 #define SIGPIPE 13 #define SIGALRM 14 #define SIGSTOP 17 #define SIGTSTP 18 #define SIGCONT 19 #define SIGCHLD 20 #define SIGTTIN 21 #define SIGTTOU 22 /* Same as SIGABRT -- no problem, I hope */ #define SIGWINCH 28 #ifndef __BORLANDC__ #define SIGUSR1 30 #define SIGUSR2 31 #endif /* * New versions of mingw have gettimeofday() and also declare * struct timezone to support it. */ #ifndef HAVE_GETTIMEOFDAY struct timezone { int tz_minuteswest; /* Minutes west of GMT. */ int tz_dsttime; /* Nonzero if DST is ever in effect. */ }; #endif /* for setitimer in backend/port/win32/timer.c */ #define ITIMER_REAL 0 struct itimerval { struct timeval it_interval; struct timeval it_value; }; int setitimer(int which, const struct itimerval * value, struct itimerval * ovalue); /* * WIN32 does not provide 64-bit off_t, but does provide the functions operating * with 64-bit offsets. */ #define pgoff_t __int64 #ifdef WIN32_ONLY_COMPILER #define fseeko(stream, offset, origin) _fseeki64(stream, offset, origin) #define ftello(stream) _ftelli64(stream) #else #define fseeko(stream, offset, origin) fseeko64(stream, offset, origin) #define ftello(stream) ftello64(stream) #endif /* * Supplement to . * * Perl already has typedefs for uid_t and gid_t. */ #ifndef PLPERL_HAVE_UID_GID typedef int uid_t; typedef int gid_t; #endif typedef long key_t; #ifdef WIN32_ONLY_COMPILER typedef int pid_t; #endif /* * Supplement to . */ #define lstat(path, sb) stat((path), (sb)) /* * Supplement to . * This is the same value as _O_NOINHERIT in the MS header file. This is * to ensure that we don't collide with a future definition. It means * we cannot use _O_NOINHERIT ourselves. */ #define O_DSYNC 0x0080 /* * Supplement to . */ #undef EAGAIN #undef EINTR #define EINTR WSAEINTR #define EAGAIN WSAEWOULDBLOCK #define EMSGSIZE WSAEMSGSIZE #define EAFNOSUPPORT WSAEAFNOSUPPORT #define EWOULDBLOCK WSAEWOULDBLOCK #define ECONNRESET WSAECONNRESET #define EINPROGRESS WSAEINPROGRESS #define ENOBUFS WSAENOBUFS #define EPROTONOSUPPORT WSAEPROTONOSUPPORT #define ECONNREFUSED WSAECONNREFUSED #define EBADFD WSAENOTSOCK #define EOPNOTSUPP WSAEOPNOTSUPP /* * Extended locale functions with gratuitous underscore prefixes. * (These APIs are nevertheless fully documented by Microsoft.) */ #define locale_t _locale_t #define tolower_l _tolower_l #define toupper_l _toupper_l #define towlower_l _towlower_l #define towupper_l _towupper_l #define isdigit_l _isdigit_l #define iswdigit_l _iswdigit_l #define isalpha_l _isalpha_l #define iswalpha_l _iswalpha_l #define isalnum_l _isalnum_l #define iswalnum_l _iswalnum_l #define isupper_l _isupper_l #define iswupper_l _iswupper_l #define islower_l _islower_l #define iswlower_l _iswlower_l #define isgraph_l _isgraph_l #define iswgraph_l _iswgraph_l #define isprint_l _isprint_l #define iswprint_l _iswprint_l #define ispunct_l _ispunct_l #define iswpunct_l _iswpunct_l #define isspace_l _isspace_l #define iswspace_l _iswspace_l #define strcoll_l _strcoll_l #define wcscoll_l _wcscoll_l #define wcstombs_l _wcstombs_l #define mbstowcs_l _mbstowcs_l /* In backend/port/win32/signal.c */ extern PGDLLIMPORT volatile int pg_signal_queue; extern PGDLLIMPORT int pg_signal_mask; extern HANDLE pgwin32_signal_event; extern HANDLE pgwin32_initial_signal_pipe; #define UNBLOCKED_SIGNAL_QUEUE() (pg_signal_queue & ~pg_signal_mask) void pgwin32_signal_initialize(void); HANDLE pgwin32_create_signal_listener(pid_t pid); void pgwin32_dispatch_queued_signals(void); void pg_queue_signal(int signum); /* In backend/port/win32/socket.c */ #ifndef FRONTEND #define socket(af, type, protocol) pgwin32_socket(af, type, protocol) #define accept(s, addr, addrlen) pgwin32_accept(s, addr, addrlen) #define connect(s, name, namelen) pgwin32_connect(s, name, namelen) #define select(n, r, w, e, timeout) pgwin32_select(n, r, w, e, timeout) #define recv(s, buf, len, flags) pgwin32_recv(s, buf, len, flags) #define send(s, buf, len, flags) pgwin32_send(s, buf, len, flags) SOCKET pgwin32_socket(int af, int type, int protocol); SOCKET pgwin32_accept(SOCKET s, struct sockaddr * addr, int *addrlen); int pgwin32_connect(SOCKET s, const struct sockaddr * name, int namelen); int pgwin32_select(int nfds, fd_set *readfs, fd_set *writefds, fd_set *exceptfds, const struct timeval * timeout); int pgwin32_recv(SOCKET s, char *buf, int len, int flags); int pgwin32_send(SOCKET s, const void *buf, int len, int flags); const char *pgwin32_socket_strerror(int err); int pgwin32_waitforsinglesocket(SOCKET s, int what, int timeout); extern int pgwin32_noblock; /* in backend/port/win32/security.c */ extern int pgwin32_is_admin(void); extern int pgwin32_is_service(void); #endif /* in backend/port/win32_shmem.c */ extern int pgwin32_ReserveSharedMemoryRegion(HANDLE); /* in backend/port/win32/crashdump.c */ extern void pgwin32_install_crashdump_handler(void); /* in port/win32error.c */ extern void _dosmaperr(unsigned long); /* in port/win32env.c */ extern int pgwin32_putenv(const char *); extern void pgwin32_unsetenv(const char *); #define putenv(x) pgwin32_putenv(x) #define unsetenv(x) pgwin32_unsetenv(x) /* Things that exist in MingW headers, but need to be added to MSVC & BCC */ #ifdef WIN32_ONLY_COMPILER #ifndef _WIN64 typedef long ssize_t; #else typedef __int64 ssize_t; #endif #ifndef __BORLANDC__ typedef unsigned short mode_t; #define S_IRUSR _S_IREAD #define S_IWUSR _S_IWRITE #define S_IXUSR _S_IEXEC #define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) /* see also S_IRGRP etc below */ #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) #endif /* __BORLANDC__ */ #define F_OK 0 #define W_OK 2 #define R_OK 4 #define isinf(x) ((_fpclass(x) == _FPCLASS_PINF) || (_fpclass(x) == _FPCLASS_NINF)) #define isnan(x) _isnan(x) /* Pulled from Makefile.port in mingw */ #define DLSUFFIX ".dll" #ifdef __BORLANDC__ /* for port/dirent.c */ #ifndef INVALID_FILE_ATTRIBUTES #define INVALID_FILE_ATTRIBUTES ((DWORD) -1) #endif /* for port/open.c */ #ifndef O_RANDOM #define O_RANDOM 0x0010 /* File access is primarily random */ #define O_SEQUENTIAL 0x0020 /* File access is primarily sequential */ #define O_TEMPORARY 0x0040 /* Temporary file bit */ #define O_SHORT_LIVED 0x1000 /* Temporary storage file, try not to flush */ #define _O_SHORT_LIVED O_SHORT_LIVED #endif /* ifndef O_RANDOM */ #endif /* __BORLANDC__ */ #endif /* WIN32_ONLY_COMPILER */ /* These aren't provided by either MingW or MSVC */ #ifndef __BORLANDC__ #define S_IRGRP 0 #define S_IWGRP 0 #define S_IXGRP 0 #define S_IRWXG 0 #define S_IROTH 0 #define S_IWOTH 0 #define S_IXOTH 0 #define S_IRWXO 0 #endif /* __BORLANDC__ */ RPostgreSQL/src/libpq/postgres_ext.h0000644000176000001440000000336212124517222017226 0ustar ripleyusers/*------------------------------------------------------------------------- * * postgres_ext.h * * This file contains declarations of things that are visible everywhere * in PostgreSQL *and* are visible to clients of frontend interface libraries. * For example, the Oid type is part of the API of libpq and other libraries. * * Declarations which are specific to a particular interface should * go in the header file for that interface (such as libpq-fe.h). This * file is only for fundamental Postgres declarations. * * User-written C functions don't count as "external to Postgres." * Those function much as local modifications to the backend itself, and * use header files that are otherwise internal to Postgres to interface * with the backend. * * src/include/postgres_ext.h * *------------------------------------------------------------------------- */ #ifndef POSTGRES_EXT_H #define POSTGRES_EXT_H /* * Object ID is a fundamental type in Postgres. */ typedef unsigned int Oid; #ifdef __cplusplus #define InvalidOid (Oid(0)) #else #define InvalidOid ((Oid) 0) #endif #define OID_MAX UINT_MAX /* you will need to include to use the above #define */ /* * Identifiers of error message fields. Kept here to keep common * between frontend and backend, and also to export them to libpq * applications. */ #define PG_DIAG_SEVERITY 'S' #define PG_DIAG_SQLSTATE 'C' #define PG_DIAG_MESSAGE_PRIMARY 'M' #define PG_DIAG_MESSAGE_DETAIL 'D' #define PG_DIAG_MESSAGE_HINT 'H' #define PG_DIAG_STATEMENT_POSITION 'P' #define PG_DIAG_INTERNAL_POSITION 'p' #define PG_DIAG_INTERNAL_QUERY 'q' #define PG_DIAG_CONTEXT 'W' #define PG_DIAG_SOURCE_FILE 'F' #define PG_DIAG_SOURCE_LINE 'L' #define PG_DIAG_SOURCE_FUNCTION 'R' #endif RPostgreSQL/src/libpq/ip.c0000644000176000001440000005041712124517222015106 0ustar ripleyusers/*------------------------------------------------------------------------- * * ip.c * IPv6-aware network access. * * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * src/backend/libpq/ip.c * * This file and the IPV6 implementation were initially provided by * Nigel Kukard , Linux Based Systems Design * http://www.lbsd.net. * *------------------------------------------------------------------------- */ /* This is intended to be used in both frontend and backend, so use c.h */ #include "c.h" #include #include #include #include #include #include #ifdef HAVE_NETINET_TCP_H #include #endif #include #include #include "libpq/ip.h" static int range_sockaddr_AF_INET(const struct sockaddr_in * addr, const struct sockaddr_in * netaddr, const struct sockaddr_in * netmask); #ifdef HAVE_IPV6 static int range_sockaddr_AF_INET6(const struct sockaddr_in6 * addr, const struct sockaddr_in6 * netaddr, const struct sockaddr_in6 * netmask); #endif #ifdef HAVE_UNIX_SOCKETS static int getaddrinfo_unix(const char *path, const struct addrinfo * hintsp, struct addrinfo ** result); static int getnameinfo_unix(const struct sockaddr_un * sa, int salen, char *node, int nodelen, char *service, int servicelen, int flags); #endif /* * pg_getaddrinfo_all - get address info for Unix, IPv4 and IPv6 sockets */ int pg_getaddrinfo_all(const char *hostname, const char *servname, const struct addrinfo * hintp, struct addrinfo ** result) { int rc; /* not all versions of getaddrinfo() zero *result on failure */ *result = NULL; #ifdef HAVE_UNIX_SOCKETS if (hintp->ai_family == AF_UNIX) return getaddrinfo_unix(servname, hintp, result); #endif /* NULL has special meaning to getaddrinfo(). */ rc = getaddrinfo((!hostname || hostname[0] == '\0') ? NULL : hostname, servname, hintp, result); return rc; } /* * pg_freeaddrinfo_all - free addrinfo structures for IPv4, IPv6, or Unix * * Note: the ai_family field of the original hint structure must be passed * so that we can tell whether the addrinfo struct was built by the system's * getaddrinfo() routine or our own getaddrinfo_unix() routine. Some versions * of getaddrinfo() might be willing to return AF_UNIX addresses, so it's * not safe to look at ai_family in the addrinfo itself. */ void pg_freeaddrinfo_all(int hint_ai_family, struct addrinfo * ai) { #ifdef HAVE_UNIX_SOCKETS if (hint_ai_family == AF_UNIX) { /* struct was built by getaddrinfo_unix (see pg_getaddrinfo_all) */ while (ai != NULL) { struct addrinfo *p = ai; ai = ai->ai_next; free(p->ai_addr); free(p); } } else #endif /* HAVE_UNIX_SOCKETS */ { /* struct was built by getaddrinfo() */ if (ai != NULL) freeaddrinfo(ai); } } /* * pg_getnameinfo_all - get name info for Unix, IPv4 and IPv6 sockets * * The API of this routine differs from the standard getnameinfo() definition * in two ways: first, the addr parameter is declared as sockaddr_storage * rather than struct sockaddr, and second, the node and service fields are * guaranteed to be filled with something even on failure return. */ int pg_getnameinfo_all(const struct sockaddr_storage * addr, int salen, char *node, int nodelen, char *service, int servicelen, int flags) { int rc; #ifdef HAVE_UNIX_SOCKETS if (addr && addr->ss_family == AF_UNIX) rc = getnameinfo_unix((const struct sockaddr_un *) addr, salen, node, nodelen, service, servicelen, flags); else #endif rc = getnameinfo((const struct sockaddr *) addr, salen, node, nodelen, service, servicelen, flags); if (rc != 0) { if (node) strlcpy(node, "???", nodelen); if (service) strlcpy(service, "???", servicelen); } return rc; } #if defined(HAVE_UNIX_SOCKETS) /* ------- * getaddrinfo_unix - get unix socket info using IPv6-compatible API * * Bugs: only one addrinfo is set even though hintsp is NULL or * ai_socktype is 0 * AI_CANONNAME is not supported. * ------- */ static int getaddrinfo_unix(const char *path, const struct addrinfo * hintsp, struct addrinfo ** result) { struct addrinfo hints; struct addrinfo *aip; struct sockaddr_un *unp; *result = NULL; MemSet(&hints, 0, sizeof(hints)); if (strlen(path) >= sizeof(unp->sun_path)) return EAI_FAIL; if (hintsp == NULL) { hints.ai_family = AF_UNIX; hints.ai_socktype = SOCK_STREAM; } else memcpy(&hints, hintsp, sizeof(hints)); if (hints.ai_socktype == 0) hints.ai_socktype = SOCK_STREAM; if (hints.ai_family != AF_UNIX) { /* shouldn't have been called */ return EAI_FAIL; } aip = calloc(1, sizeof(struct addrinfo)); if (aip == NULL) return EAI_MEMORY; unp = calloc(1, sizeof(struct sockaddr_un)); if (unp == NULL) { free(aip); return EAI_MEMORY; } aip->ai_family = AF_UNIX; aip->ai_socktype = hints.ai_socktype; aip->ai_protocol = hints.ai_protocol; aip->ai_next = NULL; aip->ai_canonname = NULL; *result = aip; unp->sun_family = AF_UNIX; aip->ai_addr = (struct sockaddr *) unp; aip->ai_addrlen = sizeof(struct sockaddr_un); strcpy(unp->sun_path, path); #ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN unp->sun_len = sizeof(struct sockaddr_un); #endif return 0; } /* * Convert an address to a hostname. */ static int getnameinfo_unix(const struct sockaddr_un * sa, int salen, char *node, int nodelen, char *service, int servicelen, int flags) { int ret = -1; /* Invalid arguments. */ if (sa == NULL || sa->sun_family != AF_UNIX || (node == NULL && service == NULL)) return EAI_FAIL; /* We don't support those. */ if ((node && !(flags & NI_NUMERICHOST)) || (service && !(flags & NI_NUMERICSERV))) return EAI_FAIL; if (node) { ret = snprintf(node, nodelen, "%s", "[local]"); if (ret == -1 || ret > nodelen) return EAI_MEMORY; } if (service) { ret = snprintf(service, servicelen, "%s", sa->sun_path); if (ret == -1 || ret > servicelen) return EAI_MEMORY; } return 0; } #endif /* HAVE_UNIX_SOCKETS */ /* * pg_range_sockaddr - is addr within the subnet specified by netaddr/netmask ? * * Note: caller must already have verified that all three addresses are * in the same address family; and AF_UNIX addresses are not supported. */ int pg_range_sockaddr(const struct sockaddr_storage * addr, const struct sockaddr_storage * netaddr, const struct sockaddr_storage * netmask) { if (addr->ss_family == AF_INET) return range_sockaddr_AF_INET((struct sockaddr_in *) addr, (struct sockaddr_in *) netaddr, (struct sockaddr_in *) netmask); #ifdef HAVE_IPV6 else if (addr->ss_family == AF_INET6) return range_sockaddr_AF_INET6((struct sockaddr_in6 *) addr, (struct sockaddr_in6 *) netaddr, (struct sockaddr_in6 *) netmask); #endif else return 0; } static int range_sockaddr_AF_INET(const struct sockaddr_in * addr, const struct sockaddr_in * netaddr, const struct sockaddr_in * netmask) { if (((addr->sin_addr.s_addr ^ netaddr->sin_addr.s_addr) & netmask->sin_addr.s_addr) == 0) return 1; else return 0; } #ifdef HAVE_IPV6 static int range_sockaddr_AF_INET6(const struct sockaddr_in6 * addr, const struct sockaddr_in6 * netaddr, const struct sockaddr_in6 * netmask) { int i; for (i = 0; i < 16; i++) { if (((addr->sin6_addr.s6_addr[i] ^ netaddr->sin6_addr.s6_addr[i]) & netmask->sin6_addr.s6_addr[i]) != 0) return 0; } return 1; } #endif /* HAVE_IPV6 */ /* * pg_sockaddr_cidr_mask - make a network mask of the appropriate family * and required number of significant bits * * numbits can be null, in which case the mask is fully set. * * The resulting mask is placed in *mask, which had better be big enough. * * Return value is 0 if okay, -1 if not. */ int pg_sockaddr_cidr_mask(struct sockaddr_storage * mask, char *numbits, int family) { long bits; char *endptr; if (numbits == NULL) { bits = (family == AF_INET) ? 32 : 128; } else { bits = strtol(numbits, &endptr, 10); if (*numbits == '\0' || *endptr != '\0') return -1; } switch (family) { case AF_INET: { struct sockaddr_in mask4; long maskl; if (bits < 0 || bits > 32) return -1; memset(&mask4, 0, sizeof(mask4)); /* avoid "x << 32", which is not portable */ if (bits > 0) maskl = (0xffffffffUL << (32 - (int) bits)) & 0xffffffffUL; else maskl = 0; mask4.sin_addr.s_addr = htonl(maskl); memcpy(mask, &mask4, sizeof(mask4)); break; } #ifdef HAVE_IPV6 case AF_INET6: { struct sockaddr_in6 mask6; int i; if (bits < 0 || bits > 128) return -1; memset(&mask6, 0, sizeof(mask6)); for (i = 0; i < 16; i++) { if (bits <= 0) mask6.sin6_addr.s6_addr[i] = 0; else if (bits >= 8) mask6.sin6_addr.s6_addr[i] = 0xff; else { mask6.sin6_addr.s6_addr[i] = (0xff << (8 - (int) bits)) & 0xff; } bits -= 8; } memcpy(mask, &mask6, sizeof(mask6)); break; } #endif default: return -1; } mask->ss_family = family; return 0; } #ifdef HAVE_IPV6 /* * pg_promote_v4_to_v6_addr --- convert an AF_INET addr to AF_INET6, using * the standard convention for IPv4 addresses mapped into IPv6 world * * The passed addr is modified in place; be sure it is large enough to * hold the result! Note that we only worry about setting the fields * that pg_range_sockaddr will look at. */ void pg_promote_v4_to_v6_addr(struct sockaddr_storage * addr) { struct sockaddr_in addr4; struct sockaddr_in6 addr6; uint32 ip4addr; memcpy(&addr4, addr, sizeof(addr4)); ip4addr = ntohl(addr4.sin_addr.s_addr); memset(&addr6, 0, sizeof(addr6)); addr6.sin6_family = AF_INET6; addr6.sin6_addr.s6_addr[10] = 0xff; addr6.sin6_addr.s6_addr[11] = 0xff; addr6.sin6_addr.s6_addr[12] = (ip4addr >> 24) & 0xFF; addr6.sin6_addr.s6_addr[13] = (ip4addr >> 16) & 0xFF; addr6.sin6_addr.s6_addr[14] = (ip4addr >> 8) & 0xFF; addr6.sin6_addr.s6_addr[15] = (ip4addr) & 0xFF; memcpy(addr, &addr6, sizeof(addr6)); } /* * pg_promote_v4_to_v6_mask --- convert an AF_INET netmask to AF_INET6, using * the standard convention for IPv4 addresses mapped into IPv6 world * * This must be different from pg_promote_v4_to_v6_addr because we want to * set the high-order bits to 1's not 0's. * * The passed addr is modified in place; be sure it is large enough to * hold the result! Note that we only worry about setting the fields * that pg_range_sockaddr will look at. */ void pg_promote_v4_to_v6_mask(struct sockaddr_storage * addr) { struct sockaddr_in addr4; struct sockaddr_in6 addr6; uint32 ip4addr; int i; memcpy(&addr4, addr, sizeof(addr4)); ip4addr = ntohl(addr4.sin_addr.s_addr); memset(&addr6, 0, sizeof(addr6)); addr6.sin6_family = AF_INET6; for (i = 0; i < 12; i++) addr6.sin6_addr.s6_addr[i] = 0xff; addr6.sin6_addr.s6_addr[12] = (ip4addr >> 24) & 0xFF; addr6.sin6_addr.s6_addr[13] = (ip4addr >> 16) & 0xFF; addr6.sin6_addr.s6_addr[14] = (ip4addr >> 8) & 0xFF; addr6.sin6_addr.s6_addr[15] = (ip4addr) & 0xFF; memcpy(addr, &addr6, sizeof(addr6)); } #endif /* HAVE_IPV6 */ /* * Run the callback function for the addr/mask, after making sure the * mask is sane for the addr. */ static void run_ifaddr_callback(PgIfAddrCallback callback, void *cb_data, struct sockaddr * addr, struct sockaddr * mask) { struct sockaddr_storage fullmask; if (!addr) return; /* Check that the mask is valid */ if (mask) { if (mask->sa_family != addr->sa_family) { mask = NULL; } else if (mask->sa_family == AF_INET) { if (((struct sockaddr_in *) mask)->sin_addr.s_addr == INADDR_ANY) mask = NULL; } #ifdef HAVE_IPV6 else if (mask->sa_family == AF_INET6) { if (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *) mask)->sin6_addr)) mask = NULL; } #endif } /* If mask is invalid, generate our own fully-set mask */ if (!mask) { pg_sockaddr_cidr_mask(&fullmask, NULL, addr->sa_family); mask = (struct sockaddr *) & fullmask; } (*callback) (addr, mask, cb_data); } #ifdef WIN32 #include #include /* * Enumerate the system's network interface addresses and call the callback * for each one. Returns 0 if successful, -1 if trouble. * * This version is for Win32. Uses the Winsock 2 functions (ie: ws2_32.dll) */ int pg_foreach_ifaddr(PgIfAddrCallback callback, void *cb_data) { INTERFACE_INFO *ptr, *ii = NULL; unsigned long length, i; unsigned long n_ii = 0; SOCKET sock; int error; sock = WSASocket(AF_INET, SOCK_DGRAM, 0, 0, 0, 0); if (sock == SOCKET_ERROR) return -1; while (n_ii < 1024) { n_ii += 64; ptr = realloc(ii, sizeof(INTERFACE_INFO) * n_ii); if (!ptr) { free(ii); closesocket(sock); errno = ENOMEM; return -1; } ii = ptr; if (WSAIoctl(sock, SIO_GET_INTERFACE_LIST, 0, 0, ii, n_ii * sizeof(INTERFACE_INFO), &length, 0, 0) == SOCKET_ERROR) { error = WSAGetLastError(); if (error == WSAEFAULT || error == WSAENOBUFS) continue; /* need to make the buffer bigger */ closesocket(sock); free(ii); return -1; } break; } for (i = 0; i < length / sizeof(INTERFACE_INFO); ++i) run_ifaddr_callback(callback, cb_data, (struct sockaddr *) & ii[i].iiAddress, (struct sockaddr *) & ii[i].iiNetmask); closesocket(sock); free(ii); return 0; } #elif HAVE_GETIFADDRS /* && !WIN32 */ #ifdef HAVE_IFADDRS_H #include #endif /* * Enumerate the system's network interface addresses and call the callback * for each one. Returns 0 if successful, -1 if trouble. * * This version uses the getifaddrs() interface, which is available on * BSDs, AIX, and modern Linux. */ int pg_foreach_ifaddr(PgIfAddrCallback callback, void *cb_data) { struct ifaddrs *ifa, *l; if (getifaddrs(&ifa) < 0) return -1; for (l = ifa; l; l = l->ifa_next) run_ifaddr_callback(callback, cb_data, l->ifa_addr, l->ifa_netmask); freeifaddrs(ifa); return 0; } #else /* !HAVE_GETIFADDRS && !WIN32 */ #ifdef HAVE_SYS_IOCTL_H #include #endif #ifdef HAVE_NET_IF_H #include #endif #ifdef HAVE_SYS_SOCKIO_H #include #endif /* * SIOCGIFCONF does not return IPv6 addresses on Solaris * and HP/UX. So we prefer SIOCGLIFCONF if it's available. * * On HP/UX, however, it *only* returns IPv6 addresses, * and the structs are named slightly differently too. * We'd have to do another call with SIOCGIFCONF to get the * IPv4 addresses as well. We don't currently bother, just * fall back to SIOCGIFCONF on HP/UX. */ #if defined(SIOCGLIFCONF) && !defined(__hpux) /* * Enumerate the system's network interface addresses and call the callback * for each one. Returns 0 if successful, -1 if trouble. * * This version uses ioctl(SIOCGLIFCONF). */ int pg_foreach_ifaddr(PgIfAddrCallback callback, void *cb_data) { struct lifconf lifc; struct lifreq *lifr, lmask; struct sockaddr *addr, *mask; char *ptr, *buffer = NULL; size_t n_buffer = 1024; pgsocket sock, fd; #ifdef HAVE_IPV6 pgsocket sock6; #endif int i, total; sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock == -1) return -1; while (n_buffer < 1024 * 100) { n_buffer += 1024; ptr = realloc(buffer, n_buffer); if (!ptr) { free(buffer); close(sock); errno = ENOMEM; return -1; } memset(&lifc, 0, sizeof(lifc)); lifc.lifc_family = AF_UNSPEC; lifc.lifc_buf = buffer = ptr; lifc.lifc_len = n_buffer; if (ioctl(sock, SIOCGLIFCONF, &lifc) < 0) { if (errno == EINVAL) continue; free(buffer); close(sock); return -1; } /* * Some Unixes try to return as much data as possible, with no * indication of whether enough space allocated. Don't believe we have * it all unless there's lots of slop. */ if (lifc.lifc_len < n_buffer - 1024) break; } #ifdef HAVE_IPV6 /* We'll need an IPv6 socket too for the SIOCGLIFNETMASK ioctls */ sock6 = socket(AF_INET6, SOCK_DGRAM, 0); if (sock6 == -1) { free(buffer); close(sock); return -1; } #endif total = lifc.lifc_len / sizeof(struct lifreq); lifr = lifc.lifc_req; for (i = 0; i < total; ++i) { addr = (struct sockaddr *) & lifr[i].lifr_addr; memcpy(&lmask, &lifr[i], sizeof(struct lifreq)); #ifdef HAVE_IPV6 fd = (addr->sa_family == AF_INET6) ? sock6 : sock; #else fd = sock; #endif if (ioctl(fd, SIOCGLIFNETMASK, &lmask) < 0) mask = NULL; else mask = (struct sockaddr *) & lmask.lifr_addr; run_ifaddr_callback(callback, cb_data, addr, mask); } free(buffer); close(sock); #ifdef HAVE_IPV6 close(sock6); #endif return 0; } #elif defined(SIOCGIFCONF) /* * Remaining Unixes use SIOCGIFCONF. Some only return IPv4 information * here, so this is the least preferred method. Note that there is no * standard way to iterate the struct ifreq returned in the array. * On some OSs the structures are padded large enough for any address, * on others you have to calculate the size of the struct ifreq. */ /* Some OSs have _SIZEOF_ADDR_IFREQ, so just use that */ #ifndef _SIZEOF_ADDR_IFREQ /* Calculate based on sockaddr.sa_len */ #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN #define _SIZEOF_ADDR_IFREQ(ifr) \ ((ifr).ifr_addr.sa_len > sizeof(struct sockaddr) ? \ (sizeof(struct ifreq) - sizeof(struct sockaddr) + \ (ifr).ifr_addr.sa_len) : sizeof(struct ifreq)) /* Padded ifreq structure, simple */ #else #define _SIZEOF_ADDR_IFREQ(ifr) \ sizeof (struct ifreq) #endif #endif /* !_SIZEOF_ADDR_IFREQ */ /* * Enumerate the system's network interface addresses and call the callback * for each one. Returns 0 if successful, -1 if trouble. * * This version uses ioctl(SIOCGIFCONF). */ int pg_foreach_ifaddr(PgIfAddrCallback callback, void *cb_data) { struct ifconf ifc; struct ifreq *ifr, *end, addr, mask; char *ptr, *buffer = NULL; size_t n_buffer = 1024; int sock; sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock == -1) return -1; while (n_buffer < 1024 * 100) { n_buffer += 1024; ptr = realloc(buffer, n_buffer); if (!ptr) { free(buffer); close(sock); errno = ENOMEM; return -1; } memset(&ifc, 0, sizeof(ifc)); ifc.ifc_buf = buffer = ptr; ifc.ifc_len = n_buffer; if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) { if (errno == EINVAL) continue; free(buffer); close(sock); return -1; } /* * Some Unixes try to return as much data as possible, with no * indication of whether enough space allocated. Don't believe we have * it all unless there's lots of slop. */ if (ifc.ifc_len < n_buffer - 1024) break; } end = (struct ifreq *) (buffer + ifc.ifc_len); for (ifr = ifc.ifc_req; ifr < end;) { memcpy(&addr, ifr, sizeof(addr)); memcpy(&mask, ifr, sizeof(mask)); if (ioctl(sock, SIOCGIFADDR, &addr, sizeof(addr)) == 0 && ioctl(sock, SIOCGIFNETMASK, &mask, sizeof(mask)) == 0) run_ifaddr_callback(callback, cb_data, &addr.ifr_addr, &mask.ifr_addr); ifr = (struct ifreq *) ((char *) ifr + _SIZEOF_ADDR_IFREQ(*ifr)); } free(buffer); close(sock); return 0; } #else /* !defined(SIOCGIFCONF) */ /* * Enumerate the system's network interface addresses and call the callback * for each one. Returns 0 if successful, -1 if trouble. * * This version is our fallback if there's no known way to get the * interface addresses. Just return the standard loopback addresses. */ int pg_foreach_ifaddr(PgIfAddrCallback callback, void *cb_data) { struct sockaddr_in addr; struct sockaddr_storage mask; #ifdef HAVE_IPV6 struct sockaddr_in6 addr6; #endif /* addr 127.0.0.1/8 */ memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = ntohl(0x7f000001); memset(&mask, 0, sizeof(mask)); pg_sockaddr_cidr_mask(&mask, "8", AF_INET); run_ifaddr_callback(callback, cb_data, (struct sockaddr *) & addr, (struct sockaddr *) & mask); #ifdef HAVE_IPV6 /* addr ::1/128 */ memset(&addr6, 0, sizeof(addr6)); addr6.sin6_family = AF_INET6; addr6.sin6_addr.s6_addr[15] = 1; memset(&mask, 0, sizeof(mask)); pg_sockaddr_cidr_mask(&mask, "128", AF_INET6); run_ifaddr_callback(callback, cb_data, (struct sockaddr *) & addr6, (struct sockaddr *) & mask); #endif return 0; } #endif /* !defined(SIOCGIFCONF) */ #endif /* !HAVE_GETIFADDRS */ RPostgreSQL/src/libpq/chklocale.c0000644000176000001440000001740512124517222016423 0ustar ripleyusers/*------------------------------------------------------------------------- * * chklocale.c * Functions for handling locale-related info * * * Copyright (c) 1996-2011, PostgreSQL Global Development Group * * * IDENTIFICATION * src/port/chklocale.c * *------------------------------------------------------------------------- */ #ifndef FRONTEND #include "postgres.h" #else #include "postgres_fe.h" #endif #include #ifdef HAVE_LANGINFO_H #include #endif #include "mb/pg_wchar.h" /* * This table needs to recognize all the CODESET spellings for supported * backend encodings, as well as frontend-only encodings where possible * (the latter case is currently only needed for initdb to recognize * error situations). On Windows, we rely on entries for codepage * numbers (CPnnn). * * Note that we search the table with pg_strcasecmp(), so variant * capitalizations don't need their own entries. */ struct encoding_match { enum pg_enc pg_enc_code; const char *system_enc_name; }; static const struct encoding_match encoding_match_list[] = { {PG_EUC_JP, "EUC-JP"}, {PG_EUC_JP, "eucJP"}, {PG_EUC_JP, "IBM-eucJP"}, {PG_EUC_JP, "sdeckanji"}, {PG_EUC_JP, "CP20932"}, {PG_EUC_CN, "EUC-CN"}, {PG_EUC_CN, "eucCN"}, {PG_EUC_CN, "IBM-eucCN"}, {PG_EUC_CN, "GB2312"}, {PG_EUC_CN, "dechanzi"}, {PG_EUC_CN, "CP20936"}, {PG_EUC_KR, "EUC-KR"}, {PG_EUC_KR, "eucKR"}, {PG_EUC_KR, "IBM-eucKR"}, {PG_EUC_KR, "deckorean"}, {PG_EUC_KR, "5601"}, {PG_EUC_KR, "CP51949"}, {PG_EUC_TW, "EUC-TW"}, {PG_EUC_TW, "eucTW"}, {PG_EUC_TW, "IBM-eucTW"}, {PG_EUC_TW, "cns11643"}, /* No codepage for EUC-TW ? */ {PG_UTF8, "UTF-8"}, {PG_UTF8, "utf8"}, {PG_UTF8, "CP65001"}, {PG_LATIN1, "ISO-8859-1"}, {PG_LATIN1, "ISO8859-1"}, {PG_LATIN1, "iso88591"}, {PG_LATIN1, "CP28591"}, {PG_LATIN2, "ISO-8859-2"}, {PG_LATIN2, "ISO8859-2"}, {PG_LATIN2, "iso88592"}, {PG_LATIN2, "CP28592"}, {PG_LATIN3, "ISO-8859-3"}, {PG_LATIN3, "ISO8859-3"}, {PG_LATIN3, "iso88593"}, {PG_LATIN3, "CP28593"}, {PG_LATIN4, "ISO-8859-4"}, {PG_LATIN4, "ISO8859-4"}, {PG_LATIN4, "iso88594"}, {PG_LATIN4, "CP28594"}, {PG_LATIN5, "ISO-8859-9"}, {PG_LATIN5, "ISO8859-9"}, {PG_LATIN5, "iso88599"}, {PG_LATIN5, "CP28599"}, {PG_LATIN6, "ISO-8859-10"}, {PG_LATIN6, "ISO8859-10"}, {PG_LATIN6, "iso885910"}, {PG_LATIN7, "ISO-8859-13"}, {PG_LATIN7, "ISO8859-13"}, {PG_LATIN7, "iso885913"}, {PG_LATIN8, "ISO-8859-14"}, {PG_LATIN8, "ISO8859-14"}, {PG_LATIN8, "iso885914"}, {PG_LATIN9, "ISO-8859-15"}, {PG_LATIN9, "ISO8859-15"}, {PG_LATIN9, "iso885915"}, {PG_LATIN9, "CP28605"}, {PG_LATIN10, "ISO-8859-16"}, {PG_LATIN10, "ISO8859-16"}, {PG_LATIN10, "iso885916"}, {PG_KOI8R, "KOI8-R"}, {PG_KOI8R, "CP20866"}, {PG_KOI8U, "KOI8-U"}, {PG_KOI8U, "CP21866"}, {PG_WIN866, "CP866"}, {PG_WIN874, "CP874"}, {PG_WIN1250, "CP1250"}, {PG_WIN1251, "CP1251"}, {PG_WIN1251, "ansi-1251"}, {PG_WIN1252, "CP1252"}, {PG_WIN1253, "CP1253"}, {PG_WIN1254, "CP1254"}, {PG_WIN1255, "CP1255"}, {PG_WIN1256, "CP1256"}, {PG_WIN1257, "CP1257"}, {PG_WIN1258, "CP1258"}, {PG_ISO_8859_5, "ISO-8859-5"}, {PG_ISO_8859_5, "ISO8859-5"}, {PG_ISO_8859_5, "iso88595"}, {PG_ISO_8859_5, "CP28595"}, {PG_ISO_8859_6, "ISO-8859-6"}, {PG_ISO_8859_6, "ISO8859-6"}, {PG_ISO_8859_6, "iso88596"}, {PG_ISO_8859_6, "CP28596"}, {PG_ISO_8859_7, "ISO-8859-7"}, {PG_ISO_8859_7, "ISO8859-7"}, {PG_ISO_8859_7, "iso88597"}, {PG_ISO_8859_7, "CP28597"}, {PG_ISO_8859_8, "ISO-8859-8"}, {PG_ISO_8859_8, "ISO8859-8"}, {PG_ISO_8859_8, "iso88598"}, {PG_ISO_8859_8, "CP28598"}, {PG_SJIS, "SJIS"}, {PG_SJIS, "PCK"}, {PG_SJIS, "CP932"}, {PG_BIG5, "BIG5"}, {PG_BIG5, "BIG5HKSCS"}, {PG_BIG5, "Big5-HKSCS"}, {PG_BIG5, "CP950"}, {PG_GBK, "GBK"}, {PG_GBK, "CP936"}, {PG_UHC, "UHC"}, {PG_UHC, "CP949"}, {PG_JOHAB, "JOHAB"}, {PG_JOHAB, "CP1361"}, {PG_GB18030, "GB18030"}, {PG_GB18030, "CP54936"}, {PG_SHIFT_JIS_2004, "SJIS_2004"}, {PG_SQL_ASCII, "US-ASCII"}, {PG_SQL_ASCII, NULL} /* end marker */ }; #ifdef WIN32 /* * On Windows, use CP instead of the nl_langinfo() result */ static char * win32_langinfo(const char *ctype) { char *r; char *codepage; int ln; /* * Locale format on Win32 is _. . For * example, English_USA.1252. */ codepage = strrchr(ctype, '.'); if (!codepage) return NULL; codepage++; ln = strlen(codepage); r = malloc(ln + 3); sprintf(r, "CP%s", codepage); return r; } #endif /* WIN32 */ #if (defined(HAVE_LANGINFO_H) && defined(CODESET)) || defined(WIN32) /* * Given a setting for LC_CTYPE, return the Postgres ID of the associated * encoding, if we can determine it. Return -1 if we can't determine it. * * Pass in NULL to get the encoding for the current locale setting. * Pass "" to get the encoding selected by the server's environment. * * If the result is PG_SQL_ASCII, callers should treat it as being compatible * with any desired encoding. */ int pg_get_encoding_from_locale(const char *ctype, bool write_message) { char *sys; int i; /* Get the CODESET property, and also LC_CTYPE if not passed in */ if (ctype) { char *save; char *name; /* If locale is C or POSIX, we can allow all encodings */ if (pg_strcasecmp(ctype, "C") == 0 || pg_strcasecmp(ctype, "POSIX") == 0) return PG_SQL_ASCII; save = setlocale(LC_CTYPE, NULL); if (!save) return -1; /* setlocale() broken? */ /* must copy result, or it might change after setlocale */ save = strdup(save); if (!save) return -1; /* out of memory; unlikely */ name = setlocale(LC_CTYPE, ctype); if (!name) { free(save); return -1; /* bogus ctype passed in? */ } #ifndef WIN32 sys = nl_langinfo(CODESET); if (sys) sys = strdup(sys); #else sys = win32_langinfo(name); #endif setlocale(LC_CTYPE, save); free(save); } else { /* much easier... */ ctype = setlocale(LC_CTYPE, NULL); if (!ctype) return -1; /* setlocale() broken? */ /* If locale is C or POSIX, we can allow all encodings */ if (pg_strcasecmp(ctype, "C") == 0 || pg_strcasecmp(ctype, "POSIX") == 0) return PG_SQL_ASCII; #ifndef WIN32 sys = nl_langinfo(CODESET); if (sys) sys = strdup(sys); #else sys = win32_langinfo(ctype); #endif } if (!sys) return -1; /* out of memory; unlikely */ /* Check the table */ for (i = 0; encoding_match_list[i].system_enc_name; i++) { if (pg_strcasecmp(sys, encoding_match_list[i].system_enc_name) == 0) { free(sys); return encoding_match_list[i].pg_enc_code; } } /* Special-case kluges for particular platforms go here */ #ifdef __darwin__ /* * Current OS X has many locales that report an empty string for CODESET, * but they all seem to actually use UTF-8. */ if (strlen(sys) == 0) { free(sys); return PG_UTF8; } #endif /* * We print a warning if we got a CODESET string but couldn't recognize * it. This means we need another entry in the table. */ if (write_message) { #ifdef FRONTEND fprintf(stderr, _("could not determine encoding for locale \"%s\": codeset is \"%s\""), ctype, sys); /* keep newline separate so there's only one translatable string */ fputc('\n', stderr); #else ereport(WARNING, (errmsg("could not determine encoding for locale \"%s\": codeset is \"%s\"", ctype, sys), errdetail("Please report this to ."))); #endif } free(sys); return -1; } #else /* (HAVE_LANGINFO_H && CODESET) || WIN32 */ /* * stub if no multi-language platform support * * Note: we could return -1 here, but that would have the effect of * forcing users to specify an encoding to initdb on such platforms. * It seems better to silently default to SQL_ASCII. */ int pg_get_encoding_from_locale(const char *ctype, bool write_message) { return PG_SQL_ASCII; } #endif /* (HAVE_LANGINFO_H && CODESET) || WIN32 */ RPostgreSQL/src/libpq/fe-protocol2.c0000644000176000001440000011360012124517222017003 0ustar ripleyusers/*------------------------------------------------------------------------- * * fe-protocol2.c * functions that are specific to frontend/backend protocol version 2 * * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * src/interfaces/libpq/fe-protocol2.c * *------------------------------------------------------------------------- */ #include "postgres_fe.h" #include #include #include "libpq-fe.h" #include "libpq-int.h" #ifdef WIN32 #include "win32.h" #else #include #include #ifdef HAVE_NETINET_TCP_H #include #endif #include #endif static int getRowDescriptions(PGconn *conn); static int getAnotherTuple(PGconn *conn, bool binary); static int pqGetErrorNotice2(PGconn *conn, bool isError); static void checkXactStatus(PGconn *conn, const char *cmdTag); static int getNotify(PGconn *conn); /* * pqSetenvPoll * * Polls the process of passing the values of a standard set of environment * variables to the backend. */ PostgresPollingStatusType pqSetenvPoll(PGconn *conn) { PGresult *res; if (conn == NULL || conn->status == CONNECTION_BAD) return PGRES_POLLING_FAILED; /* Check whether there are any data for us */ switch (conn->setenv_state) { /* These are reading states */ case SETENV_STATE_CLIENT_ENCODING_WAIT: case SETENV_STATE_OPTION_WAIT: case SETENV_STATE_QUERY1_WAIT: case SETENV_STATE_QUERY2_WAIT: { /* Load waiting data */ int n = pqReadData(conn); if (n < 0) goto error_return; if (n == 0) return PGRES_POLLING_READING; break; } /* These are writing states, so we just proceed. */ case SETENV_STATE_CLIENT_ENCODING_SEND: case SETENV_STATE_OPTION_SEND: case SETENV_STATE_QUERY1_SEND: case SETENV_STATE_QUERY2_SEND: break; /* Should we raise an error if called when not active? */ case SETENV_STATE_IDLE: return PGRES_POLLING_OK; default: printfPQExpBuffer(&conn->errorMessage, libpq_gettext( "invalid setenv state %c, " "probably indicative of memory corruption\n" ), conn->setenv_state); goto error_return; } /* We will loop here until there is nothing left to do in this call. */ for (;;) { switch (conn->setenv_state) { /* * The _CLIENT_ENCODING_SEND code is slightly different from * _OPTION_SEND below (e.g., no getenv() call), which is why a * different state is used. */ case SETENV_STATE_CLIENT_ENCODING_SEND: { char setQuery[100]; /* note length limit in * sprintf below */ const char *val = conn->client_encoding_initial; if (val) { if (pg_strcasecmp(val, "default") == 0) sprintf(setQuery, "SET client_encoding = DEFAULT"); else sprintf(setQuery, "SET client_encoding = '%.60s'", val); #ifdef CONNECTDEBUG fprintf(stderr, "Sending client_encoding with %s\n", setQuery); #endif if (!PQsendQuery(conn, setQuery)) goto error_return; conn->setenv_state = SETENV_STATE_CLIENT_ENCODING_WAIT; } else conn->setenv_state = SETENV_STATE_OPTION_SEND; break; } case SETENV_STATE_OPTION_SEND: { /* * Send SET commands for stuff directed by Environment * Options. Note: we assume that SET commands won't start * transaction blocks, even in a 7.3 server with * autocommit off. */ char setQuery[100]; /* note length limit in * sprintf below */ if (conn->next_eo->envName) { const char *val; if ((val = getenv(conn->next_eo->envName))) { if (pg_strcasecmp(val, "default") == 0) sprintf(setQuery, "SET %s = DEFAULT", conn->next_eo->pgName); else sprintf(setQuery, "SET %s = '%.60s'", conn->next_eo->pgName, val); #ifdef CONNECTDEBUG fprintf(stderr, "Use environment variable %s to send %s\n", conn->next_eo->envName, setQuery); #endif if (!PQsendQuery(conn, setQuery)) goto error_return; conn->setenv_state = SETENV_STATE_OPTION_WAIT; } else conn->next_eo++; } else { /* No more options to send, so move on to querying */ conn->setenv_state = SETENV_STATE_QUERY1_SEND; } break; } case SETENV_STATE_CLIENT_ENCODING_WAIT: { if (PQisBusy(conn)) return PGRES_POLLING_READING; res = PQgetResult(conn); if (res) { if (PQresultStatus(res) != PGRES_COMMAND_OK) { PQclear(res); goto error_return; } PQclear(res); /* Keep reading until PQgetResult returns NULL */ } else { /* Query finished, so send the next option */ conn->setenv_state = SETENV_STATE_OPTION_SEND; } break; } case SETENV_STATE_OPTION_WAIT: { if (PQisBusy(conn)) return PGRES_POLLING_READING; res = PQgetResult(conn); if (res) { if (PQresultStatus(res) != PGRES_COMMAND_OK) { PQclear(res); goto error_return; } PQclear(res); /* Keep reading until PQgetResult returns NULL */ } else { /* Query finished, so send the next option */ conn->next_eo++; conn->setenv_state = SETENV_STATE_OPTION_SEND; } break; } case SETENV_STATE_QUERY1_SEND: { /* * Issue query to get information we need. Here we must * use begin/commit in case autocommit is off by default * in a 7.3 server. * * Note: version() exists in all protocol-2.0-supporting * backends. In 7.3 it would be safer to write * pg_catalog.version(), but we can't do that without * causing problems on older versions. */ if (!PQsendQuery(conn, "begin; select version(); end")) goto error_return; conn->setenv_state = SETENV_STATE_QUERY1_WAIT; return PGRES_POLLING_READING; } case SETENV_STATE_QUERY1_WAIT: { if (PQisBusy(conn)) return PGRES_POLLING_READING; res = PQgetResult(conn); if (res) { char *val; if (PQresultStatus(res) == PGRES_COMMAND_OK) { /* ignore begin/commit command results */ PQclear(res); continue; } if (PQresultStatus(res) != PGRES_TUPLES_OK || PQntuples(res) != 1) { PQclear(res); goto error_return; } /* * Extract server version and save as if * ParameterStatus */ val = PQgetvalue(res, 0, 0); if (val && strncmp(val, "PostgreSQL ", 11) == 0) { char *ptr; /* strip off PostgreSQL part */ val += 11; /* * strip off platform part (scribbles on result, * naughty naughty) */ ptr = strchr(val, ' '); if (ptr) *ptr = '\0'; pqSaveParameterStatus(conn, "server_version", val); } PQclear(res); /* Keep reading until PQgetResult returns NULL */ } else { /* Query finished, move to next */ conn->setenv_state = SETENV_STATE_QUERY2_SEND; } break; } case SETENV_STATE_QUERY2_SEND: { const char *query; /* * pg_client_encoding does not exist in pre-7.2 servers. * So we need to be prepared for an error here. Do *not* * start a transaction block, except in 7.3 servers where * we need to prevent autocommit-off from starting a * transaction anyway. */ if (conn->sversion >= 70300 && conn->sversion < 70400) query = "begin; select pg_catalog.pg_client_encoding(); end"; else query = "select pg_client_encoding()"; if (!PQsendQuery(conn, query)) goto error_return; conn->setenv_state = SETENV_STATE_QUERY2_WAIT; return PGRES_POLLING_READING; } case SETENV_STATE_QUERY2_WAIT: { if (PQisBusy(conn)) return PGRES_POLLING_READING; res = PQgetResult(conn); if (res) { const char *val; if (PQresultStatus(res) == PGRES_COMMAND_OK) { /* ignore begin/commit command results */ PQclear(res); continue; } if (PQresultStatus(res) == PGRES_TUPLES_OK && PQntuples(res) == 1) { /* Extract client encoding and save it */ val = PQgetvalue(res, 0, 0); if (val && *val) /* null should not happen, but */ pqSaveParameterStatus(conn, "client_encoding", val); } else { /* * Error: presumably function not available, so * use PGCLIENTENCODING or SQL_ASCII as the * fallback. */ val = getenv("PGCLIENTENCODING"); if (val && *val) pqSaveParameterStatus(conn, "client_encoding", val); else pqSaveParameterStatus(conn, "client_encoding", "SQL_ASCII"); } PQclear(res); /* Keep reading until PQgetResult returns NULL */ } else { /* Query finished, so we're done */ conn->setenv_state = SETENV_STATE_IDLE; return PGRES_POLLING_OK; } break; } default: printfPQExpBuffer(&conn->errorMessage, libpq_gettext("invalid state %c, " "probably indicative of memory corruption\n"), conn->setenv_state); goto error_return; } } /* Unreachable */ error_return: conn->setenv_state = SETENV_STATE_IDLE; return PGRES_POLLING_FAILED; } /* * parseInput: if appropriate, parse input data from backend * until input is exhausted or a stopping state is reached. * Note that this function will NOT attempt to read more data from the backend. */ void pqParseInput2(PGconn *conn) { char id; /* * Loop to parse successive complete messages available in the buffer. */ for (;;) { /* * Quit if in COPY_OUT state: we expect raw data from the server until * PQendcopy is called. Don't try to parse it according to the normal * protocol. (This is bogus. The data lines ought to be part of the * protocol and have identifying leading characters.) */ if (conn->asyncStatus == PGASYNC_COPY_OUT) return; /* * OK to try to read a message type code. */ conn->inCursor = conn->inStart; if (pqGetc(&id, conn)) return; /* * NOTIFY and NOTICE messages can happen in any state besides COPY * OUT; always process them right away. * * Most other messages should only be processed while in BUSY state. * (In particular, in READY state we hold off further parsing until * the application collects the current PGresult.) * * However, if the state is IDLE then we got trouble; we need to deal * with the unexpected message somehow. */ if (id == 'A') { if (getNotify(conn)) return; } else if (id == 'N') { if (pqGetErrorNotice2(conn, false)) return; } else if (conn->asyncStatus != PGASYNC_BUSY) { /* If not IDLE state, just wait ... */ if (conn->asyncStatus != PGASYNC_IDLE) return; /* * Unexpected message in IDLE state; need to recover somehow. * ERROR messages are displayed using the notice processor; * anything else is just dropped on the floor after displaying a * suitable warning notice. (An ERROR is very possibly the * backend telling us why it is about to close the connection, so * we don't want to just discard it...) */ if (id == 'E') { if (pqGetErrorNotice2(conn, false /* treat as notice */ )) return; } else { pqInternalNotice(&conn->noticeHooks, "message type 0x%02x arrived from server while idle", id); /* Discard the unexpected message; good idea?? */ conn->inStart = conn->inEnd; break; } } else { /* * In BUSY state, we can process everything. */ switch (id) { case 'C': /* command complete */ if (pqGets(&conn->workBuffer, conn)) return; if (conn->result == NULL) { conn->result = PQmakeEmptyPGresult(conn, PGRES_COMMAND_OK); if (!conn->result) return; } strncpy(conn->result->cmdStatus, conn->workBuffer.data, CMDSTATUS_LEN); checkXactStatus(conn, conn->workBuffer.data); conn->asyncStatus = PGASYNC_READY; break; case 'E': /* error return */ if (pqGetErrorNotice2(conn, true)) return; conn->asyncStatus = PGASYNC_READY; break; case 'Z': /* backend is ready for new query */ conn->asyncStatus = PGASYNC_IDLE; break; case 'I': /* empty query */ /* read and throw away the closing '\0' */ if (pqGetc(&id, conn)) return; if (id != '\0') pqInternalNotice(&conn->noticeHooks, "unexpected character %c following empty query response (\"I\" message)", id); if (conn->result == NULL) conn->result = PQmakeEmptyPGresult(conn, PGRES_EMPTY_QUERY); conn->asyncStatus = PGASYNC_READY; break; case 'K': /* secret key data from the backend */ /* * This is expected only during backend startup, but it's * just as easy to handle it as part of the main loop. * Save the data and continue processing. */ if (pqGetInt(&(conn->be_pid), 4, conn)) return; if (pqGetInt(&(conn->be_key), 4, conn)) return; break; case 'P': /* synchronous (normal) portal */ if (pqGets(&conn->workBuffer, conn)) return; /* We pretty much ignore this message type... */ break; case 'T': /* row descriptions (start of query results) */ if (conn->result == NULL) { /* First 'T' in a query sequence */ if (getRowDescriptions(conn)) return; } else { /* * A new 'T' message is treated as the start of * another PGresult. (It is not clear that this is * really possible with the current backend.) We stop * parsing until the application accepts the current * result. */ conn->asyncStatus = PGASYNC_READY; return; } break; case 'D': /* ASCII data tuple */ if (conn->result != NULL) { /* Read another tuple of a normal query response */ if (getAnotherTuple(conn, FALSE)) return; } else { pqInternalNotice(&conn->noticeHooks, "server sent data (\"D\" message) without prior row description (\"T\" message)"); /* Discard the unexpected message; good idea?? */ conn->inStart = conn->inEnd; return; } break; case 'B': /* Binary data tuple */ if (conn->result != NULL) { /* Read another tuple of a normal query response */ if (getAnotherTuple(conn, TRUE)) return; } else { pqInternalNotice(&conn->noticeHooks, "server sent binary data (\"B\" message) without prior row description (\"T\" message)"); /* Discard the unexpected message; good idea?? */ conn->inStart = conn->inEnd; return; } break; case 'G': /* Start Copy In */ conn->asyncStatus = PGASYNC_COPY_IN; break; case 'H': /* Start Copy Out */ conn->asyncStatus = PGASYNC_COPY_OUT; break; /* * Don't need to process CopyBothResponse here because it * never arrives from the server during protocol 2.0. */ default: printfPQExpBuffer(&conn->errorMessage, libpq_gettext( "unexpected response from server; first received character was \"%c\"\n"), id); /* build an error result holding the error message */ pqSaveErrorResult(conn); /* Discard the unexpected message; good idea?? */ conn->inStart = conn->inEnd; conn->asyncStatus = PGASYNC_READY; return; } /* switch on protocol character */ } /* Successfully consumed this message */ conn->inStart = conn->inCursor; } } /* * parseInput subroutine to read a 'T' (row descriptions) message. * We build a PGresult structure containing the attribute data. * Returns: 0 if completed message, EOF if not enough data yet. * * Note that if we run out of data, we have to release the partially * constructed PGresult, and rebuild it again next time. Fortunately, * that shouldn't happen often, since 'T' messages usually fit in a packet. */ static int getRowDescriptions(PGconn *conn) { PGresult *result = NULL; int nfields; int i; result = PQmakeEmptyPGresult(conn, PGRES_TUPLES_OK); if (!result) goto failure; /* parseInput already read the 'T' label. */ /* the next two bytes are the number of fields */ if (pqGetInt(&(result->numAttributes), 2, conn)) goto failure; nfields = result->numAttributes; /* allocate space for the attribute descriptors */ if (nfields > 0) { result->attDescs = (PGresAttDesc *) pqResultAlloc(result, nfields * sizeof(PGresAttDesc), TRUE); if (!result->attDescs) goto failure; MemSet(result->attDescs, 0, nfields * sizeof(PGresAttDesc)); } /* get type info */ for (i = 0; i < nfields; i++) { int typid; int typlen; int atttypmod; if (pqGets(&conn->workBuffer, conn) || pqGetInt(&typid, 4, conn) || pqGetInt(&typlen, 2, conn) || pqGetInt(&atttypmod, 4, conn)) goto failure; /* * Since pqGetInt treats 2-byte integers as unsigned, we need to * coerce the result to signed form. */ typlen = (int) ((int16) typlen); result->attDescs[i].name = pqResultStrdup(result, conn->workBuffer.data); if (!result->attDescs[i].name) goto failure; result->attDescs[i].tableid = 0; result->attDescs[i].columnid = 0; result->attDescs[i].format = 0; result->attDescs[i].typid = typid; result->attDescs[i].typlen = typlen; result->attDescs[i].atttypmod = atttypmod; } /* Success! */ conn->result = result; return 0; failure: if (result) PQclear(result); return EOF; } /* * parseInput subroutine to read a 'B' or 'D' (row data) message. * We add another tuple to the existing PGresult structure. * Returns: 0 if completed message, EOF if error or not enough data yet. * * Note that if we run out of data, we have to suspend and reprocess * the message after more data is received. We keep a partially constructed * tuple in conn->curTuple, and avoid reallocating already-allocated storage. */ static int getAnotherTuple(PGconn *conn, bool binary) { PGresult *result = conn->result; int nfields = result->numAttributes; PGresAttValue *tup; /* the backend sends us a bitmap of which attributes are null */ char std_bitmap[64]; /* used unless it doesn't fit */ char *bitmap = std_bitmap; int i; size_t nbytes; /* the number of bytes in bitmap */ char bmap; /* One byte of the bitmap */ int bitmap_index; /* Its index */ int bitcnt; /* number of bits examined in current byte */ int vlen; /* length of the current field value */ result->binary = binary; /* Allocate tuple space if first time for this data message */ if (conn->curTuple == NULL) { conn->curTuple = (PGresAttValue *) pqResultAlloc(result, nfields * sizeof(PGresAttValue), TRUE); if (conn->curTuple == NULL) goto outOfMemory; MemSet(conn->curTuple, 0, nfields * sizeof(PGresAttValue)); /* * If it's binary, fix the column format indicators. We assume the * backend will consistently send either B or D, not a mix. */ if (binary) { for (i = 0; i < nfields; i++) result->attDescs[i].format = 1; } } tup = conn->curTuple; /* Get the null-value bitmap */ nbytes = (nfields + BITS_PER_BYTE - 1) / BITS_PER_BYTE; /* malloc() only for unusually large field counts... */ if (nbytes > sizeof(std_bitmap)) { bitmap = (char *) malloc(nbytes); if (!bitmap) goto outOfMemory; } if (pqGetnchar(bitmap, nbytes, conn)) goto EOFexit; /* Scan the fields */ bitmap_index = 0; bmap = bitmap[bitmap_index]; bitcnt = 0; for (i = 0; i < nfields; i++) { if (!(bmap & 0200)) { /* if the field value is absent, make it a null string */ tup[i].value = result->null_field; tup[i].len = NULL_LEN; } else { /* get the value length (the first four bytes are for length) */ if (pqGetInt(&vlen, 4, conn)) goto EOFexit; if (!binary) vlen = vlen - 4; if (vlen < 0) vlen = 0; if (tup[i].value == NULL) { tup[i].value = (char *) pqResultAlloc(result, vlen + 1, binary); if (tup[i].value == NULL) goto outOfMemory; } tup[i].len = vlen; /* read in the value */ if (vlen > 0) if (pqGetnchar((char *) (tup[i].value), vlen, conn)) goto EOFexit; /* we have to terminate this ourselves */ tup[i].value[vlen] = '\0'; } /* advance the bitmap stuff */ bitcnt++; if (bitcnt == BITS_PER_BYTE) { bitmap_index++; bmap = bitmap[bitmap_index]; bitcnt = 0; } else bmap <<= 1; } /* Success! Store the completed tuple in the result */ if (!pqAddTuple(result, tup)) goto outOfMemory; /* and reset for a new message */ conn->curTuple = NULL; if (bitmap != std_bitmap) free(bitmap); return 0; outOfMemory: /* Replace partially constructed result with an error result */ /* * we do NOT use pqSaveErrorResult() here, because of the likelihood that * there's not enough memory to concatenate messages... */ pqClearAsyncResult(conn); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("out of memory for query result\n")); /* * XXX: if PQmakeEmptyPGresult() fails, there's probably not much we can * do to recover... */ conn->result = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR); conn->asyncStatus = PGASYNC_READY; /* Discard the failed message --- good idea? */ conn->inStart = conn->inEnd; EOFexit: if (bitmap != NULL && bitmap != std_bitmap) free(bitmap); return EOF; } /* * Attempt to read an Error or Notice response message. * This is possible in several places, so we break it out as a subroutine. * Entry: 'E' or 'N' message type has already been consumed. * Exit: returns 0 if successfully consumed message. * returns EOF if not enough data. */ static int pqGetErrorNotice2(PGconn *conn, bool isError) { PGresult *res = NULL; PQExpBufferData workBuf; char *startp; char *splitp; /* * Since the message might be pretty long, we create a temporary * PQExpBuffer rather than using conn->workBuffer. workBuffer is intended * for stuff that is expected to be short. */ initPQExpBuffer(&workBuf); if (pqGets(&workBuf, conn)) goto failure; /* * Make a PGresult to hold the message. We temporarily lie about the * result status, so that PQmakeEmptyPGresult doesn't uselessly copy * conn->errorMessage. */ res = PQmakeEmptyPGresult(conn, PGRES_EMPTY_QUERY); if (!res) goto failure; res->resultStatus = isError ? PGRES_FATAL_ERROR : PGRES_NONFATAL_ERROR; res->errMsg = pqResultStrdup(res, workBuf.data); if (!res->errMsg) goto failure; /* * Break the message into fields. We can't do very much here, but we can * split the severity code off, and remove trailing newlines. Also, we use * the heuristic that the primary message extends only to the first * newline --- anything after that is detail message. (In some cases it'd * be better classed as hint, but we can hardly be expected to guess that * here.) */ while (workBuf.len > 0 && workBuf.data[workBuf.len - 1] == '\n') workBuf.data[--workBuf.len] = '\0'; splitp = strstr(workBuf.data, ": "); if (splitp) { /* what comes before the colon is severity */ *splitp = '\0'; pqSaveMessageField(res, PG_DIAG_SEVERITY, workBuf.data); startp = splitp + 3; } else { /* can't find a colon? oh well... */ startp = workBuf.data; } splitp = strchr(startp, '\n'); if (splitp) { /* what comes before the newline is primary message */ *splitp++ = '\0'; pqSaveMessageField(res, PG_DIAG_MESSAGE_PRIMARY, startp); /* the rest is detail; strip any leading whitespace */ while (*splitp && isspace((unsigned char) *splitp)) splitp++; pqSaveMessageField(res, PG_DIAG_MESSAGE_DETAIL, splitp); } else { /* single-line message, so all primary */ pqSaveMessageField(res, PG_DIAG_MESSAGE_PRIMARY, startp); } /* * Either save error as current async result, or just emit the notice. * Also, if it's an error and we were in a transaction block, assume the * server has now gone to error-in-transaction state. */ if (isError) { pqClearAsyncResult(conn); conn->result = res; resetPQExpBuffer(&conn->errorMessage); appendPQExpBufferStr(&conn->errorMessage, res->errMsg); if (conn->xactStatus == PQTRANS_INTRANS) conn->xactStatus = PQTRANS_INERROR; } else { if (res->noticeHooks.noticeRec != NULL) (*res->noticeHooks.noticeRec) (res->noticeHooks.noticeRecArg, res); PQclear(res); } termPQExpBuffer(&workBuf); return 0; failure: if (res) PQclear(res); termPQExpBuffer(&workBuf); return EOF; } /* * checkXactStatus - attempt to track transaction-block status of server * * This is called each time we receive a command-complete message. By * watching for messages from BEGIN/COMMIT/ROLLBACK commands, we can do * a passable job of tracking the server's xact status. BUT: this does * not work at all on 7.3 servers with AUTOCOMMIT OFF. (Man, was that * feature ever a mistake.) Caveat user. * * The tags known here are all those used as far back as 7.0; is it worth * adding those from even-older servers? */ static void checkXactStatus(PGconn *conn, const char *cmdTag) { if (strcmp(cmdTag, "BEGIN") == 0) conn->xactStatus = PQTRANS_INTRANS; else if (strcmp(cmdTag, "COMMIT") == 0) conn->xactStatus = PQTRANS_IDLE; else if (strcmp(cmdTag, "ROLLBACK") == 0) conn->xactStatus = PQTRANS_IDLE; else if (strcmp(cmdTag, "START TRANSACTION") == 0) /* 7.3 only */ conn->xactStatus = PQTRANS_INTRANS; /* * Normally we get into INERROR state by detecting an Error message. * However, if we see one of these tags then we know for sure the server * is in abort state ... */ else if (strcmp(cmdTag, "*ABORT STATE*") == 0) /* pre-7.3 only */ conn->xactStatus = PQTRANS_INERROR; } /* * Attempt to read a Notify response message. * This is possible in several places, so we break it out as a subroutine. * Entry: 'A' message type and length have already been consumed. * Exit: returns 0 if successfully consumed Notify message. * returns EOF if not enough data. */ static int getNotify(PGconn *conn) { int be_pid; int nmlen; PGnotify *newNotify; if (pqGetInt(&be_pid, 4, conn)) return EOF; if (pqGets(&conn->workBuffer, conn)) return EOF; /* * Store the relation name right after the PQnotify structure so it can * all be freed at once. We don't use NAMEDATALEN because we don't want * to tie this interface to a specific server name length. */ nmlen = strlen(conn->workBuffer.data); newNotify = (PGnotify *) malloc(sizeof(PGnotify) + nmlen + 1); if (newNotify) { newNotify->relname = (char *) newNotify + sizeof(PGnotify); strcpy(newNotify->relname, conn->workBuffer.data); /* fake up an empty-string extra field */ newNotify->extra = newNotify->relname + nmlen; newNotify->be_pid = be_pid; newNotify->next = NULL; if (conn->notifyTail) conn->notifyTail->next = newNotify; else conn->notifyHead = newNotify; conn->notifyTail = newNotify; } return 0; } /* * PQgetCopyData - read a row of data from the backend during COPY OUT * * If successful, sets *buffer to point to a malloc'd row of data, and * returns row length (always > 0) as result. * Returns 0 if no row available yet (only possible if async is true), * -1 if end of copy (consult PQgetResult), or -2 if error (consult * PQerrorMessage). */ int pqGetCopyData2(PGconn *conn, char **buffer, int async) { bool found; int msgLength; for (;;) { /* * Do we have a complete line of data? */ conn->inCursor = conn->inStart; found = false; while (conn->inCursor < conn->inEnd) { char c = conn->inBuffer[conn->inCursor++]; if (c == '\n') { found = true; break; } } if (!found) goto nodata; msgLength = conn->inCursor - conn->inStart; /* * If it's the end-of-data marker, consume it, exit COPY_OUT mode, and * let caller read status with PQgetResult(). */ if (msgLength == 3 && strncmp(&conn->inBuffer[conn->inStart], "\\.\n", 3) == 0) { conn->inStart = conn->inCursor; conn->asyncStatus = PGASYNC_BUSY; return -1; } /* * Pass the line back to the caller. */ *buffer = (char *) malloc(msgLength + 1); if (*buffer == NULL) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("out of memory\n")); return -2; } memcpy(*buffer, &conn->inBuffer[conn->inStart], msgLength); (*buffer)[msgLength] = '\0'; /* Add terminating null */ /* Mark message consumed */ conn->inStart = conn->inCursor; return msgLength; nodata: /* Don't block if async read requested */ if (async) return 0; /* Need to load more data */ if (pqWait(TRUE, FALSE, conn) || pqReadData(conn) < 0) return -2; } } /* * PQgetline - gets a newline-terminated string from the backend. * * See fe-exec.c for documentation. */ int pqGetline2(PGconn *conn, char *s, int maxlen) { int result = 1; /* return value if buffer overflows */ if (conn->sock < 0) { *s = '\0'; return EOF; } /* * Since this is a purely synchronous routine, we don't bother to maintain * conn->inCursor; there is no need to back up. */ while (maxlen > 1) { if (conn->inStart < conn->inEnd) { char c = conn->inBuffer[conn->inStart++]; if (c == '\n') { result = 0; /* success exit */ break; } *s++ = c; maxlen--; } else { /* need to load more data */ if (pqWait(TRUE, FALSE, conn) || pqReadData(conn) < 0) { result = EOF; break; } } } *s = '\0'; return result; } /* * PQgetlineAsync - gets a COPY data row without blocking. * * See fe-exec.c for documentation. */ int pqGetlineAsync2(PGconn *conn, char *buffer, int bufsize) { int avail; if (conn->asyncStatus != PGASYNC_COPY_OUT) return -1; /* we are not doing a copy... */ /* * Move data from libpq's buffer to the caller's. We want to accept data * only in units of whole lines, not partial lines. This ensures that we * can recognize the terminator line "\\.\n". (Otherwise, if it happened * to cross a packet/buffer boundary, we might hand the first one or two * characters off to the caller, which we shouldn't.) */ conn->inCursor = conn->inStart; avail = bufsize; while (avail > 0 && conn->inCursor < conn->inEnd) { char c = conn->inBuffer[conn->inCursor++]; *buffer++ = c; --avail; if (c == '\n') { /* Got a complete line; mark the data removed from libpq */ conn->inStart = conn->inCursor; /* Is it the endmarker line? */ if (bufsize - avail == 3 && buffer[-3] == '\\' && buffer[-2] == '.') return -1; /* No, return the data line to the caller */ return bufsize - avail; } } /* * We don't have a complete line. We'd prefer to leave it in libpq's * buffer until the rest arrives, but there is a special case: what if the * line is longer than the buffer the caller is offering us? In that case * we'd better hand over a partial line, else we'd get into an infinite * loop. Do this in a way that ensures we can't misrecognize a terminator * line later: leave last 3 characters in libpq buffer. */ if (avail == 0 && bufsize > 3) { conn->inStart = conn->inCursor - 3; return bufsize - 3; } return 0; } /* * PQendcopy * * See fe-exec.c for documentation. */ int pqEndcopy2(PGconn *conn) { PGresult *result; if (conn->asyncStatus != PGASYNC_COPY_IN && conn->asyncStatus != PGASYNC_COPY_OUT) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("no COPY in progress\n")); return 1; } /* * make sure no data is waiting to be sent, abort if we are non-blocking * and the flush fails */ if (pqFlush(conn) && pqIsnonblocking(conn)) return 1; /* non blocking connections may have to abort at this point. */ if (pqIsnonblocking(conn) && PQisBusy(conn)) return 1; /* Return to active duty */ conn->asyncStatus = PGASYNC_BUSY; resetPQExpBuffer(&conn->errorMessage); /* Wait for the completion response */ result = PQgetResult(conn); /* Expecting a successful result */ if (result && result->resultStatus == PGRES_COMMAND_OK) { PQclear(result); return 0; } /* * Trouble. For backwards-compatibility reasons, we issue the error * message as if it were a notice (would be nice to get rid of this * silliness, but too many apps probably don't handle errors from * PQendcopy reasonably). Note that the app can still obtain the error * status from the PGconn object. */ if (conn->errorMessage.len > 0) { /* We have to strip the trailing newline ... pain in neck... */ char svLast = conn->errorMessage.data[conn->errorMessage.len - 1]; if (svLast == '\n') conn->errorMessage.data[conn->errorMessage.len - 1] = '\0'; pqInternalNotice(&conn->noticeHooks, "%s", conn->errorMessage.data); conn->errorMessage.data[conn->errorMessage.len - 1] = svLast; } PQclear(result); /* * The worst case is that we've lost sync with the backend entirely due to * application screwup of the copy in/out protocol. To recover, reset the * connection (talk about using a sledgehammer...) */ pqInternalNotice(&conn->noticeHooks, "lost synchronization with server, resetting connection"); /* * Users doing non-blocking connections need to handle the reset * themselves, they'll need to check the connection status if we return an * error. */ if (pqIsnonblocking(conn)) PQresetStart(conn); else PQreset(conn); return 1; } /* * PQfn - Send a function call to the POSTGRES backend. * * See fe-exec.c for documentation. */ PGresult * pqFunctionCall2(PGconn *conn, Oid fnid, int *result_buf, int *actual_result_len, int result_is_int, const PQArgBlock *args, int nargs) { bool needInput = false; ExecStatusType status = PGRES_FATAL_ERROR; char id; int i; /* PQfn already validated connection state */ if (pqPutMsgStart('F', false, conn) < 0 || /* function call msg */ pqPuts(" ", conn) < 0 || /* dummy string */ pqPutInt(fnid, 4, conn) != 0 || /* function id */ pqPutInt(nargs, 4, conn) != 0) /* # of args */ { pqHandleSendFailure(conn); return NULL; } for (i = 0; i < nargs; ++i) { /* len.int4 + contents */ if (pqPutInt(args[i].len, 4, conn)) { pqHandleSendFailure(conn); return NULL; } if (args[i].isint) { if (pqPutInt(args[i].u.integer, 4, conn)) { pqHandleSendFailure(conn); return NULL; } } else { if (pqPutnchar((char *) args[i].u.ptr, args[i].len, conn)) { pqHandleSendFailure(conn); return NULL; } } } if (pqPutMsgEnd(conn) < 0 || pqFlush(conn)) { pqHandleSendFailure(conn); return NULL; } for (;;) { if (needInput) { /* Wait for some data to arrive (or for the channel to close) */ if (pqWait(TRUE, FALSE, conn) || pqReadData(conn) < 0) break; } /* * Scan the message. If we run out of data, loop around to try again. */ conn->inCursor = conn->inStart; needInput = true; if (pqGetc(&id, conn)) continue; /* * We should see V or E response to the command, but might get N * and/or A notices first. We also need to swallow the final Z before * returning. */ switch (id) { case 'V': /* function result */ if (pqGetc(&id, conn)) continue; if (id == 'G') { /* function returned nonempty value */ if (pqGetInt(actual_result_len, 4, conn)) continue; if (result_is_int) { if (pqGetInt(result_buf, 4, conn)) continue; } else { if (pqGetnchar((char *) result_buf, *actual_result_len, conn)) continue; } if (pqGetc(&id, conn)) /* get the last '0' */ continue; } if (id == '0') { /* correctly finished function result message */ status = PGRES_COMMAND_OK; } else { /* The backend violates the protocol. */ printfPQExpBuffer(&conn->errorMessage, libpq_gettext("protocol error: id=0x%x\n"), id); pqSaveErrorResult(conn); conn->inStart = conn->inCursor; return pqPrepareAsyncResult(conn); } break; case 'E': /* error return */ if (pqGetErrorNotice2(conn, true)) continue; status = PGRES_FATAL_ERROR; break; case 'A': /* notify message */ /* handle notify and go back to processing return values */ if (getNotify(conn)) continue; break; case 'N': /* notice */ /* handle notice and go back to processing return values */ if (pqGetErrorNotice2(conn, false)) continue; break; case 'Z': /* backend is ready for new query */ /* consume the message and exit */ conn->inStart = conn->inCursor; /* if we saved a result object (probably an error), use it */ if (conn->result) return pqPrepareAsyncResult(conn); return PQmakeEmptyPGresult(conn, status); default: /* The backend violates the protocol. */ printfPQExpBuffer(&conn->errorMessage, libpq_gettext("protocol error: id=0x%x\n"), id); pqSaveErrorResult(conn); conn->inStart = conn->inCursor; return pqPrepareAsyncResult(conn); } /* Completed this message, keep going */ conn->inStart = conn->inCursor; needInput = false; } /* * We fall out of the loop only upon failing to read data. * conn->errorMessage has been set by pqWait or pqReadData. We want to * append it to any already-received error message. */ pqSaveErrorResult(conn); return pqPrepareAsyncResult(conn); } /* * Construct startup packet * * Returns a malloc'd packet buffer, or NULL if out of memory */ char * pqBuildStartupPacket2(PGconn *conn, int *packetlen, const PQEnvironmentOption *options) { StartupPacket *startpacket; *packetlen = sizeof(StartupPacket); startpacket = (StartupPacket *) malloc(sizeof(StartupPacket)); if (!startpacket) return NULL; MemSet(startpacket, 0, sizeof(StartupPacket)); startpacket->protoVersion = htonl(conn->pversion); strncpy(startpacket->user, conn->pguser, SM_USER); strncpy(startpacket->database, conn->dbName, SM_DATABASE); strncpy(startpacket->tty, conn->pgtty, SM_TTY); if (conn->pgoptions) strncpy(startpacket->options, conn->pgoptions, SM_OPTIONS); return (char *) startpacket; } RPostgreSQL/src/libpq/Makefile.global.win320000644000176000001440000004542411663173071020203 0ustar ripleyusers# -*-makefile-*- # src/Makefile.global.in #------------------------------------------------------------------------------ # All PostgreSQL makefiles include this file and use the variables it sets, # which in turn are put here by the configure script. There is no need for # users to edit this file -- if it turns out to be necessary then that's a # bug. # # A makefile that includes this file needs to set the variable `subdir' to # the relative path from the top to itself and `top_builddir' to the relative # path from itself to the top before including this file. (The "top" is the # parent directory of the directory this file is in.) #------------------------------------------------------------------------------ ########################################################################## # # Meta configuration standard_targets = all install installdirs uninstall distprep clean distclean maintainer-clean coverage check installcheck maintainer-check # these targets should recurse even into subdirectories not being built: standard_always_targets = distprep clean distclean maintainer-clean .PHONY: $(standard_targets) install-strip html man installcheck-parallel # make `all' the default target all: # Delete target files if the command fails after it has # started to update the file. .DELETE_ON_ERROR: # PostgreSQL version number VERSION = 9.1.1 MAJORVERSION = 9.1 # Support for VPATH builds vpath_build = no abs_top_srcdir = /cygdrive/c/R/postgresql-9.1.1 ifneq ($(vpath_build),yes) top_srcdir = $(top_builddir) srcdir = . else # vpath_build = yes top_srcdir = $(abs_top_srcdir) srcdir = $(top_srcdir)/$(subdir) endif vpathsearch = `for f in $(addsuffix /$(1),$(subst :, ,. $(VPATH))); do test -r $$f && echo $$f && break; done` # Saved arguments from configure configure_args = '--without-zlib' ########################################################################## # # Installation directories # # These are set by the equivalent --xxxdir configure options. We # append "postgresql" to some of them, if the string does not already # contain "pgsql" or "postgres", in order to avoid directory clutter. # # In a PGXS build, we cannot use the values inserted into Makefile.global # by configure, since the installation tree may have been relocated. # Instead get the path values from pg_config. ifndef PGXS # Note that prefix, exec_prefix, and datarootdir aren't defined in a PGXS build; # makefiles may only use the derived variables such as bindir. prefix := /usr/local/pgsql exec_prefix := ${prefix} datarootdir := ${prefix}/share bindir := ${exec_prefix}/bin datadir := ${datarootdir} ifeq "$(findstring pgsql, $(datadir))" "" ifeq "$(findstring postgres, $(datadir))" "" override datadir := $(datadir)/postgresql endif endif sysconfdir := ${prefix}/etc ifeq "$(findstring pgsql, $(sysconfdir))" "" ifeq "$(findstring postgres, $(sysconfdir))" "" override sysconfdir := $(sysconfdir)/postgresql endif endif libdir := ${exec_prefix}/lib pkglibdir = $(libdir) ifeq "$(findstring pgsql, $(pkglibdir))" "" ifeq "$(findstring postgres, $(pkglibdir))" "" override pkglibdir := $(pkglibdir)/postgresql endif endif includedir := ${prefix}/include pkgincludedir = $(includedir) ifeq "$(findstring pgsql, $(pkgincludedir))" "" ifeq "$(findstring postgres, $(pkgincludedir))" "" override pkgincludedir := $(pkgincludedir)/postgresql endif endif mandir := ${datarootdir}/man docdir := ${datarootdir}/doc/${PACKAGE_TARNAME} ifeq "$(findstring pgsql, $(docdir))" "" ifeq "$(findstring postgres, $(docdir))" "" override docdir := $(docdir)/postgresql endif endif htmldir := ${docdir} localedir := ${datarootdir}/locale else # PGXS case # Extension makefiles should set PG_CONFIG, but older ones might not ifndef PG_CONFIG PG_CONFIG = pg_config endif bindir := $(shell $(PG_CONFIG) --bindir) datadir := $(shell $(PG_CONFIG) --sharedir) sysconfdir := $(shell $(PG_CONFIG) --sysconfdir) libdir := $(shell $(PG_CONFIG) --libdir) pkglibdir := $(shell $(PG_CONFIG) --pkglibdir) includedir := $(shell $(PG_CONFIG) --includedir) pkgincludedir := $(shell $(PG_CONFIG) --pkgincludedir) mandir := $(shell $(PG_CONFIG) --mandir) docdir := $(shell $(PG_CONFIG) --docdir) localedir := $(shell $(PG_CONFIG) --localedir) endif # PGXS # These derived path variables aren't separately configurable. includedir_server = $(pkgincludedir)/server includedir_internal = $(pkgincludedir)/internal pgxsdir = $(pkglibdir)/pgxs ########################################################################## # # Features # # Records the choice of the various --enable-xxx and --with-xxx options. with_perl = no with_python = no with_tcl = no with_openssl = no with_ossp_uuid = no with_selinux = no with_libxml = no with_libxslt = no with_system_tzdata = with_zlib = no enable_shared = yes enable_rpath = yes enable_nls = no enable_debug = no enable_dtrace = no enable_coverage = no enable_thread_safety = yes python_includespec = python_libdir = python_libspec = python_additional_libs = python_configdir = python_majorversion = python_version = krb_srvtab = TCLSH = TCL_LIB_FILE = TCL_LIBS = TCL_LIB_SPEC = TCL_INCLUDE_SPEC = TCL_SHARED_BUILD = TCL_SHLIB_LD_LIBS = PTHREAD_CFLAGS = PTHREAD_LIBS = ########################################################################## # # Programs and flags # Compilers CPP = gcc -E CPPFLAGS = -I./wininclude -DEXEC_BACKEND ifdef PGXS override CPPFLAGS := -I$(includedir_server) -I$(includedir_internal) $(CPPFLAGS) else # not PGXS ifdef VPATH endif endif # not PGXS CC = gcc GCC = yes SUN_STUDIO_CC = no CFLAGS = -O2 -Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement -Wendif-labels -Wformat-security -fno-strict-aliasing -fwrapv # Kind-of compilers BISON = /bin/bison BISONFLAGS = $(YFLAGS) FLEX = /bin/flex FLEXFLAGS = $(LFLAGS) DTRACE = DTRACEFLAGS = ZIC = # Linking AR = ar DLLTOOL = dlltool DLLWRAP = dllwrap LIBS = -lm LDAP_LIBS_FE = LDAP_LIBS_BE = OSSP_UUID_LIBS = LD = c:/mingw/mingw32/bin/ld.exe with_gnu_ld = yes ld_R_works = # We want -L for libpgport.a to be first in LDFLAGS. We also need LDFLAGS # to be a "recursively expanded" variable, else adjustments to rpathdir # don't work right. So we must NOT do LDFLAGS := something, meaning this has # to be done first and elsewhere we must only do LDFLAGS += something. ifdef PGXS LDFLAGS = -L$(libdir) else LDFLAGS = -L$(top_builddir)/src/port endif LDFLAGS += -Wl,--allow-multiple-definition -Wl,--as-needed LDFLAGS_EX = # LDFLAGS_SL might have already been assigned by calling makefile LDFLAGS_SL += LDREL = -r LDOUT = -o RANLIB = ranlib WINDRES = windres X = .exe # Perl ifneq (/bin/perl,) # quoted to protect pathname with spaces PERL = '/bin/perl' else PERL = $(missing) perl endif perl_archlibexp = perl_privlibexp = perl_useshrplib = perl_embed_ldflags = # Miscellaneous AWK = gawk LN_S = cp -p MSGFMT = MSGMERGE = PYTHON = TAR = /bin/tar XGETTEXT = GZIP = gzip BZIP2 = bzip2 # Installation. INSTALL = $(SHELL) $(top_srcdir)/config/install-sh -c INSTALL_SCRIPT_MODE = 755 INSTALL_DATA_MODE = 644 INSTALL_PROGRAM = $(INSTALL_PROGRAM_ENV) $(INSTALL) $(INSTALL_STRIP_FLAG) INSTALL_SCRIPT = $(INSTALL) -m $(INSTALL_SCRIPT_MODE) INSTALL_DATA = $(INSTALL) -m $(INSTALL_DATA_MODE) INSTALL_STLIB = $(INSTALL_STLIB_ENV) $(INSTALL_DATA) $(INSTALL_STRIP_FLAG) INSTALL_SHLIB = $(INSTALL_SHLIB_ENV) $(INSTALL) $(INSTALL_SHLIB_OPTS) $(INSTALL_STRIP_FLAG) # Override in Makefile.port if necessary INSTALL_SHLIB_OPTS = -m 755 MKDIR_P = /bin/mkdir -p missing = $(SHELL) $(top_srcdir)/config/missing STRIP = strip STRIP_STATIC_LIB = strip -x STRIP_SHARED_LIB = strip --strip-unneeded # Documentation have_docbook = no COLLATEINDEX = DOCBOOKSTYLE = JADE = NSGMLS = OSX = XSLTPROC = # Code coverage GCOV = LCOV = GENHTML = ifeq ($(enable_coverage),yes) # ccache loses .gcno files export CCACHE_DISABLE = 1 endif # Feature settings DEF_PGPORT = 5432 WANTED_LANGUAGES = ########################################################################## # # Additional platform-specific settings # # Name of the "template" PORTNAME= win32 build_os = mingw32 host_tuple = i686-pc-mingw32 host_os = mingw32 host_cpu = i686 # Make HAVE_IPV6 available for initdb script creation HAVE_IPV6= yes # The HP-UX port makefile, for one, needs access to this symbol HAVE_POSIX_SIGNALS= # This is mainly for use on FreeBSD, where we have both a.out and elf # systems now. May be applicable to other systems to? ELF_SYSTEM= # Backend stack size limit has to be hard-wired on Windows (it's in bytes) WIN32_STACK_RLIMIT=4194304 # Set if we have a working win32 crashdump header have_win32_dbghelp = no # Pull in platform-specific magic include Makefile.port # Set up rpath if enabled. By default it will point to our libdir, # but individual Makefiles can force other rpath paths if needed. rpathdir = $(libdir) ifeq ($(enable_rpath), yes) LDFLAGS += $(rpath) endif ########################################################################## # # Some variables needed to find some client interfaces ifdef PGXS # some contribs assumes headers and libs are in the source tree... libpq_srcdir = $(includedir) libpq_builddir = $(libdir) else libpq_srcdir = $(top_srcdir)/src/interfaces/libpq libpq_builddir = $(top_builddir)/src/interfaces/libpq endif # This macro is for use by libraries linking to libpq. (Because libpgport # isn't created with the same link flags as libpq, it can't be used.) libpq = -L$(libpq_builddir) -lpq # If doing static linking, shared library dependency info isn't available, # so add in the libraries that libpq depends on. ifeq ($(enable_shared), no) libpq += $(filter -lintl -lssl -lcrypto -lkrb5 -lcrypt, $(LIBS)) \ $(LDAP_LIBS_FE) $(PTHREAD_LIBS) endif # This macro is for use by client executables (not libraries) that use libpq. # We force clients to pull symbols from the non-shared library libpgport # rather than pulling some libpgport symbols from libpq just because # libpq uses those functions too. This makes applications less # dependent on changes in libpq's usage of pgport. To do this we link to # pgport before libpq. This does cause duplicate -lpgport's to appear # on client link lines. ifdef PGXS libpq_pgport = -L$(libdir) -lpgport $(libpq) else libpq_pgport = -L$(top_builddir)/src/port -lpgport $(libpq) endif submake-libpq: $(MAKE) -C $(libpq_builddir) all submake-libpgport: $(MAKE) -C $(top_builddir)/src/port all .PHONY: submake-libpq submake-libpgport ########################################################################## # # Testing support PL_TESTDB = pl_regression CONTRIB_TESTDB = contrib_regression ifdef NO_LOCALE NOLOCALE += --no-locale endif pg_regress_locale_flags = $(if $(ENCODING),--encoding=$(ENCODING)) $(NOLOCALE) pg_regress_check = $(top_builddir)/src/test/regress/pg_regress --inputdir=$(srcdir) --temp-install=./tmp_check --top-builddir=$(top_builddir) $(pg_regress_locale_flags) pg_regress_installcheck = $(top_builddir)/src/test/regress/pg_regress --inputdir=$(srcdir) --psqldir='$(PSQLDIR)' $(pg_regress_locale_flags) pg_regress_clean_files = results/ regression.diffs regression.out tmp_check/ log/ ########################################################################## # # Customization # # This includes your local customizations if Makefile.custom exists # in the source directory. This file doesn't exist in the original # distribution so that it doesn't get overwritten when you upgrade. # # NOTE: Makefile.custom is from the pre-Autoconf days of PostgreSQL. # You are liable to shoot yourself in the foot if you use it without # knowing exactly what you're doing. The preferred (and more # reliable) method is to communicate what you want to do to the # configure script, and leave the makefiles alone. -include $(top_srcdir)/src/Makefile.custom ifneq ($(CUSTOM_INSTALL),) INSTALL= $(CUSTOM_INSTALL) endif ifneq ($(CUSTOM_CC),) CC= $(CUSTOM_CC) endif ifneq ($(CUSTOM_COPT),) COPT= $(CUSTOM_COPT) endif ifdef COPT CFLAGS += $(COPT) LDFLAGS += $(COPT) endif ifdef PROFILE CFLAGS += $(PROFILE) LDFLAGS += $(PROFILE) endif ########################################################################## # # substitute implementations of C library routines (see src/port/) # note we already included -L.../src/port in LDFLAGS above LIBOBJS = ${LIBOBJDIR}fseeko$U.o ${LIBOBJDIR}crypt$U.o ${LIBOBJDIR}erand48$U.o ${LIBOBJDIR}getrusage$U.o ${LIBOBJDIR}inet_aton$U.o ${LIBOBJDIR}random$U.o ${LIBOBJDIR}srandom$U.o ${LIBOBJDIR}strlcat$U.o ${LIBOBJDIR}strlcpy$U.o ${LIBOBJDIR}getaddrinfo$U.o ${LIBOBJDIR}getopt$U.o ${LIBOBJDIR}getopt_long$U.o ${LIBOBJDIR}kill$U.o ${LIBOBJDIR}open$U.o ${LIBOBJDIR}win32env$U.o ${LIBOBJDIR}win32error$U.o ${LIBOBJDIR}win32setlocale$U.o ${LIBOBJDIR}snprintf$U.o LIBS := -lpgport $(LIBS) # to make ws2_32.lib the last library, and always link with shfolder, # so SHGetFolderName isn't picked up from shell32.dll ifeq ($(PORTNAME),win32) LIBS += -lws2_32 -lshfolder endif # Not really standard libc functions, used by the backend. TAS = ########################################################################## # # Global targets and rules %.i: %.c $(CPP) $(CPPFLAGS) -o $@ $< %.gz: % $(GZIP) --best -c $< >$@ %.bz2: % $(BZIP2) -c $< >$@ ifndef PGXS # Remake Makefile.global from Makefile.global.in if the latter # changed. In order to trigger this rule, the including file must # write `include $(top_builddir)/src/Makefile.global', not some # shortcut thereof. $(top_builddir)/src/Makefile.global: $(top_srcdir)/src/Makefile.global.in $(top_builddir)/config.status cd $(top_builddir) && ./config.status src/Makefile.global # Remake pg_config.h from pg_config.h.in if the latter changed. # config.status will not change the timestamp on pg_config.h if it # doesn't change, so as to avoid recompiling the entire tree # unnecessarily. Therefore we make config.status update a timestamp file # stamp-h everytime it runs, so that we don't trigger this rule everytime. # (We do trigger the null rule for stamp-h to pg_config.h everytime; so it's # important for that rule to be null!) # # Of course you need to turn on dependency tracking to get any # dependencies on pg_config.h. $(top_builddir)/src/include/pg_config.h: $(top_builddir)/src/include/stamp-h $(top_builddir)/src/include/stamp-h: $(top_srcdir)/src/include/pg_config.h.in $(top_builddir)/config.status cd $(top_builddir) && ./config.status src/include/pg_config.h # Also remake ecpg_config.h from ecpg_config.h.in if the latter changed, same # logic as above. $(top_builddir)/src/interfaces/ecpg/include/ecpg_config.h: $(top_builddir)/src/interfaces/ecpg/include/stamp-h $(top_builddir)/src/interfaces/ecpg/include/stamp-h: $(top_builddir)/src/interfaces/ecpg/include/ecpg_config.h.in $(top_builddir)/config.status cd $(top_builddir) && ./config.status src/interfaces/ecpg/include/ecpg_config.h # When configure changes, rerun configure with the same options as # last time. To change configure, you need to run autoconf manually. $(top_builddir)/config.status: $(top_srcdir)/configure cd $(top_builddir) && ./config.status --recheck endif # not PGXS install-strip: @$(MAKE) INSTALL_PROGRAM_ENV="STRIPPROG='$(STRIP)'" \ INSTALL_STLIB_ENV="STRIPPROG='$(STRIP_STATIC_LIB)'" \ INSTALL_SHLIB_ENV="STRIPPROG='$(STRIP_SHARED_LIB)'" \ INSTALL_STRIP_FLAG=-s \ install ########################################################################## # # Automatic dependency generation # ------------------------------- # When we configure with --enable-depend then we override the default # compilation rule with the magic below. While or after creating the # actual output file we also create a dependency list for the .c file. # Next time we invoke make we will have top-notch information about # whether this file needs to be updated. The dependency files are kept # in the .deps subdirectory of each directory. autodepend = ifeq ($(autodepend), yes) ifndef COMPILE.c COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) -c endif DEPDIR = .deps ifeq ($(GCC), yes) # GCC allows us to create object and dependency file in one invocation. %.o : %.c @if test ! -d $(DEPDIR); then mkdir -p $(DEPDIR); fi $(COMPILE.c) -o $@ $< -MMD -MP -MF $(DEPDIR)/$(*F).Po endif # GCC # Include all the dependency files generated for the current # directory. List /dev/null as dummy because if the wildcard expands # to nothing then make would complain. -include $(wildcard $(DEPDIR)/*.Po) /dev/null # hook for clean-up clean distclean maintainer-clean: clean-deps .PHONY: clean-deps clean-deps: @rm -rf $(DEPDIR) # When in automatic dependency mode, never delete any intermediate # files automatically. Otherwise, the following could happen: When # starting from a clean source tree, the first build would delete the # intermediate file, but also create the dependency file, which # mentions the intermediate file, thus making it non-intermediate. # The second build will then need to rebuild the now non-intermediate # missing file. So the second build will do work even though nothing # had changed. One place where this happens is the .c -> .o -> .so # chain for some contrib modules. .SECONDARY: endif # autodepend ########################################################################## # # Native language support ifeq ($(enable_nls), yes) ifneq (,$(wildcard $(srcdir)/nls.mk)) include $(top_srcdir)/src/nls-global.mk endif # nls.mk endif # enable_nls ########################################################################## # # Coverage # Explanation of involved files: # foo.c source file # foo.o object file # foo.gcno gcov graph (a.k.a. "notes") file, created at compile time # (by gcc -ftest-coverage) # foo.gcda gcov data file, created when the program is run (for # programs compiled with gcc -fprofile-arcs) # foo.c.gcov gcov output file with coverage information, created by # gcov from foo.gcda (by "make coverage") # foo.c.gcov.out stdout captured when foo.c.gcov is created, mildly # interesting # lcov.info lcov tracefile, built from gcda files in one directory, # later collected by "make coverage-html" ifeq ($(enable_coverage), yes) # There is a strange interaction between lcov and existing .gcov # output files. Hence the rm command and the ordering dependency. gcda_files := $(wildcard *.gcda) lcov.info: $(gcda_files) rm -f *.gcov $(if $^,$(LCOV) -d . -c -o $@ $(LCOVFLAGS)) %.c.gcov: %.gcda | lcov.info $(GCOV) -b -f -p -o . $(GCOVFLAGS) $*.c >$*.c.gcov.out coverage: $(gcda_files:.gcda=.c.gcov) lcov.info .PHONY: coverage-html coverage-html: coverage rm -rf coverage mkdir coverage $(GENHTML) --show-details --legend --output-directory=coverage --title=PostgreSQL --num-spaces=4 --prefix=$(abs_top_srcdir) `find . -name lcov.info -print` # hook for clean-up clean distclean maintainer-clean: clean-coverage .PHONY: clean-coverage clean-coverage: rm -rf coverage rm -f *.gcda *.gcno lcov.info *.gcov *.gcov.out # User-callable target to reset counts between test runs coverage-clean: rm -f `find . -name '*.gcda' -print` endif # enable_coverage RPostgreSQL/src/libpq/fe-auth.h0000644000176000001440000000120312124517222016021 0ustar ripleyusers/*------------------------------------------------------------------------- * * fe-auth.h * * Definitions for network authentication routines * * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/interfaces/libpq/fe-auth.h * *------------------------------------------------------------------------- */ #ifndef FE_AUTH_H #define FE_AUTH_H #include "libpq-fe.h" #include "libpq-int.h" extern int pg_fe_sendauth(AuthRequest areq, PGconn *conn); extern char *pg_fe_getauthname(PQExpBuffer errorMessage); #endif /* FE_AUTH_H */ RPostgreSQL/src/libpq/mb/0000755000176000001440000000000012124517222014721 5ustar ripleyusersRPostgreSQL/src/libpq/mb/pg_wchar.h0000644000176000001440000003743612124517222016701 0ustar ripleyusers/*------------------------------------------------------------------------- * * pg_wchar.h * multibyte-character support * * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/mb/pg_wchar.h * * NOTES * This is used both by the backend and by libpq, but should not be * included by libpq client programs. In particular, a libpq client * should not assume that the encoding IDs used by the version of libpq * it's linked to match up with the IDs declared here. * *------------------------------------------------------------------------- */ #ifndef PG_WCHAR_H #define PG_WCHAR_H /* * The pg_wchar type */ typedef unsigned int pg_wchar; /* * various definitions for EUC */ #define SS2 0x8e /* single shift 2 (JIS0201) */ #define SS3 0x8f /* single shift 3 (JIS0212) */ /* * SJIS validation macros */ #define ISSJISHEAD(c) (((c) >= 0x81 && (c) <= 0x9f) || ((c) >= 0xe0 && (c) <= 0xfc)) #define ISSJISTAIL(c) (((c) >= 0x40 && (c) <= 0x7e) || ((c) >= 0x80 && (c) <= 0xfc)) /* * Leading byte types or leading prefix byte for MULE internal code. * See http://www.xemacs.org for more details. (there is a doc titled * "XEmacs Internals Manual", "MULE Character Sets and Encodings" * section.) */ /* * Is a leading byte for "official" single byte encodings? */ #define IS_LC1(c) ((unsigned char)(c) >= 0x81 && (unsigned char)(c) <= 0x8d) /* * Is a prefix byte for "private" single byte encodings? */ #define IS_LCPRV1(c) ((unsigned char)(c) == 0x9a || (unsigned char)(c) == 0x9b) /* * Is a leading byte for "official" multibyte encodings? */ #define IS_LC2(c) ((unsigned char)(c) >= 0x90 && (unsigned char)(c) <= 0x99) /* * Is a prefix byte for "private" multibyte encodings? */ #define IS_LCPRV2(c) ((unsigned char)(c) == 0x9c || (unsigned char)(c) == 0x9d) /*---------------------------------------------------- * leading characters *---------------------------------------------------- */ /* * Official single byte encodings (0x81-0x8e) */ #define LC_ISO8859_1 0x81 /* ISO8859 Latin 1 */ #define LC_ISO8859_2 0x82 /* ISO8859 Latin 2 */ #define LC_ISO8859_3 0x83 /* ISO8859 Latin 3 */ #define LC_ISO8859_4 0x84 /* ISO8859 Latin 4 */ #define LC_TIS620 0x85 /* Thai (not supported yet) */ #define LC_ISO8859_7 0x86 /* Greek (not supported yet) */ #define LC_ISO8859_6 0x87 /* Arabic (not supported yet) */ #define LC_ISO8859_8 0x88 /* Hebrew (not supported yet) */ #define LC_JISX0201K 0x89 /* Japanese 1 byte kana */ #define LC_JISX0201R 0x8a /* Japanese 1 byte Roman */ /* Note that 0x8b seems to be unused as of Emacs 20.7. * However, there might be a chance that 0x8b could be used * in later version of Emacs. */ #define LC_KOI8_R 0x8b /* Cyrillic KOI8-R */ #define LC_KOI8_U 0x8b /* Cyrillic KOI8-U */ #define LC_ISO8859_5 0x8c /* ISO8859 Cyrillic */ #define LC_ISO8859_9 0x8d /* ISO8859 Latin 5 (not supported yet) */ /* #define FREE 0x8e free (unused) */ /* * Unused */ #define CONTROL_1 0x8f /* control characters (unused) */ /* * Official multibyte byte encodings (0x90-0x99) * 0x9a-0x9d are free. 0x9e and 0x9f are reserved. */ #define LC_JISX0208_1978 0x90 /* Japanese Kanji, old JIS (not supported) */ /* #define FREE 0x90 free (unused) */ #define LC_GB2312_80 0x91 /* Chinese */ #define LC_JISX0208 0x92 /* Japanese Kanji (JIS X 0208) */ #define LC_KS5601 0x93 /* Korean */ #define LC_JISX0212 0x94 /* Japanese Kanji (JIS X 0212) */ #define LC_CNS11643_1 0x95 /* CNS 11643-1992 Plane 1 */ #define LC_CNS11643_2 0x96 /* CNS 11643-1992 Plane 2 */ /* #define FREE 0x97 free (unused) */ #define LC_BIG5_1 0x98 /* Plane 1 Chinese traditional (not supported) */ #define LC_BIG5_2 0x99 /* Plane 1 Chinese traditional (not supported) */ /* * Private single byte encodings (0xa0-0xef) */ #define LC_SISHENG 0xa0/* Chinese SiSheng characters for * PinYin/ZhuYin (not supported) */ #define LC_IPA 0xa1/* IPA (International Phonetic Association) * (not supported) */ #define LC_VISCII_LOWER 0xa2/* Vietnamese VISCII1.1 lower-case (not * supported) */ #define LC_VISCII_UPPER 0xa3/* Vietnamese VISCII1.1 upper-case (not * supported) */ #define LC_ARABIC_DIGIT 0xa4 /* Arabic digit (not supported) */ #define LC_ARABIC_1_COLUMN 0xa5 /* Arabic 1-column (not supported) */ #define LC_ASCII_RIGHT_TO_LEFT 0xa6 /* ASCII (left half of ISO8859-1) with * right-to-left direction (not * supported) */ #define LC_LAO 0xa7/* Lao characters (ISO10646 0E80..0EDF) (not * supported) */ #define LC_ARABIC_2_COLUMN 0xa8 /* Arabic 1-column (not supported) */ /* * Private multibyte encodings (0xf0-0xff) */ #define LC_INDIAN_1_COLUMN 0xf0/* Indian charset for 1-column width glypps * (not supported) */ #define LC_TIBETAN_1_COLUMN 0xf1 /* Tibetan 1 column glyph (not supported) */ #define LC_ETHIOPIC 0xf5 /* Ethiopic characters (not supported) */ #define LC_CNS11643_3 0xf6 /* CNS 11643-1992 Plane 3 */ #define LC_CNS11643_4 0xf7 /* CNS 11643-1992 Plane 4 */ #define LC_CNS11643_5 0xf8 /* CNS 11643-1992 Plane 5 */ #define LC_CNS11643_6 0xf9 /* CNS 11643-1992 Plane 6 */ #define LC_CNS11643_7 0xfa /* CNS 11643-1992 Plane 7 */ #define LC_INDIAN_2_COLUMN 0xfb/* Indian charset for 2-column width glypps * (not supported) */ #define LC_TIBETAN 0xfc /* Tibetan (not supported) */ /* #define FREE 0xfd free (unused) */ /* #define FREE 0xfe free (unused) */ /* #define FREE 0xff free (unused) */ /* * PostgreSQL encoding identifiers * * WARNING: the order of this enum must be same as order of entries * in the pg_enc2name_tbl[] array (in mb/encnames.c), and * in the pg_wchar_table[] array (in mb/wchar.c)! * * If you add some encoding don't forget to check * PG_ENCODING_BE_LAST macro. * * PG_SQL_ASCII is default encoding and must be = 0. * * XXX We must avoid renumbering any backend encoding until libpq's major * version number is increased beyond 5; it turns out that the backend * encoding IDs are effectively part of libpq's ABI as far as 8.2 initdb and * psql are concerned. */ typedef enum pg_enc { PG_SQL_ASCII = 0, /* SQL/ASCII */ PG_EUC_JP, /* EUC for Japanese */ PG_EUC_CN, /* EUC for Chinese */ PG_EUC_KR, /* EUC for Korean */ PG_EUC_TW, /* EUC for Taiwan */ PG_EUC_JIS_2004, /* EUC-JIS-2004 */ PG_UTF8, /* Unicode UTF8 */ PG_MULE_INTERNAL, /* Mule internal code */ PG_LATIN1, /* ISO-8859-1 Latin 1 */ PG_LATIN2, /* ISO-8859-2 Latin 2 */ PG_LATIN3, /* ISO-8859-3 Latin 3 */ PG_LATIN4, /* ISO-8859-4 Latin 4 */ PG_LATIN5, /* ISO-8859-9 Latin 5 */ PG_LATIN6, /* ISO-8859-10 Latin6 */ PG_LATIN7, /* ISO-8859-13 Latin7 */ PG_LATIN8, /* ISO-8859-14 Latin8 */ PG_LATIN9, /* ISO-8859-15 Latin9 */ PG_LATIN10, /* ISO-8859-16 Latin10 */ PG_WIN1256, /* windows-1256 */ PG_WIN1258, /* Windows-1258 */ PG_WIN866, /* (MS-DOS CP866) */ PG_WIN874, /* windows-874 */ PG_KOI8R, /* KOI8-R */ PG_WIN1251, /* windows-1251 */ PG_WIN1252, /* windows-1252 */ PG_ISO_8859_5, /* ISO-8859-5 */ PG_ISO_8859_6, /* ISO-8859-6 */ PG_ISO_8859_7, /* ISO-8859-7 */ PG_ISO_8859_8, /* ISO-8859-8 */ PG_WIN1250, /* windows-1250 */ PG_WIN1253, /* windows-1253 */ PG_WIN1254, /* windows-1254 */ PG_WIN1255, /* windows-1255 */ PG_WIN1257, /* windows-1257 */ PG_KOI8U, /* KOI8-U */ /* PG_ENCODING_BE_LAST points to the above entry */ /* followings are for client encoding only */ PG_SJIS, /* Shift JIS (Winindows-932) */ PG_BIG5, /* Big5 (Windows-950) */ PG_GBK, /* GBK (Windows-936) */ PG_UHC, /* UHC (Windows-949) */ PG_GB18030, /* GB18030 */ PG_JOHAB, /* EUC for Korean JOHAB */ PG_SHIFT_JIS_2004, /* Shift-JIS-2004 */ _PG_LAST_ENCODING_ /* mark only */ } pg_enc; #define PG_ENCODING_BE_LAST PG_KOI8U /* * Please use these tests before access to pg_encconv_tbl[] * or to other places... */ #define PG_VALID_BE_ENCODING(_enc) \ ((_enc) >= 0 && (_enc) <= PG_ENCODING_BE_LAST) #define PG_ENCODING_IS_CLIENT_ONLY(_enc) \ ((_enc) > PG_ENCODING_BE_LAST && (_enc) < _PG_LAST_ENCODING_) #define PG_VALID_ENCODING(_enc) \ ((_enc) >= 0 && (_enc) < _PG_LAST_ENCODING_) /* On FE are possible all encodings */ #define PG_VALID_FE_ENCODING(_enc) PG_VALID_ENCODING(_enc) /* * Encoding names with all aliases */ typedef struct pg_encname { char *name; pg_enc encoding; } pg_encname; extern pg_encname pg_encname_tbl[]; extern unsigned int pg_encname_tbl_sz; /* * Careful: * * if (PG_VALID_ENCODING(encoding)) * pg_enc2name_tbl[ encoding ]; */ typedef struct pg_enc2name { char *name; pg_enc encoding; #ifdef WIN32 unsigned codepage; /* codepage for WIN32 */ #endif } pg_enc2name; extern pg_enc2name pg_enc2name_tbl[]; /* * Encoding names for gettext */ typedef struct pg_enc2gettext { pg_enc encoding; const char *name; } pg_enc2gettext; extern pg_enc2gettext pg_enc2gettext_tbl[]; /* * pg_wchar stuff */ typedef int (*mb2wchar_with_len_converter) (const unsigned char *from, pg_wchar *to, int len); typedef int (*mblen_converter) (const unsigned char *mbstr); typedef int (*mbdisplaylen_converter) (const unsigned char *mbstr); typedef int (*mbverifier) (const unsigned char *mbstr, int len); typedef struct { mb2wchar_with_len_converter mb2wchar_with_len; /* convert a multibyte * string to a wchar */ mblen_converter mblen; /* get byte length of a char */ mbdisplaylen_converter dsplen; /* get display width of a char */ mbverifier mbverify; /* verify multibyte sequence */ int maxmblen; /* max bytes for a char in this encoding */ } pg_wchar_tbl; extern pg_wchar_tbl pg_wchar_table[]; /* * UTF-8 to local code conversion map * Note that we limit the max length of UTF-8 to 4 bytes, * which is UCS-4 00010000-001FFFFF range. */ typedef struct { uint32 utf; /* UTF-8 */ uint32 code; /* local code */ } pg_utf_to_local; /* * local code to UTF-8 conversion map */ typedef struct { uint32 code; /* local code */ uint32 utf; /* UTF-8 */ } pg_local_to_utf; /* * UTF-8 to local code conversion map(combined characters) */ typedef struct { uint32 utf1; /* UTF-8 code 1 */ uint32 utf2; /* UTF-8 code 2 */ uint32 code; /* local code */ } pg_utf_to_local_combined; /* * local code to UTF-8 conversion map(combined characters) */ typedef struct { uint32 code; /* local code */ uint32 utf1; /* UTF-8 code 1 */ uint32 utf2; /* UTF-8 code 2 */ } pg_local_to_utf_combined; /* * Support macro for encoding conversion functions to validate their * arguments. (This could be made more compact if we included fmgr.h * here, but we don't want to do that because this header file is also * used by frontends.) */ #define CHECK_ENCODING_CONVERSION_ARGS(srcencoding,destencoding) \ check_encoding_conversion_args(PG_GETARG_INT32(0), \ PG_GETARG_INT32(1), \ PG_GETARG_INT32(4), \ (srcencoding), \ (destencoding)) /* * These functions are considered part of libpq's exported API and * are also declared in libpq-fe.h. */ extern int pg_char_to_encoding(const char *name); extern const char *pg_encoding_to_char(int encoding); extern int pg_valid_server_encoding_id(int encoding); /* * Remaining functions are not considered part of libpq's API, though many * of them do exist inside libpq. */ extern pg_encname *pg_char_to_encname_struct(const char *name); extern int pg_mb2wchar(const char *from, pg_wchar *to); extern int pg_mb2wchar_with_len(const char *from, pg_wchar *to, int len); extern int pg_encoding_mb2wchar_with_len(int encoding, const char *from, pg_wchar *to, int len); extern int pg_char_and_wchar_strcmp(const char *s1, const pg_wchar *s2); extern int pg_wchar_strncmp(const pg_wchar *s1, const pg_wchar *s2, size_t n); extern int pg_char_and_wchar_strncmp(const char *s1, const pg_wchar *s2, size_t n); extern size_t pg_wchar_strlen(const pg_wchar *wstr); extern int pg_mblen(const char *mbstr); extern int pg_dsplen(const char *mbstr); extern int pg_encoding_mblen(int encoding, const char *mbstr); extern int pg_encoding_dsplen(int encoding, const char *mbstr); extern int pg_encoding_verifymb(int encoding, const char *mbstr, int len); extern int pg_mule_mblen(const unsigned char *mbstr); extern int pg_mic_mblen(const unsigned char *mbstr); extern int pg_mbstrlen(const char *mbstr); extern int pg_mbstrlen_with_len(const char *mbstr, int len); extern int pg_mbcliplen(const char *mbstr, int len, int limit); extern int pg_encoding_mbcliplen(int encoding, const char *mbstr, int len, int limit); extern int pg_mbcharcliplen(const char *mbstr, int len, int imit); extern int pg_encoding_max_length(int encoding); extern int pg_database_encoding_max_length(void); extern int PrepareClientEncoding(int encoding); extern int SetClientEncoding(int encoding); extern void InitializeClientEncoding(void); extern int pg_get_client_encoding(void); extern const char *pg_get_client_encoding_name(void); extern void SetDatabaseEncoding(int encoding); extern int GetDatabaseEncoding(void); extern const char *GetDatabaseEncodingName(void); extern int GetPlatformEncoding(void); extern void pg_bind_textdomain_codeset(const char *domainname); extern int pg_valid_client_encoding(const char *name); extern int pg_valid_server_encoding(const char *name); extern unsigned char *unicode_to_utf8(pg_wchar c, unsigned char *utf8string); extern pg_wchar utf8_to_unicode(const unsigned char *c); extern int pg_utf_mblen(const unsigned char *); extern unsigned char *pg_do_encoding_conversion(unsigned char *src, int len, int src_encoding, int dest_encoding); extern char *pg_client_to_server(const char *s, int len); extern char *pg_server_to_client(const char *s, int len); extern char *pg_any_to_server(const char *s, int len, int encoding); extern char *pg_server_to_any(const char *s, int len, int encoding); extern unsigned short BIG5toCNS(unsigned short big5, unsigned char *lc); extern unsigned short CNStoBIG5(unsigned short cns, unsigned char lc); extern void LocalToUtf(const unsigned char *iso, unsigned char *utf, const pg_local_to_utf *map, const pg_local_to_utf_combined *cmap, int size1, int size2, int encoding, int len); extern void UtfToLocal(const unsigned char *utf, unsigned char *iso, const pg_utf_to_local *map, const pg_utf_to_local_combined *cmap, int size1, int size2, int encoding, int len); extern bool pg_verifymbstr(const char *mbstr, int len, bool noError); extern bool pg_verify_mbstr(int encoding, const char *mbstr, int len, bool noError); extern int pg_verify_mbstr_len(int encoding, const char *mbstr, int len, bool noError); extern void check_encoding_conversion_args(int src_encoding, int dest_encoding, int len, int expected_src_encoding, int expected_dest_encoding); extern void report_invalid_encoding(int encoding, const char *mbstr, int len); extern void report_untranslatable_char(int src_encoding, int dest_encoding, const char *mbstr, int len); extern void pg_ascii2mic(const unsigned char *l, unsigned char *p, int len); extern void pg_mic2ascii(const unsigned char *mic, unsigned char *p, int len); extern void latin2mic(const unsigned char *l, unsigned char *p, int len, int lc, int encoding); extern void mic2latin(const unsigned char *mic, unsigned char *p, int len, int lc, int encoding); extern void latin2mic_with_table(const unsigned char *l, unsigned char *p, int len, int lc, int encoding, const unsigned char *tab); extern void mic2latin_with_table(const unsigned char *mic, unsigned char *p, int len, int lc, int encoding, const unsigned char *tab); extern bool pg_utf8_islegal(const unsigned char *source, int length); #ifdef WIN32 extern WCHAR *pgwin32_toUTF16(const char *str, int len, int *utf16len); #endif #endif /* PG_WCHAR_H */ RPostgreSQL/src/libpq/libpq-events.c0000644000176000001440000001060512124517222017102 0ustar ripleyusers/*------------------------------------------------------------------------- * * libpq-events.c * functions for supporting the libpq "events" API * * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * src/interfaces/libpq/libpq-events.c * *------------------------------------------------------------------------- */ #include "postgres_fe.h" #include "libpq-fe.h" #include "libpq-int.h" /* * Registers an event proc with the given PGconn. * * The same proc can't be registered more than once in a PGconn. This * restriction is required because we use the proc address to identify * the event for purposes such as PQinstanceData(). * * The name argument is used within error messages to aid in debugging. * A name must be supplied, but it needn't be unique. The string is * copied, so the passed value needn't be long-lived. * * The passThrough argument is an application specific pointer and can be set * to NULL if not required. It is passed through to the event proc whenever * the event proc is called, and is not otherwise touched by libpq. * * The function returns a non-zero if successful. If the function fails, * zero is returned. */ int PQregisterEventProc(PGconn *conn, PGEventProc proc, const char *name, void *passThrough) { int i; PGEventRegister regevt; if (!proc || !conn || !name || !*name) return FALSE; /* bad arguments */ for (i = 0; i < conn->nEvents; i++) { if (conn->events[i].proc == proc) return FALSE; /* already registered */ } if (conn->nEvents >= conn->eventArraySize) { PGEvent *e; int newSize; newSize = conn->eventArraySize ? conn->eventArraySize * 2 : 8; if (conn->events) e = (PGEvent *) realloc(conn->events, newSize * sizeof(PGEvent)); else e = (PGEvent *) malloc(newSize * sizeof(PGEvent)); if (!e) return FALSE; conn->eventArraySize = newSize; conn->events = e; } conn->events[conn->nEvents].proc = proc; conn->events[conn->nEvents].name = strdup(name); if (!conn->events[conn->nEvents].name) return FALSE; conn->events[conn->nEvents].passThrough = passThrough; conn->events[conn->nEvents].data = NULL; conn->events[conn->nEvents].resultInitialized = FALSE; conn->nEvents++; regevt.conn = conn; if (!proc(PGEVT_REGISTER, ®evt, passThrough)) { conn->nEvents--; free(conn->events[conn->nEvents].name); return FALSE; } return TRUE; } /* * Set some "instance data" for an event within a PGconn. * Returns nonzero on success, zero on failure. */ int PQsetInstanceData(PGconn *conn, PGEventProc proc, void *data) { int i; if (!conn || !proc) return FALSE; for (i = 0; i < conn->nEvents; i++) { if (conn->events[i].proc == proc) { conn->events[i].data = data; return TRUE; } } return FALSE; } /* * Obtain the "instance data", if any, for the event. */ void * PQinstanceData(const PGconn *conn, PGEventProc proc) { int i; if (!conn || !proc) return NULL; for (i = 0; i < conn->nEvents; i++) { if (conn->events[i].proc == proc) return conn->events[i].data; } return NULL; } /* * Set some "instance data" for an event within a PGresult. * Returns nonzero on success, zero on failure. */ int PQresultSetInstanceData(PGresult *result, PGEventProc proc, void *data) { int i; if (!result || !proc) return FALSE; for (i = 0; i < result->nEvents; i++) { if (result->events[i].proc == proc) { result->events[i].data = data; return TRUE; } } return FALSE; } /* * Obtain the "instance data", if any, for the event. */ void * PQresultInstanceData(const PGresult *result, PGEventProc proc) { int i; if (!result || !proc) return NULL; for (i = 0; i < result->nEvents; i++) if (result->events[i].proc == proc) return result->events[i].data; return NULL; } /* * Fire RESULTCREATE events for an application-created PGresult. * * The conn argument can be NULL if event procedures won't use it. */ int PQfireResultCreateEvents(PGconn *conn, PGresult *res) { int i; if (!res) return FALSE; for (i = 0; i < res->nEvents; i++) { if (!res->events[i].resultInitialized) { PGEventResultCreate evt; evt.conn = conn; evt.result = res; if (!res->events[i].proc(PGEVT_RESULTCREATE, &evt, res->events[i].passThrough)) return FALSE; res->events[i].resultInitialized = TRUE; } } return TRUE; } RPostgreSQL/src/libpq/Makefile.shlib0000644000176000001440000003610511711132675017076 0ustar ripleyusers#------------------------------------------------------------------------- # # Makefile.shlib # Common rules for building shared libraries # # Copyright (c) 1998, Regents of the University of California # # IDENTIFICATION # src/Makefile.shlib # #------------------------------------------------------------------------- # This file should be included by any Postgres module Makefile that # wants to build a shared library (if possible for the current # platform). A static library is also built from the same object # files. Only one library can be built per makefile. # # Before including this file, the module Makefile must define these # variables: # # NAME Name of library to build (no suffix nor "lib" prefix) # OBJS List of object files to include in library # SHLIB_LINK If shared library relies on other libraries, # additional stuff to put in its link command # SHLIB_PREREQS Order-only prerequisites for library build target # SHLIB_EXPORTS (optional) Name of file containing list of symbols to # export, in the format "function_name number" # # When building a shared library, the following version information # must also be set. It should be omitted when building a dynamically # loadable module. # # SO_MAJOR_VERSION Major version number to use for shared library # SO_MINOR_VERSION Minor version number to use for shared library # (If you want a patchlevel, include it in SO_MINOR_VERSION, e.g., "6.2".) # # Optional flags when building DLL's (only applicable to win32 and cygwin # platforms). # DLLTOOL_DEFFLAGS Additional flags when creating the dll .def file # DLLTOOL_LIBFLAGS Additional flags when creating the lib.a file # DLLWRAP_FLAGS Additional flags to dllwrap # # The module Makefile must also include # $(top_builddir)/src/Makefile.global before including this file. # (Makefile.global sets PORTNAME and other needed symbols.) # # This makefile provides the following (phony) targets: # # all-lib build the static and shared (if applicable) libraries # install-lib install the libraries into $(libdir) # installdirs-lib create installation directory $(libdir) # uninstall-lib remove the libraries from $(libdir) # clean-lib delete the static and shared libraries from the build dir # maintainer-clean-lib delete .def files built for win32 # # Since `all-lib' is the first rule in this file you probably want to # have the `all' target before including this file. In the most simple # case it would look like this: # # all: all-lib # # Similarly, the install rule might look like # # install: install-lib # # plus any additional things you want to install. Et cetera. # # Got that? Look at src/interfaces/libpq/Makefile for an example. # # While the linker allows creation of most shared libraries, # -Bsymbolic requires resolution of all symbols, making the # compiler a better choice for shared library creation on ELF platforms. # With the linker, -Bsymbolic requires the crt1.o startup object file. # bjm 2001-02-10 COMPILER = $(CC) $(CFLAGS) LINK.static = $(AR) $(AROPT) ifdef SO_MAJOR_VERSION # Default library naming convention used by the majority of platforms ifeq ($(enable_shared), yes) shlib = lib$(NAME)$(DLSUFFIX).$(SO_MAJOR_VERSION).$(SO_MINOR_VERSION) shlib_major = lib$(NAME)$(DLSUFFIX).$(SO_MAJOR_VERSION) shlib_bare = lib$(NAME)$(DLSUFFIX) endif # Testing the soname variable is a reliable way to determine whether a # linkable library is being built. soname = $(shlib_major) else # Naming convention for dynamically loadable modules ifeq ($(enable_shared), yes) shlib = $(NAME)$(DLSUFFIX) endif endif stlib = lib$(NAME).a ifndef soname # additional flags for backend modules SHLIB_LINK += $(BE_DLLLIBS) endif # For each platform we support shared libraries on, set shlib to the # name of the library (if default above is not right), set # LINK.shared to the command to link the library, # and adjust SHLIB_LINK if necessary. # Try to keep the sections in some kind of order, folks... override CFLAGS += $(CFLAGS_SL) ifdef SO_MAJOR_VERSION # libraries ought to use this to refer to versioned gettext domain names override CPPFLAGS += -DSO_MAJOR_VERSION=$(SO_MAJOR_VERSION) endif ifeq ($(PORTNAME), aix) ifdef SO_MAJOR_VERSION shlib = lib$(NAME)$(DLSUFFIX).$(SO_MAJOR_VERSION) endif haslibarule = yes exports_file = lib$(NAME).exp endif ifeq ($(PORTNAME), darwin) ifdef soname # linkable library DLSUFFIX = .dylib ifneq ($(SO_MAJOR_VERSION), 0) version_link = -compatibility_version $(SO_MAJOR_VERSION) -current_version $(SO_MAJOR_VERSION).$(SO_MINOR_VERSION) endif LINK.shared = $(COMPILER) -dynamiclib -install_name '$(libdir)/lib$(NAME).$(SO_MAJOR_VERSION)$(DLSUFFIX)' $(version_link) $(exported_symbols_list) -multiply_defined suppress shlib = lib$(NAME).$(SO_MAJOR_VERSION).$(SO_MINOR_VERSION)$(DLSUFFIX) shlib_major = lib$(NAME).$(SO_MAJOR_VERSION)$(DLSUFFIX) else # loadable module DLSUFFIX = .so LINK.shared = $(COMPILER) -bundle -multiply_defined suppress endif BUILD.exports = $(AWK) '/^[^\#]/ {printf "_%s\n",$$1}' $< >$@ exports_file = $(SHLIB_EXPORTS:%.txt=%.list) ifneq (,$(exports_file)) exported_symbols_list = -exported_symbols_list $(exports_file) endif endif ifeq ($(PORTNAME), openbsd) ifdef ELF_SYSTEM LINK.shared = $(COMPILER) -shared ifdef soname LINK.shared += -Wl,-x,-soname,$(soname) endif SHLIB_LINK += -lc else LINK.shared = $(LD) -x -Bshareable -Bforcearchive endif endif ifeq ($(PORTNAME), bsdi) ifeq ($(DLSUFFIX), .so) LINK.shared = $(COMPILER) -shared ifdef soname LINK.shared += -Wl,-x,-soname,$(soname) endif SHLIB_LINK += -lc endif ifeq ($(DLSUFFIX), .o) LINK.shared = shlicc -O $(LDREL) endif endif ifeq ($(PORTNAME), freebsd) ifdef ELF_SYSTEM ifdef SO_MAJOR_VERSION shlib = lib$(NAME)$(DLSUFFIX).$(SO_MAJOR_VERSION) endif LINK.shared = $(COMPILER) -shared ifdef soname LINK.shared += -Wl,-x,-soname,$(soname) endif else ifdef SO_MAJOR_VERSION shlib = lib$(NAME)$(DLSUFFIX).$(SO_MAJOR_VERSION).$(SO_MINOR_VERSION) endif LINK.shared = $(LD) -x -Bshareable -Bforcearchive endif endif ifeq ($(PORTNAME), netbsd) ifdef ELF_SYSTEM LINK.shared = $(COMPILER) -shared ifdef soname LINK.shared += -Wl,-x,-soname,$(soname) endif else LINK.shared = $(LD) -x -Bshareable -Bforcearchive endif endif ifeq ($(PORTNAME), hpux) ifdef SO_MAJOR_VERSION shlib = lib$(NAME)$(DLSUFFIX).$(SO_MAJOR_VERSION) endif ifeq ($(with_gnu_ld), yes) LINK.shared = $(CC) -shared ifdef soname LINK.shared += -Wl,-h -Wl,$(soname) endif else LINK.shared = $(LD) -b ifdef soname LINK.shared += +h $(soname) endif # can't use the CC-syntax rpath pattern here, so instead: rpath = ifeq ($(enable_rpath), yes) LINK.shared += +b '$(rpathdir)' endif # On HPUX platforms, gcc is usually configured to search for libraries # in /usr/local/lib, but ld won't do so. Add an explicit -L switch so # ld can find the same libraries gcc does. Make sure it goes after any # -L switches provided explicitly. ifeq ($(GCC), yes) SHLIB_LINK += -L/usr/local/lib endif endif # And we need to link with libgcc, too ifeq ($(GCC), yes) SHLIB_LINK += `$(CC) $(LDFLAGS) -print-libgcc-file-name` endif endif ifeq ($(PORTNAME), irix) ifdef SO_MAJOR_VERSION shlib = lib$(NAME)$(DLSUFFIX).$(SO_MAJOR_VERSION) endif LINK.shared = $(COMPILER) -shared ifdef soname LINK.shared += -Wl,-set_version,sgi$(SO_MAJOR_VERSION).$(SO_MINOR_VERSION) endif endif ifeq ($(PORTNAME), linux) LINK.shared = $(COMPILER) -shared ifdef soname LINK.shared += -Wl,-soname,$(soname) endif BUILD.exports = ( echo '{ global:'; $(AWK) '/^[^\#]/ {printf "%s;\n",$$1}' $<; echo ' local: *; };' ) >$@ exports_file = $(SHLIB_EXPORTS:%.txt=%.list) ifneq (,$(exports_file)) LINK.shared += -Wl,--version-script=$(exports_file) endif endif ifeq ($(PORTNAME), solaris) ifeq ($(GCC), yes) LINK.shared = $(COMPILER) -shared else LINK.shared = $(COMPILER) -G endif ifdef soname ifeq ($(with_gnu_ld), yes) LINK.shared += -Wl,-soname,$(soname) else LINK.shared += -h $(soname) endif endif endif ifeq ($(PORTNAME), sunos4) LINK.shared = $(LD) -assert pure-text -Bdynamic endif ifeq ($(PORTNAME), osf) LINK.shared = $(LD) -shared -expect_unresolved '*' endif ifeq ($(PORTNAME), sco) ifeq ($(GCC), yes) LINK.shared = $(CC) -shared else LINK.shared = $(CC) -G endif LINK.shared += -Wl,-z,text ifdef soname LINK.shared += -Wl,-h,$(soname) endif endif ifeq ($(PORTNAME), svr4) LINK.shared = $(LD) -G endif ifeq ($(PORTNAME), univel) LINK.shared = $(LD) -G -z text endif ifeq ($(PORTNAME), unixware) ifeq ($(GCC), yes) LINK.shared = $(CC) -shared else LINK.shared = $(CC) -G endif LINK.shared += -Wl,-z,text ifdef soname LINK.shared += -Wl,-h,$(soname) endif endif ifeq ($(PORTNAME), cygwin) ifdef SO_MAJOR_VERSION shlib = cyg$(NAME)$(DLSUFFIX) endif haslibarule = yes endif ifeq ($(PORTNAME), win32) ifdef SO_MAJOR_VERSION shlib = lib$(NAME)$(DLSUFFIX) endif haslibarule = yes endif ## ## BUILD ## .PHONY: all-lib all-static-lib all-shared-lib all-lib: all-shared-lib ifdef soname # no static library when building a dynamically loadable module all-lib: all-static-lib endif all-static-lib: $(stlib) all-shared-lib: $(shlib) ifndef haslibarule $(stlib): $(OBJS) $(LINK.static) $@ $^ $(RANLIB) $@ endif #haslibarule ifeq ($(enable_shared), yes) ifeq (,$(filter cygwin win32,$(PORTNAME))) ifneq ($(PORTNAME), aix) # Normal case $(shlib): $(OBJS) $(LINK.shared) -o $@ $(OBJS) $(LDFLAGS) $(LDFLAGS_SL) $(SHLIB_LINK) ifdef shlib_major # If we're using major and minor versions, then make a symlink to major-version-only. ifneq ($(shlib), $(shlib_major)) rm -f $(shlib_major) $(LN_S) $(shlib) $(shlib_major) endif # Make sure we have a link to a name without any version numbers ifneq ($(shlib), $(shlib_bare)) rm -f $(shlib_bare) $(LN_S) $(shlib) $(shlib_bare) endif endif # shlib_major # Where possible, restrict the symbols exported by the library to just the # official list, so as to avoid unintentional ABI changes. On recent Darwin # this also quiets multiply-defined-symbol warnings in programs that use # libpgport along with libpq. ifneq (,$(SHLIB_EXPORTS)) ifdef BUILD.exports $(shlib): $(SHLIB_EXPORTS:%.txt=%.list) $(SHLIB_EXPORTS:%.txt=%.list): %.list: %.txt $(BUILD.exports) endif endif else # PORTNAME == aix # AIX case $(shlib) $(stlib): $(OBJS) $(LINK.static) $(stlib) $^ $(RANLIB) $(stlib) $(MKLDEXPORT) $(stlib) >$(exports_file) $(COMPILER) -o $(shlib) $(stlib) -Wl,-bE:$(exports_file) $(LDFLAGS) $(LDFLAGS_SL) $(SHLIB_LINK) rm -f $(stlib) $(AR) $(AROPT) $(stlib) $(shlib) endif # PORTNAME == aix else # PORTNAME == cygwin || PORTNAME == win32 # Cygwin or Win32 case # If SHLIB_EXPORTS is set, the rules below will build a .def file from # that. Else we build a temporary one here. ifeq (,$(SHLIB_EXPORTS)) DLL_DEFFILE = lib$(NAME)dll.def exports_file = $(DLL_DEFFILE) $(exports_file): $(OBJS) $(DLLTOOL) --export-all $(DLLTOOL_DEFFLAGS) --output-def $@ $^ else DLL_DEFFILE = lib$(NAME)dll.def endif ifeq "$(WIN)" "64" $(shlib): $(OBJS) $(DLL_DEFFILE) $(LD) -shared --dll -o $@ $(OBJS) $(DLL_DEFFILE) ifeq "$(AR)" "x86_64-w64-mingw32-ar" $(stlib): $(OBJS) $(AR) rcs $@ $(OBJS) else $(stlib): $(OBJS) $(AR) rcs --target pe-x86-64 $@ $(OBJS) endif else $(shlib): $(OBJS) $(DLL_DEFFILE) $(DLLWRAP) -o $@ --dllname $(shlib) $(DLLWRAP_FLAGS) --def $(DLL_DEFFILE) $(OBJS) $(LDFLAGS) $(LDFLAGS_SL) $(SHLIB_LINK) $(stlib): $(OBJS) $(AR) rcs $@ $(OBJS) endif endif # PORTNAME == cygwin || PORTNAME == win32 endif # enable_shared # We need several not-quite-identical variants of .DEF files to build # DLLs for Windows. These are made from the single source file # exports.txt. Since we can't assume that Windows boxes will have # sed, the .DEF files are always built and included in distribution # tarballs. ifneq (,$(SHLIB_EXPORTS)) distprep: lib$(NAME)dll.def lib$(NAME)ddll.def blib$(NAME)dll.def UC_NAME = $(shell echo $(NAME) | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ') lib$(NAME)dll.def: $(SHLIB_EXPORTS) echo '; DEF file for MS VC++' >$@ echo 'LIBRARY LIB$(UC_NAME)' >>$@ echo 'EXPORTS' >>$@ sed -e '/^#/d' -e 's/^\(.*[ ]\)\([0-9][0-9]*\)/ \1@ \2/' $< >>$@ lib$(NAME)ddll.def: $(SHLIB_EXPORTS) echo '; DEF file for MS VC++' >$@ echo 'LIBRARY LIB$(UC_NAME)D' >>$@ echo 'EXPORTS' >>$@ sed -e '/^#/d' -e 's/^\(.*[ ]\)\([0-9][0-9]*\)/ \1@ \2/' $< >>$@ blib$(NAME)dll.def: $(SHLIB_EXPORTS) echo '; DEF file for Borland C++ Builder' >$@ echo 'LIBRARY BLIB$(UC_NAME)' >>$@ echo 'EXPORTS' >>$@ sed -e '/^#/d' -e 's/^\(.*[ ]\)\([0-9][0-9]*\)/ _\1@ \2/' $< >>$@ echo >>$@ echo '; Aliases for MS compatible names' >> $@ sed -e '/^#/d' -e 's/^\(.*[ ]\)\([0-9][0-9]*\)/ \1= _\1/' $< | sed 's/ *$$//' >>$@ endif # SHLIB_EXPORTS ## ## INSTALL ## .PHONY: install-lib install-lib-static install-lib-shared installdirs-lib install-lib: install-lib-shared ifdef soname install-lib: install-lib-static endif install-lib-static: $(stlib) installdirs-lib $(INSTALL_STLIB) $< '$(DESTDIR)$(libdir)/$(stlib)' ifeq ($(PORTNAME), darwin) cd '$(DESTDIR)$(libdir)' && \ ranlib $(stlib) endif ifeq ($(enable_shared), yes) install-lib-shared: $(shlib) installdirs-lib ifdef soname # we don't install $(shlib) on AIX # (see http://archives.postgresql.org/message-id/52EF20B2E3209443BC37736D00C3C1380A6E79FE@EXADV1.host.magwien.gv.at) ifneq ($(PORTNAME), aix) $(INSTALL_SHLIB) $< '$(DESTDIR)$(libdir)/$(shlib)' ifneq ($(PORTNAME), cygwin) ifneq ($(PORTNAME), win32) ifneq ($(shlib), $(shlib_major)) cd '$(DESTDIR)$(libdir)' && \ rm -f $(shlib_major) && \ $(LN_S) $(shlib) $(shlib_major) endif ifneq ($(shlib), $(shlib_bare)) cd '$(DESTDIR)$(libdir)' && \ rm -f $(shlib_bare) && \ $(LN_S) $(shlib) $(shlib_bare) endif endif # not win32 endif # not cygwin endif # not aix else # no soname $(INSTALL_SHLIB) $< '$(DESTDIR)$(pkglibdir)/$(shlib)' endif else # not enable_shared ifndef soname install-lib-shared: @echo "*****"; \ echo "* Module $(NAME) was not installed due to lack of shared library support."; \ echo "*****" endif endif # enable_shared installdirs-lib: ifdef soname $(MKDIR_P) '$(DESTDIR)$(libdir)' else $(MKDIR_P) '$(DESTDIR)$(pkglibdir)' endif ## ## UNINSTALL ## .PHONY: uninstall-lib uninstall-lib: ifdef soname rm -f '$(DESTDIR)$(libdir)/$(stlib)' ifeq ($(enable_shared), yes) rm -f '$(DESTDIR)$(libdir)/$(shlib_bare)' \ '$(DESTDIR)$(libdir)/$(shlib_major)' \ '$(DESTDIR)$(libdir)/$(shlib)' endif # enable_shared else # no soname rm -f '$(DESTDIR)$(pkglibdir)/$(shlib)' endif # no soname ## ## CLEAN ## .PHONY: clean-lib clean-lib: rm -f $(shlib) $(shlib_bare) $(shlib_major) $(stlib) $(exports_file) ifneq (,$(SHLIB_EXPORTS)) maintainer-clean-lib: rm -f lib$(NAME)dll.def lib$(NAME)ddll.def blib$(NAME)dll.def endif RPostgreSQL/src/libpq/inet_net_ntop.c0000644000176000001440000001606412124517222017343 0ustar ripleyusers/* * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1996,1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * src/backend/utils/adt/inet_net_ntop.c */ #if defined(LIBC_SCCS) && !defined(lint) static const char rcsid[] = "Id: inet_net_ntop.c,v 1.1.2.2 2004/03/09 09:17:27 marka Exp $"; #endif #ifndef FRONTEND #include "postgres.h" #else #include "postgres_fe.h" #endif #include #include #include #include #ifndef FRONTEND #include "utils/inet.h" #else /* * In a frontend build, we can't include inet.h, but we still need to have * sensible definitions of these two constants. Note that inet_net_ntop() * assumes that PGSQL_AF_INET is equal to AF_INET. */ #define PGSQL_AF_INET (AF_INET + 0) #define PGSQL_AF_INET6 (AF_INET + 1) #endif #define NS_IN6ADDRSZ 16 #define NS_INT16SZ 2 #ifdef SPRINTF_CHAR #define SPRINTF(x) strlen(sprintf/**/x) #else #define SPRINTF(x) ((size_t)sprintf x) #endif static char *inet_net_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size); static char *inet_net_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size); /* * char * * inet_net_ntop(af, src, bits, dst, size) * convert host/network address from network to presentation format. * "src"'s size is determined from its "af". * return: * pointer to dst, or NULL if an error occurred (check errno). * note: * 192.5.5.1/28 has a nonzero host part, which means it isn't a network * as called for by inet_net_pton() but it can be a host address with * an included netmask. * author: * Paul Vixie (ISC), October 1998 */ char * inet_net_ntop(int af, const void *src, int bits, char *dst, size_t size) { /* * We need to cover both the address family constants used by the PG inet * type (PGSQL_AF_INET and PGSQL_AF_INET6) and those used by the system * libraries (AF_INET and AF_INET6). We can safely assume PGSQL_AF_INET * == AF_INET, but the INET6 constants are very likely to be different. If * AF_INET6 isn't defined, silently ignore it. */ switch (af) { case PGSQL_AF_INET: return (inet_net_ntop_ipv4(src, bits, dst, size)); case PGSQL_AF_INET6: #if defined(AF_INET6) && AF_INET6 != PGSQL_AF_INET6 case AF_INET6: #endif return (inet_net_ntop_ipv6(src, bits, dst, size)); default: errno = EAFNOSUPPORT; return (NULL); } } /* * static char * * inet_net_ntop_ipv4(src, bits, dst, size) * convert IPv4 network address from network to presentation format. * "src"'s size is determined from its "af". * return: * pointer to dst, or NULL if an error occurred (check errno). * note: * network byte order assumed. this means 192.5.5.240/28 has * 0b11110000 in its fourth octet. * author: * Paul Vixie (ISC), October 1998 */ static char * inet_net_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size) { char *odst = dst; char *t; int len = 4; int b; if (bits < 0 || bits > 32) { errno = EINVAL; return (NULL); } /* Always format all four octets, regardless of mask length. */ for (b = len; b > 0; b--) { if (size <= sizeof ".255") goto emsgsize; t = dst; if (dst != odst) *dst++ = '.'; dst += SPRINTF((dst, "%u", *src++)); size -= (size_t) (dst - t); } /* don't print masklen if 32 bits */ if (bits != 32) { if (size <= sizeof "/32") goto emsgsize; dst += SPRINTF((dst, "/%u", bits)); } return (odst); emsgsize: errno = EMSGSIZE; return (NULL); } static int decoct(const u_char *src, int bytes, char *dst, size_t size) { char *odst = dst; char *t; int b; for (b = 1; b <= bytes; b++) { if (size <= sizeof "255.") return (0); t = dst; dst += SPRINTF((dst, "%u", *src++)); if (b != bytes) { *dst++ = '.'; *dst = '\0'; } size -= (size_t) (dst - t); } return (dst - odst); } static char * inet_net_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size) { /* * Note that int32_t and int16_t need only be "at least" large enough to * contain a value of the specified size. On some systems, like Crays, * there is no such thing as an integer variable with 16 bits. Keep this * in mind if you think this function should have been coded to use * pointer overlays. All the world's not a VAX. */ char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255/128"]; char *tp; struct { int base, len; } best, cur; u_int words[NS_IN6ADDRSZ / NS_INT16SZ]; int i; if ((bits < -1) || (bits > 128)) { errno = EINVAL; return (NULL); } /* * Preprocess: Copy the input (bytewise) array into a wordwise array. Find * the longest run of 0x00's in src[] for :: shorthanding. */ memset(words, '\0', sizeof words); for (i = 0; i < NS_IN6ADDRSZ; i++) words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3)); best.base = -1; cur.base = -1; best.len = 0; cur.len = 0; for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) { if (words[i] == 0) { if (cur.base == -1) cur.base = i, cur.len = 1; else cur.len++; } else { if (cur.base != -1) { if (best.base == -1 || cur.len > best.len) best = cur; cur.base = -1; } } } if (cur.base != -1) { if (best.base == -1 || cur.len > best.len) best = cur; } if (best.base != -1 && best.len < 2) best.base = -1; /* * Format the result. */ tp = tmp; for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) { /* Are we inside the best run of 0x00's? */ if (best.base != -1 && i >= best.base && i < (best.base + best.len)) { if (i == best.base) *tp++ = ':'; continue; } /* Are we following an initial run of 0x00s or any real hex? */ if (i != 0) *tp++ = ':'; /* Is this address an encapsulated IPv4? */ if (i == 6 && best.base == 0 && (best.len == 6 || (best.len == 7 && words[7] != 0x0001) || (best.len == 5 && words[5] == 0xffff))) { int n; n = decoct(src + 12, 4, tp, sizeof tmp - (tp - tmp)); if (n == 0) { errno = EMSGSIZE; return (NULL); } tp += strlen(tp); break; } tp += SPRINTF((tp, "%x", words[i])); } /* Was it a trailing run of 0x00's? */ if (best.base != -1 && (best.base + best.len) == (NS_IN6ADDRSZ / NS_INT16SZ)) *tp++ = ':'; *tp = '\0'; if (bits != -1 && bits != 128) tp += SPRINTF((tp, "/%u", bits)); /* * Check for overflow, copy, and we're done. */ if ((size_t) (tp - tmp) > size) { errno = EMSGSIZE; return (NULL); } strcpy(dst, tmp); return (dst); } RPostgreSQL/src/libpq/fe-secure.c0000644000176000001440000011674512124517222016363 0ustar ripleyusers/*------------------------------------------------------------------------- * * fe-secure.c * functions related to setting up a secure connection to the backend. * Secure connections are expected to provide confidentiality, * message integrity and endpoint authentication. * * * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * src/interfaces/libpq/fe-secure.c * * NOTES * * We don't provide informational callbacks here (like * info_cb() in be-secure.c), since there's no good mechanism to * display such information to the user. * *------------------------------------------------------------------------- */ #include "postgres_fe.h" #include #include #include #include "libpq-fe.h" #include "fe-auth.h" #include "pqsignal.h" #include "libpq-int.h" #ifdef WIN32 #include "win32.h" #else #include #include #include #include #ifdef HAVE_NETINET_TCP_H #include #endif #include #endif #include #ifdef ENABLE_THREAD_SAFETY #ifdef WIN32 #include "pthread-win32.h" #else #include #endif #endif #ifdef USE_SSL #include #if (SSLEAY_VERSION_NUMBER >= 0x00907000L) #include #endif #ifdef USE_SSL_ENGINE #include #endif #ifndef WIN32 #define USER_CERT_FILE ".postgresql/postgresql.crt" #define USER_KEY_FILE ".postgresql/postgresql.key" #define ROOT_CERT_FILE ".postgresql/root.crt" #define ROOT_CRL_FILE ".postgresql/root.crl" #else /* On Windows, the "home" directory is already PostgreSQL-specific */ #define USER_CERT_FILE "postgresql.crt" #define USER_KEY_FILE "postgresql.key" #define ROOT_CERT_FILE "root.crt" #define ROOT_CRL_FILE "root.crl" #endif static bool verify_peer_name_matches_certificate(PGconn *); static int verify_cb(int ok, X509_STORE_CTX *ctx); static int init_ssl_system(PGconn *conn); static void destroy_ssl_system(void); static int initialize_SSL(PGconn *conn); static void destroySSL(void); static PostgresPollingStatusType open_client_SSL(PGconn *); static void close_SSL(PGconn *); static char *SSLerrmessage(void); static void SSLerrfree(char *buf); static bool pq_init_ssl_lib = true; static bool pq_init_crypto_lib = true; static SSL_CTX *SSL_context = NULL; #ifdef ENABLE_THREAD_SAFETY static long ssl_open_connections = 0; #ifndef WIN32 static pthread_mutex_t ssl_config_mutex = PTHREAD_MUTEX_INITIALIZER; #else static pthread_mutex_t ssl_config_mutex = NULL; static long win32_ssl_create_mutex = 0; #endif #endif /* ENABLE_THREAD_SAFETY */ #endif /* SSL */ /* * Macros to handle disabling and then restoring the state of SIGPIPE handling. * On Windows, these are all no-ops since there's no SIGPIPEs. */ #ifndef WIN32 #define SIGPIPE_MASKED(conn) ((conn)->sigpipe_so || (conn)->sigpipe_flag) #ifdef ENABLE_THREAD_SAFETY struct sigpipe_info { sigset_t oldsigmask; bool sigpipe_pending; bool got_epipe; }; #define DECLARE_SIGPIPE_INFO(spinfo) struct sigpipe_info spinfo #define DISABLE_SIGPIPE(conn, spinfo, failaction) \ do { \ (spinfo).got_epipe = false; \ if (!SIGPIPE_MASKED(conn)) \ { \ if (pq_block_sigpipe(&(spinfo).oldsigmask, \ &(spinfo).sigpipe_pending) < 0) \ failaction; \ } \ } while (0) #define REMEMBER_EPIPE(spinfo, cond) \ do { \ if (cond) \ (spinfo).got_epipe = true; \ } while (0) #define RESTORE_SIGPIPE(conn, spinfo) \ do { \ if (!SIGPIPE_MASKED(conn)) \ pq_reset_sigpipe(&(spinfo).oldsigmask, (spinfo).sigpipe_pending, \ (spinfo).got_epipe); \ } while (0) #else /* !ENABLE_THREAD_SAFETY */ #define DECLARE_SIGPIPE_INFO(spinfo) pqsigfunc spinfo = NULL #define DISABLE_SIGPIPE(conn, spinfo, failaction) \ do { \ if (!SIGPIPE_MASKED(conn)) \ spinfo = pqsignal(SIGPIPE, SIG_IGN); \ } while (0) #define REMEMBER_EPIPE(spinfo, cond) #define RESTORE_SIGPIPE(conn, spinfo) \ do { \ if (!SIGPIPE_MASKED(conn)) \ pqsignal(SIGPIPE, spinfo); \ } while (0) #endif /* ENABLE_THREAD_SAFETY */ #else /* WIN32 */ #define DECLARE_SIGPIPE_INFO(spinfo) #define DISABLE_SIGPIPE(conn, spinfo, failaction) #define REMEMBER_EPIPE(spinfo, cond) #define RESTORE_SIGPIPE(conn, spinfo) #endif /* WIN32 */ /* ------------------------------------------------------------ */ /* Procedures common to all secure sessions */ /* ------------------------------------------------------------ */ /* * Exported function to allow application to tell us it's already * initialized OpenSSL. */ void PQinitSSL(int do_init) { PQinitOpenSSL(do_init, do_init); } /* * Exported function to allow application to tell us it's already * initialized OpenSSL and/or libcrypto. */ void PQinitOpenSSL(int do_ssl, int do_crypto) { #ifdef USE_SSL #ifdef ENABLE_THREAD_SAFETY /* * Disallow changing the flags while we have open connections, else we'd * get completely confused. */ if (ssl_open_connections != 0) return; #endif pq_init_ssl_lib = do_ssl; pq_init_crypto_lib = do_crypto; #endif } /* * Initialize global SSL context */ int pqsecure_initialize(PGconn *conn) { int r = 0; #ifdef USE_SSL r = init_ssl_system(conn); #endif return r; } /* * Destroy global context */ void pqsecure_destroy(void) { #ifdef USE_SSL destroySSL(); #endif } /* * Begin or continue negotiating a secure session. */ PostgresPollingStatusType pqsecure_open_client(PGconn *conn) { #ifdef USE_SSL /* First time through? */ if (conn->ssl == NULL) { /* We cannot use MSG_NOSIGNAL to block SIGPIPE when using SSL */ conn->sigpipe_flag = false; /* Create a connection-specific SSL object */ if (!(conn->ssl = SSL_new(SSL_context)) || !SSL_set_app_data(conn->ssl, conn) || !SSL_set_fd(conn->ssl, conn->sock)) { char *err = SSLerrmessage(); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not establish SSL connection: %s\n"), err); SSLerrfree(err); close_SSL(conn); return PGRES_POLLING_FAILED; } /* * Load client certificate, private key, and trusted CA certs. */ if (initialize_SSL(conn) != 0) { /* initialize_SSL already put a message in conn->errorMessage */ close_SSL(conn); return PGRES_POLLING_FAILED; } } /* Begin or continue the actual handshake */ return open_client_SSL(conn); #else /* shouldn't get here */ return PGRES_POLLING_FAILED; #endif } /* * Close secure session. */ void pqsecure_close(PGconn *conn) { #ifdef USE_SSL if (conn->ssl) close_SSL(conn); #endif } /* * Read data from a secure connection. * * On failure, this function is responsible for putting a suitable message * into conn->errorMessage. The caller must still inspect errno, but only * to determine whether to continue/retry after error. */ ssize_t pqsecure_read(PGconn *conn, void *ptr, size_t len) { ssize_t n; int result_errno = 0; char sebuf[256]; #ifdef USE_SSL if (conn->ssl) { int err; DECLARE_SIGPIPE_INFO(spinfo); /* SSL_read can write to the socket, so we need to disable SIGPIPE */ DISABLE_SIGPIPE(conn, spinfo, return -1); rloop: SOCK_ERRNO_SET(0); n = SSL_read(conn->ssl, ptr, len); err = SSL_get_error(conn->ssl, n); switch (err) { case SSL_ERROR_NONE: if (n < 0) { /* Not supposed to happen, so we don't translate the msg */ printfPQExpBuffer(&conn->errorMessage, "SSL_read failed but did not provide error information\n"); /* assume the connection is broken */ result_errno = ECONNRESET; } break; case SSL_ERROR_WANT_READ: n = 0; break; case SSL_ERROR_WANT_WRITE: /* * Returning 0 here would cause caller to wait for read-ready, * which is not correct since what SSL wants is wait for * write-ready. The former could get us stuck in an infinite * wait, so don't risk it; busy-loop instead. */ goto rloop; case SSL_ERROR_SYSCALL: if (n < 0) { result_errno = SOCK_ERRNO; REMEMBER_EPIPE(spinfo, result_errno == EPIPE); if (result_errno == EPIPE || result_errno == ECONNRESET) printfPQExpBuffer(&conn->errorMessage, libpq_gettext( "server closed the connection unexpectedly\n" "\tThis probably means the server terminated abnormally\n" "\tbefore or while processing the request.\n")); else printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL SYSCALL error: %s\n"), SOCK_STRERROR(result_errno, sebuf, sizeof(sebuf))); } else { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL SYSCALL error: EOF detected\n")); /* assume the connection is broken */ result_errno = ECONNRESET; n = -1; } break; case SSL_ERROR_SSL: { char *errm = SSLerrmessage(); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL error: %s\n"), errm); SSLerrfree(errm); /* assume the connection is broken */ result_errno = ECONNRESET; n = -1; break; } case SSL_ERROR_ZERO_RETURN: /* * Per OpenSSL documentation, this error code is only returned * for a clean connection closure, so we should not report it * as a server crash. */ printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL connection has been closed unexpectedly\n")); result_errno = ECONNRESET; n = -1; break; default: printfPQExpBuffer(&conn->errorMessage, libpq_gettext("unrecognized SSL error code: %d\n"), err); /* assume the connection is broken */ result_errno = ECONNRESET; n = -1; break; } RESTORE_SIGPIPE(conn, spinfo); } else #endif /* USE_SSL */ { n = recv(conn->sock, ptr, len, 0); if (n < 0) { result_errno = SOCK_ERRNO; /* Set error message if appropriate */ switch (result_errno) { #ifdef EAGAIN case EAGAIN: #endif #if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN)) case EWOULDBLOCK: #endif case EINTR: /* no error message, caller is expected to retry */ break; #ifdef ECONNRESET case ECONNRESET: printfPQExpBuffer(&conn->errorMessage, libpq_gettext( "server closed the connection unexpectedly\n" "\tThis probably means the server terminated abnormally\n" "\tbefore or while processing the request.\n")); break; #endif default: printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not receive data from server: %s\n"), SOCK_STRERROR(result_errno, sebuf, sizeof(sebuf))); break; } } } /* ensure we return the intended errno to caller */ SOCK_ERRNO_SET(result_errno); return n; } /* * Write data to a secure connection. * * On failure, this function is responsible for putting a suitable message * into conn->errorMessage. The caller must still inspect errno, but only * to determine whether to continue/retry after error. */ ssize_t pqsecure_write(PGconn *conn, const void *ptr, size_t len) { ssize_t n; int result_errno = 0; char sebuf[256]; DECLARE_SIGPIPE_INFO(spinfo); #ifdef USE_SSL if (conn->ssl) { int err; DISABLE_SIGPIPE(conn, spinfo, return -1); SOCK_ERRNO_SET(0); n = SSL_write(conn->ssl, ptr, len); err = SSL_get_error(conn->ssl, n); switch (err) { case SSL_ERROR_NONE: if (n < 0) { /* Not supposed to happen, so we don't translate the msg */ printfPQExpBuffer(&conn->errorMessage, "SSL_write failed but did not provide error information\n"); /* assume the connection is broken */ result_errno = ECONNRESET; } break; case SSL_ERROR_WANT_READ: /* * Returning 0 here causes caller to wait for write-ready, * which is not really the right thing, but it's the best we * can do. */ n = 0; break; case SSL_ERROR_WANT_WRITE: n = 0; break; case SSL_ERROR_SYSCALL: if (n < 0) { result_errno = SOCK_ERRNO; REMEMBER_EPIPE(spinfo, result_errno == EPIPE); if (result_errno == EPIPE || result_errno == ECONNRESET) printfPQExpBuffer(&conn->errorMessage, libpq_gettext( "server closed the connection unexpectedly\n" "\tThis probably means the server terminated abnormally\n" "\tbefore or while processing the request.\n")); else printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL SYSCALL error: %s\n"), SOCK_STRERROR(result_errno, sebuf, sizeof(sebuf))); } else { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL SYSCALL error: EOF detected\n")); /* assume the connection is broken */ result_errno = ECONNRESET; n = -1; } break; case SSL_ERROR_SSL: { char *errm = SSLerrmessage(); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL error: %s\n"), errm); SSLerrfree(errm); /* assume the connection is broken */ result_errno = ECONNRESET; n = -1; break; } case SSL_ERROR_ZERO_RETURN: /* * Per OpenSSL documentation, this error code is only returned * for a clean connection closure, so we should not report it * as a server crash. */ printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL connection has been closed unexpectedly\n")); result_errno = ECONNRESET; n = -1; break; default: printfPQExpBuffer(&conn->errorMessage, libpq_gettext("unrecognized SSL error code: %d\n"), err); /* assume the connection is broken */ result_errno = ECONNRESET; n = -1; break; } } else #endif /* USE_SSL */ { int flags = 0; #ifdef MSG_NOSIGNAL if (conn->sigpipe_flag) flags |= MSG_NOSIGNAL; retry_masked: #endif /* MSG_NOSIGNAL */ DISABLE_SIGPIPE(conn, spinfo, return -1); n = send(conn->sock, ptr, len, flags); if (n < 0) { result_errno = SOCK_ERRNO; /* * If we see an EINVAL, it may be because MSG_NOSIGNAL isn't * available on this machine. So, clear sigpipe_flag so we don't * try the flag again, and retry the send(). */ #ifdef MSG_NOSIGNAL if (flags != 0 && result_errno == EINVAL) { conn->sigpipe_flag = false; flags = 0; goto retry_masked; } #endif /* MSG_NOSIGNAL */ /* Set error message if appropriate */ switch (result_errno) { #ifdef EAGAIN case EAGAIN: #endif #if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN)) case EWOULDBLOCK: #endif case EINTR: /* no error message, caller is expected to retry */ break; case EPIPE: /* Set flag for EPIPE */ REMEMBER_EPIPE(spinfo, true); /* FALL THRU */ #ifdef ECONNRESET case ECONNRESET: #endif printfPQExpBuffer(&conn->errorMessage, libpq_gettext( "server closed the connection unexpectedly\n" "\tThis probably means the server terminated abnormally\n" "\tbefore or while processing the request.\n")); break; default: printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not send data to server: %s\n"), SOCK_STRERROR(result_errno, sebuf, sizeof(sebuf))); break; } } } RESTORE_SIGPIPE(conn, spinfo); /* ensure we return the intended errno to caller */ SOCK_ERRNO_SET(result_errno); return n; } /* ------------------------------------------------------------ */ /* SSL specific code */ /* ------------------------------------------------------------ */ #ifdef USE_SSL /* * Certificate verification callback * * This callback allows us to log intermediate problems during * verification, but there doesn't seem to be a clean way to get * our PGconn * structure. So we can't log anything! * * This callback also allows us to override the default acceptance * criteria (e.g., accepting self-signed or expired certs), but * for now we accept the default checks. */ static int verify_cb(int ok, X509_STORE_CTX *ctx) { return ok; } /* * Check if a wildcard certificate matches the server hostname. * * The rule for this is: * 1. We only match the '*' character as wildcard * 2. We match only wildcards at the start of the string * 3. The '*' character does *not* match '.', meaning that we match only * a single pathname component. * 4. We don't support more than one '*' in a single pattern. * * This is roughly in line with RFC2818, but contrary to what most browsers * appear to be implementing (point 3 being the difference) * * Matching is always case-insensitive, since DNS is case insensitive. */ static int wildcard_certificate_match(const char *pattern, const char *string) { int lenpat = strlen(pattern); int lenstr = strlen(string); /* If we don't start with a wildcard, it's not a match (rule 1 & 2) */ if (lenpat < 3 || pattern[0] != '*' || pattern[1] != '.') return 0; if (lenpat > lenstr) /* If pattern is longer than the string, we can never match */ return 0; if (pg_strcasecmp(pattern + 1, string + lenstr - lenpat + 1) != 0) /* * If string does not end in pattern (minus the wildcard), we don't * match */ return 0; if (strchr(string, '.') < string + lenstr - lenpat) /* * If there is a dot left of where the pattern started to match, we * don't match (rule 3) */ return 0; /* String ended with pattern, and didn't have a dot before, so we match */ return 1; } /* * Verify that common name resolves to peer. */ static bool verify_peer_name_matches_certificate(PGconn *conn) { /* * If told not to verify the peer name, don't do it. Return true * indicating that the verification was successful. */ if (strcmp(conn->sslmode, "verify-full") != 0) return true; if (!(conn->pghost && conn->pghost[0] != '\0')) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("host name must be specified for a verified SSL connection\n")); return false; } else { /* * Compare CN to originally given hostname. * * XXX: Should support alternate names here */ if (pg_strcasecmp(conn->peer_cn, conn->pghost) == 0) /* Exact name match */ return true; else if (wildcard_certificate_match(conn->peer_cn, conn->pghost)) /* Matched wildcard certificate */ return true; else { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("server common name \"%s\" does not match host name \"%s\"\n"), conn->peer_cn, conn->pghost); return false; } } } #ifdef ENABLE_THREAD_SAFETY /* * Callback functions for OpenSSL internal locking */ static unsigned long pq_threadidcallback(void) { /* * This is not standards-compliant. pthread_self() returns pthread_t, and * shouldn't be cast to unsigned long, but CRYPTO_set_id_callback requires * it, so we have to do it. */ return (unsigned long) pthread_self(); } static pthread_mutex_t *pq_lockarray; static void pq_lockingcallback(int mode, int n, const char *file, int line) { if (mode & CRYPTO_LOCK) { if (pthread_mutex_lock(&pq_lockarray[n])) PGTHREAD_ERROR("failed to lock mutex"); } else { if (pthread_mutex_unlock(&pq_lockarray[n])) PGTHREAD_ERROR("failed to unlock mutex"); } } #endif /* ENABLE_THREAD_SAFETY */ /* * Initialize SSL system, in particular creating the SSL_context object * that will be shared by all SSL-using connections in this process. * * In threadsafe mode, this includes setting up libcrypto callback functions * to do thread locking. * * If the caller has told us (through PQinitOpenSSL) that he's taking care * of libcrypto, we expect that callbacks are already set, and won't try to * override it. * * The conn parameter is only used to be able to pass back an error * message - no connection-local setup is made here. * * Returns 0 if OK, -1 on failure (with a message in conn->errorMessage). */ static int init_ssl_system(PGconn *conn) { #ifdef ENABLE_THREAD_SAFETY #ifdef WIN32 /* Also see similar code in fe-connect.c, default_threadlock() */ if (ssl_config_mutex == NULL) { while (InterlockedExchange(&win32_ssl_create_mutex, 1) == 1) /* loop, another thread own the lock */ ; if (ssl_config_mutex == NULL) { if (pthread_mutex_init(&ssl_config_mutex, NULL)) return -1; } InterlockedExchange(&win32_ssl_create_mutex, 0); } #endif if (pthread_mutex_lock(&ssl_config_mutex)) return -1; if (pq_init_crypto_lib) { /* * If necessary, set up an array to hold locks for libcrypto. * libcrypto will tell us how big to make this array. */ if (pq_lockarray == NULL) { int i; pq_lockarray = malloc(sizeof(pthread_mutex_t) * CRYPTO_num_locks()); if (!pq_lockarray) { pthread_mutex_unlock(&ssl_config_mutex); return -1; } for (i = 0; i < CRYPTO_num_locks(); i++) { if (pthread_mutex_init(&pq_lockarray[i], NULL)) { free(pq_lockarray); pq_lockarray = NULL; pthread_mutex_unlock(&ssl_config_mutex); return -1; } } } if (ssl_open_connections++ == 0) { /* These are only required for threaded libcrypto applications */ CRYPTO_set_id_callback(pq_threadidcallback); CRYPTO_set_locking_callback(pq_lockingcallback); } } #endif /* ENABLE_THREAD_SAFETY */ if (!SSL_context) { if (pq_init_ssl_lib) { #if SSLEAY_VERSION_NUMBER >= 0x00907000L OPENSSL_config(NULL); #endif SSL_library_init(); SSL_load_error_strings(); } SSL_context = SSL_CTX_new(TLSv1_method()); if (!SSL_context) { char *err = SSLerrmessage(); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not create SSL context: %s\n"), err); SSLerrfree(err); #ifdef ENABLE_THREAD_SAFETY pthread_mutex_unlock(&ssl_config_mutex); #endif return -1; } /* * Disable OpenSSL's moving-write-buffer sanity check, because it * causes unnecessary failures in nonblocking send cases. */ SSL_CTX_set_mode(SSL_context, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); } #ifdef ENABLE_THREAD_SAFETY pthread_mutex_unlock(&ssl_config_mutex); #endif return 0; } /* * This function is needed because if the libpq library is unloaded * from the application, the callback functions will no longer exist when * libcrypto is used by other parts of the system. For this reason, * we unregister the callback functions when the last libpq * connection is closed. (The same would apply for OpenSSL callbacks * if we had any.) * * Callbacks are only set when we're compiled in threadsafe mode, so * we only need to remove them in this case. */ static void destroy_ssl_system(void) { #ifdef ENABLE_THREAD_SAFETY /* Mutex is created in initialize_ssl_system() */ if (pthread_mutex_lock(&ssl_config_mutex)) return; if (pq_init_crypto_lib && ssl_open_connections > 0) --ssl_open_connections; if (pq_init_crypto_lib && ssl_open_connections == 0) { /* No connections left, unregister libcrypto callbacks */ CRYPTO_set_locking_callback(NULL); CRYPTO_set_id_callback(NULL); /* * We don't free the lock array. If we get another connection in this * process, we will just re-use it with the existing mutexes. * * This means we leak a little memory on repeated load/unload of the * library. */ } pthread_mutex_unlock(&ssl_config_mutex); #endif } /* * Initialize (potentially) per-connection SSL data, namely the * client certificate, private key, and trusted CA certs. * * conn->ssl must already be created. It receives the connection's client * certificate and private key. Note however that certificates also get * loaded into the SSL_context object, and are therefore accessible to all * connections in this process. This should be OK as long as there aren't * any hash collisions among the certs. * * Returns 0 if OK, -1 on failure (with a message in conn->errorMessage). */ static int initialize_SSL(PGconn *conn) { struct stat buf; char homedir[MAXPGPATH]; char fnbuf[MAXPGPATH]; char sebuf[256]; bool have_homedir; bool have_cert; EVP_PKEY *pkey = NULL; /* * We'll need the home directory if any of the relevant parameters are * defaulted. If pqGetHomeDirectory fails, act as though none of the * files could be found. */ if (!(conn->sslcert && strlen(conn->sslcert) > 0) || !(conn->sslkey && strlen(conn->sslkey) > 0) || !(conn->sslrootcert && strlen(conn->sslrootcert) > 0) || !(conn->sslcrl && strlen(conn->sslcrl) > 0)) have_homedir = pqGetHomeDirectory(homedir, sizeof(homedir)); else /* won't need it */ have_homedir = false; /* Read the client certificate file */ if (conn->sslcert && strlen(conn->sslcert) > 0) strncpy(fnbuf, conn->sslcert, sizeof(fnbuf)); else if (have_homedir) snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, USER_CERT_FILE); else fnbuf[0] = '\0'; if (fnbuf[0] == '\0') { /* no home directory, proceed without a client cert */ have_cert = false; } else if (stat(fnbuf, &buf) != 0) { /* * If file is not present, just go on without a client cert; server * might or might not accept the connection. Any other error, * however, is grounds for complaint. */ if (errno != ENOENT) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not open certificate file \"%s\": %s\n"), fnbuf, pqStrerror(errno, sebuf, sizeof(sebuf))); return -1; } have_cert = false; } else { /* * Cert file exists, so load it. Since OpenSSL doesn't provide the * equivalent of "SSL_use_certificate_chain_file", we actually have to * load the file twice. The first call loads any extra certs after * the first one into chain-cert storage associated with the * SSL_context. The second call loads the first cert (only) into the * SSL object, where it will be correctly paired with the private key * we load below. We do it this way so that each connection * understands which subject cert to present, in case different * sslcert settings are used for different connections in the same * process. */ if (SSL_CTX_use_certificate_chain_file(SSL_context, fnbuf) != 1) { char *err = SSLerrmessage(); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not read certificate file \"%s\": %s\n"), fnbuf, err); SSLerrfree(err); return -1; } if (SSL_use_certificate_file(conn->ssl, fnbuf, SSL_FILETYPE_PEM) != 1) { char *err = SSLerrmessage(); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not read certificate file \"%s\": %s\n"), fnbuf, err); SSLerrfree(err); return -1; } /* need to load the associated private key, too */ have_cert = true; } /* * Read the SSL key. If a key is specified, treat it as an engine:key * combination if there is colon present - we don't support files with * colon in the name. The exception is if the second character is a colon, * in which case it can be a Windows filename with drive specification. */ if (have_cert && conn->sslkey && strlen(conn->sslkey) > 0) { #ifdef USE_SSL_ENGINE if (strchr(conn->sslkey, ':') #ifdef WIN32 && conn->sslkey[1] != ':' #endif ) { /* Colon, but not in second character, treat as engine:key */ char *engine_str = strdup(conn->sslkey); char *engine_colon = strchr(engine_str, ':'); *engine_colon = '\0'; /* engine_str now has engine name */ engine_colon++; /* engine_colon now has key name */ conn->engine = ENGINE_by_id(engine_str); if (conn->engine == NULL) { char *err = SSLerrmessage(); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not load SSL engine \"%s\": %s\n"), engine_str, err); SSLerrfree(err); free(engine_str); return -1; } if (ENGINE_init(conn->engine) == 0) { char *err = SSLerrmessage(); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not initialize SSL engine \"%s\": %s\n"), engine_str, err); SSLerrfree(err); ENGINE_free(conn->engine); conn->engine = NULL; free(engine_str); return -1; } pkey = ENGINE_load_private_key(conn->engine, engine_colon, NULL, NULL); if (pkey == NULL) { char *err = SSLerrmessage(); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not read private SSL key \"%s\" from engine \"%s\": %s\n"), engine_colon, engine_str, err); SSLerrfree(err); ENGINE_finish(conn->engine); ENGINE_free(conn->engine); conn->engine = NULL; free(engine_str); return -1; } if (SSL_use_PrivateKey(conn->ssl, pkey) != 1) { char *err = SSLerrmessage(); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not load private SSL key \"%s\" from engine \"%s\": %s\n"), engine_colon, engine_str, err); SSLerrfree(err); ENGINE_finish(conn->engine); ENGINE_free(conn->engine); conn->engine = NULL; free(engine_str); return -1; } free(engine_str); fnbuf[0] = '\0'; /* indicate we're not going to load from a * file */ } else #endif /* USE_SSL_ENGINE */ { /* PGSSLKEY is not an engine, treat it as a filename */ strncpy(fnbuf, conn->sslkey, sizeof(fnbuf)); } } else if (have_homedir) { /* No PGSSLKEY specified, load default file */ snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, USER_KEY_FILE); } else fnbuf[0] = '\0'; if (have_cert && fnbuf[0] != '\0') { /* read the client key from file */ if (stat(fnbuf, &buf) != 0) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("certificate present, but not private key file \"%s\"\n"), fnbuf); return -1; } #ifndef WIN32 if (!S_ISREG(buf.st_mode) || buf.st_mode & (S_IRWXG | S_IRWXO)) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("private key file \"%s\" has group or world access; permissions should be u=rw (0600) or less\n"), fnbuf); return -1; } #endif if (SSL_use_PrivateKey_file(conn->ssl, fnbuf, SSL_FILETYPE_PEM) != 1) { char *err = SSLerrmessage(); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not load private key file \"%s\": %s\n"), fnbuf, err); SSLerrfree(err); return -1; } } /* verify that the cert and key go together */ if (have_cert && SSL_check_private_key(conn->ssl) != 1) { char *err = SSLerrmessage(); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("certificate does not match private key file \"%s\": %s\n"), fnbuf, err); SSLerrfree(err); return -1; } /* * If the root cert file exists, load it so we can perform certificate * verification. If sslmode is "verify-full" we will also do further * verification after the connection has been completed. */ if (conn->sslrootcert && strlen(conn->sslrootcert) > 0) strncpy(fnbuf, conn->sslrootcert, sizeof(fnbuf)); else if (have_homedir) snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, ROOT_CERT_FILE); else fnbuf[0] = '\0'; if (fnbuf[0] != '\0' && stat(fnbuf, &buf) == 0) { X509_STORE *cvstore; if (SSL_CTX_load_verify_locations(SSL_context, fnbuf, NULL) != 1) { char *err = SSLerrmessage(); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not read root certificate file \"%s\": %s\n"), fnbuf, err); SSLerrfree(err); return -1; } if ((cvstore = SSL_CTX_get_cert_store(SSL_context)) != NULL) { if (conn->sslcrl && strlen(conn->sslcrl) > 0) strncpy(fnbuf, conn->sslcrl, sizeof(fnbuf)); else if (have_homedir) snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, ROOT_CRL_FILE); else fnbuf[0] = '\0'; /* Set the flags to check against the complete CRL chain */ if (fnbuf[0] != '\0' && X509_STORE_load_locations(cvstore, fnbuf, NULL) == 1) { /* OpenSSL 0.96 does not support X509_V_FLAG_CRL_CHECK */ #ifdef X509_V_FLAG_CRL_CHECK X509_STORE_set_flags(cvstore, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); #else char *err = SSLerrmessage(); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL library does not support CRL certificates (file \"%s\")\n"), fnbuf); SSLerrfree(err); return -1; #endif } /* if not found, silently ignore; we do not require CRL */ } SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, verify_cb); } else { /* * stat() failed; assume root file doesn't exist. If sslmode is * verify-ca or verify-full, this is an error. Otherwise, continue * without performing any server cert verification. */ if (conn->sslmode[0] == 'v') /* "verify-ca" or "verify-full" */ { /* * The only way to reach here with an empty filename is if * pqGetHomeDirectory failed. That's a sufficiently unusual case * that it seems worth having a specialized error message for it. */ if (fnbuf[0] == '\0') printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not get home directory to locate root certificate file\n" "Either provide the file or change sslmode to disable server certificate verification.\n")); else printfPQExpBuffer(&conn->errorMessage, libpq_gettext("root certificate file \"%s\" does not exist\n" "Either provide the file or change sslmode to disable server certificate verification.\n"), fnbuf); return -1; } } return 0; } static void destroySSL(void) { destroy_ssl_system(); } /* * Attempt to negotiate SSL connection. */ static PostgresPollingStatusType open_client_SSL(PGconn *conn) { int r; r = SSL_connect(conn->ssl); if (r <= 0) { int err = SSL_get_error(conn->ssl, r); switch (err) { case SSL_ERROR_WANT_READ: return PGRES_POLLING_READING; case SSL_ERROR_WANT_WRITE: return PGRES_POLLING_WRITING; case SSL_ERROR_SYSCALL: { char sebuf[256]; if (r == -1) printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL SYSCALL error: %s\n"), SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); else printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL SYSCALL error: EOF detected\n")); close_SSL(conn); return PGRES_POLLING_FAILED; } case SSL_ERROR_SSL: { char *err = SSLerrmessage(); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL error: %s\n"), err); SSLerrfree(err); close_SSL(conn); return PGRES_POLLING_FAILED; } default: printfPQExpBuffer(&conn->errorMessage, libpq_gettext("unrecognized SSL error code: %d\n"), err); close_SSL(conn); return PGRES_POLLING_FAILED; } } /* * We already checked the server certificate in initialize_SSL() using * SSL_CTX_set_verify(), if root.crt exists. */ /* pull out server distinguished and common names */ conn->peer = SSL_get_peer_certificate(conn->ssl); if (conn->peer == NULL) { char *err = SSLerrmessage(); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("certificate could not be obtained: %s\n"), err); SSLerrfree(err); close_SSL(conn); return PGRES_POLLING_FAILED; } X509_NAME_oneline(X509_get_subject_name(conn->peer), conn->peer_dn, sizeof(conn->peer_dn)); conn->peer_dn[sizeof(conn->peer_dn) - 1] = '\0'; r = X509_NAME_get_text_by_NID(X509_get_subject_name(conn->peer), NID_commonName, conn->peer_cn, SM_USER); conn->peer_cn[SM_USER] = '\0'; /* buffer is SM_USER+1 chars! */ if (r == -1) { /* Unable to get the CN, set it to blank so it can't be used */ conn->peer_cn[0] = '\0'; } else { /* * Reject embedded NULLs in certificate common name to prevent attacks * like CVE-2009-4034. */ if (r != strlen(conn->peer_cn)) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL certificate's common name contains embedded null\n")); close_SSL(conn); return PGRES_POLLING_FAILED; } } if (!verify_peer_name_matches_certificate(conn)) { close_SSL(conn); return PGRES_POLLING_FAILED; } /* SSL handshake is complete */ return PGRES_POLLING_OK; } /* * Close SSL connection. */ static void close_SSL(PGconn *conn) { if (conn->ssl) { DECLARE_SIGPIPE_INFO(spinfo); DISABLE_SIGPIPE(conn, spinfo, (void) 0); SSL_shutdown(conn->ssl); SSL_free(conn->ssl); conn->ssl = NULL; pqsecure_destroy(); /* We have to assume we got EPIPE */ REMEMBER_EPIPE(spinfo, true); RESTORE_SIGPIPE(conn, spinfo); } if (conn->peer) { X509_free(conn->peer); conn->peer = NULL; } #ifdef USE_SSL_ENGINE if (conn->engine) { ENGINE_finish(conn->engine); ENGINE_free(conn->engine); conn->engine = NULL; } #endif } /* * Obtain reason string for last SSL error * * Some caution is needed here since ERR_reason_error_string will * return NULL if it doesn't recognize the error code. We don't * want to return NULL ever. */ static char ssl_nomem[] = "out of memory allocating error description"; #define SSL_ERR_LEN 128 static char * SSLerrmessage(void) { unsigned long errcode; const char *errreason; char *errbuf; errbuf = malloc(SSL_ERR_LEN); if (!errbuf) return ssl_nomem; errcode = ERR_get_error(); if (errcode == 0) { snprintf(errbuf, SSL_ERR_LEN, libpq_gettext("no SSL error reported")); return errbuf; } errreason = ERR_reason_error_string(errcode); if (errreason != NULL) { strlcpy(errbuf, errreason, SSL_ERR_LEN); return errbuf; } snprintf(errbuf, SSL_ERR_LEN, libpq_gettext("SSL error code %lu"), errcode); return errbuf; } static void SSLerrfree(char *buf) { if (buf != ssl_nomem) free(buf); } /* * Return pointer to OpenSSL object. */ void * PQgetssl(PGconn *conn) { if (!conn) return NULL; return conn->ssl; } #else /* !USE_SSL */ void * PQgetssl(PGconn *conn) { return NULL; } #endif /* USE_SSL */ #if defined(ENABLE_THREAD_SAFETY) && !defined(WIN32) /* * Block SIGPIPE for this thread. This prevents send()/write() from exiting * the application. */ int pq_block_sigpipe(sigset_t *osigset, bool *sigpipe_pending) { sigset_t sigpipe_sigset; sigset_t sigset; sigemptyset(&sigpipe_sigset); sigaddset(&sigpipe_sigset, SIGPIPE); /* Block SIGPIPE and save previous mask for later reset */ SOCK_ERRNO_SET(pthread_sigmask(SIG_BLOCK, &sigpipe_sigset, osigset)); if (SOCK_ERRNO) return -1; /* We can have a pending SIGPIPE only if it was blocked before */ if (sigismember(osigset, SIGPIPE)) { /* Is there a pending SIGPIPE? */ if (sigpending(&sigset) != 0) return -1; if (sigismember(&sigset, SIGPIPE)) *sigpipe_pending = true; else *sigpipe_pending = false; } else *sigpipe_pending = false; return 0; } /* * Discard any pending SIGPIPE and reset the signal mask. * * Note: we are effectively assuming here that the C library doesn't queue * up multiple SIGPIPE events. If it did, then we'd accidentally leave * ours in the queue when an event was already pending and we got another. * As long as it doesn't queue multiple events, we're OK because the caller * can't tell the difference. * * The caller should say got_epipe = FALSE if it is certain that it * didn't get an EPIPE error; in that case we'll skip the clear operation * and things are definitely OK, queuing or no. If it got one or might have * gotten one, pass got_epipe = TRUE. * * We do not want this to change errno, since if it did that could lose * the error code from a preceding send(). We essentially assume that if * we were able to do pq_block_sigpipe(), this can't fail. */ void pq_reset_sigpipe(sigset_t *osigset, bool sigpipe_pending, bool got_epipe) { int save_errno = SOCK_ERRNO; int signo; sigset_t sigset; /* Clear SIGPIPE only if none was pending */ if (got_epipe && !sigpipe_pending) { if (sigpending(&sigset) == 0 && sigismember(&sigset, SIGPIPE)) { sigset_t sigpipe_sigset; sigemptyset(&sigpipe_sigset); sigaddset(&sigpipe_sigset, SIGPIPE); sigwait(&sigpipe_sigset, &signo); } } /* Restore saved block mask */ pthread_sigmask(SIG_SETMASK, osigset, NULL); SOCK_ERRNO_SET(save_errno); } #endif /* ENABLE_THREAD_SAFETY && !WIN32 */ RPostgreSQL/src/libpq/inet_aton.c0000644000176000001440000000774212124517222016461 0ustar ripleyusers/* src/port/inet_aton.c * * This inet_aton() function was taken from the GNU C library and * incorporated into Postgres for those systems which do not have this * routine in their standard C libraries. * * The function was been extracted whole from the file inet_aton.c in * Release 5.3.12 of the Linux C library, which is derived from the * GNU C library, by Bryan Henderson in October 1996. The copyright * notice from that file is below. */ /* * Copyright (c) 1983, 1990, 1993 * The Regents of the University of California. All rights 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. Neither the name of the University 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 REGENTS 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 REGENTS 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. */ #include "c.h" #include #include /* * Check whether "cp" is a valid ascii representation * of an Internet address and convert to a binary address. * Returns 1 if the address is valid, 0 if not. * This replaces inet_addr, the return value from which * cannot distinguish between failure and a local broadcast address. */ int inet_aton(const char *cp, struct in_addr * addr) { unsigned int val; int base, n; char c; u_int parts[4]; u_int *pp = parts; for (;;) { /* * Collect number up to ``.''. Values are specified as for C: 0x=hex, * 0=octal, other=decimal. */ val = 0; base = 10; if (*cp == '0') { if (*++cp == 'x' || *cp == 'X') base = 16, cp++; else base = 8; } while ((c = *cp) != '\0') { if (isdigit((unsigned char) c)) { val = (val * base) + (c - '0'); cp++; continue; } if (base == 16 && isxdigit((unsigned char) c)) { val = (val << 4) + (c + 10 - (islower((unsigned char) c) ? 'a' : 'A')); cp++; continue; } break; } if (*cp == '.') { /* * Internet format: a.b.c.d a.b.c (with c treated as 16-bits) * a.b (with b treated as 24 bits) */ if (pp >= parts + 3 || val > 0xff) return 0; *pp++ = val, cp++; } else break; } /* * Check for trailing junk. */ while (*cp) if (!isspace((unsigned char) *cp++)) return 0; /* * Concoct the address according to the number of parts specified. */ n = pp - parts + 1; switch (n) { case 1: /* a -- 32 bits */ break; case 2: /* a.b -- 8.24 bits */ if (val > 0xffffff) return 0; val |= parts[0] << 24; break; case 3: /* a.b.c -- 8.8.16 bits */ if (val > 0xffff) return 0; val |= (parts[0] << 24) | (parts[1] << 16); break; case 4: /* a.b.c.d -- 8.8.8.8 bits */ if (val > 0xff) return 0; val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); break; } if (addr) addr->s_addr = htonl(val); return 1; } RPostgreSQL/src/libpq/getaddrinfo.h0000644000176000001440000000754012124517222016770 0ustar ripleyusers/*------------------------------------------------------------------------- * * getaddrinfo.h * Support getaddrinfo() on platforms that don't have it. * * Note: we use our own routines on platforms that don't HAVE_STRUCT_ADDRINFO, * whether or not the library routine getaddrinfo() can be found. This * policy is needed because on some platforms a manually installed libbind.a * may provide getaddrinfo(), yet the system headers may not provide the * struct definitions needed to call it. To avoid conflict with the libbind * definition in such cases, we rename our routines to pg_xxx() via macros. * * This code will also work on platforms where struct addrinfo is defined * in the system headers but no getaddrinfo() can be located. * * Copyright (c) 2003-2011, PostgreSQL Global Development Group * * src/include/getaddrinfo.h * *------------------------------------------------------------------------- */ #ifndef GETADDRINFO_H #define GETADDRINFO_H #include #include /* Various macros that ought to be in , but might not be */ #ifndef EAI_FAIL #ifndef WIN32 #define EAI_BADFLAGS (-1) #define EAI_NONAME (-2) #define EAI_AGAIN (-3) #define EAI_FAIL (-4) #define EAI_FAMILY (-6) #define EAI_SOCKTYPE (-7) #define EAI_SERVICE (-8) #define EAI_MEMORY (-10) #define EAI_SYSTEM (-11) #else /* WIN32 */ #ifdef WIN32_ONLY_COMPILER #ifndef WSA_NOT_ENOUGH_MEMORY #define WSA_NOT_ENOUGH_MEMORY (WSAENOBUFS) #endif #ifndef __BORLANDC__ #define WSATYPE_NOT_FOUND (WSABASEERR+109) #endif #endif #define EAI_AGAIN WSATRY_AGAIN #define EAI_BADFLAGS WSAEINVAL #define EAI_FAIL WSANO_RECOVERY #define EAI_FAMILY WSAEAFNOSUPPORT #define EAI_MEMORY WSA_NOT_ENOUGH_MEMORY #define EAI_NODATA WSANO_DATA #define EAI_NONAME WSAHOST_NOT_FOUND #define EAI_SERVICE WSATYPE_NOT_FOUND #define EAI_SOCKTYPE WSAESOCKTNOSUPPORT #endif /* !WIN32 */ #endif /* !EAI_FAIL */ #ifndef AI_PASSIVE #define AI_PASSIVE 0x0001 #endif #ifndef AI_NUMERICHOST /* * some platforms don't support AI_NUMERICHOST; define as zero if using * the system version of getaddrinfo... */ #if defined(HAVE_STRUCT_ADDRINFO) && defined(HAVE_GETADDRINFO) #define AI_NUMERICHOST 0 #else #define AI_NUMERICHOST 0x0004 #endif #endif #ifndef NI_NUMERICHOST #define NI_NUMERICHOST 1 #endif #ifndef NI_NUMERICSERV #define NI_NUMERICSERV 2 #endif #ifndef NI_MAXHOST #define NI_MAXHOST 1025 #endif #ifndef NI_MAXSERV #define NI_MAXSERV 32 #endif #ifndef HAVE_STRUCT_ADDRINFO #ifndef WIN32 struct addrinfo { int ai_flags; int ai_family; int ai_socktype; int ai_protocol; size_t ai_addrlen; struct sockaddr *ai_addr; char *ai_canonname; struct addrinfo *ai_next; }; #else /* * The order of the structure elements on Win32 doesn't match the * order specified in the standard, but we have to match it for * IPv6 to work. */ struct addrinfo { int ai_flags; int ai_family; int ai_socktype; int ai_protocol; size_t ai_addrlen; char *ai_canonname; struct sockaddr *ai_addr; struct addrinfo *ai_next; }; #endif #endif /* HAVE_STRUCT_ADDRINFO */ #ifndef HAVE_GETADDRINFO /* Rename private copies per comments above */ #ifdef getaddrinfo #undef getaddrinfo #endif #define getaddrinfo pg_getaddrinfo #ifdef freeaddrinfo #undef freeaddrinfo #endif #define freeaddrinfo pg_freeaddrinfo #ifdef gai_strerror #undef gai_strerror #endif #define gai_strerror pg_gai_strerror #ifdef getnameinfo #undef getnameinfo #endif #define getnameinfo pg_getnameinfo extern int getaddrinfo(const char *node, const char *service, const struct addrinfo * hints, struct addrinfo ** res); extern void freeaddrinfo(struct addrinfo * res); extern const char *gai_strerror(int errcode); extern int getnameinfo(const struct sockaddr * sa, int salen, char *node, int nodelen, char *service, int servicelen, int flags); #endif /* HAVE_GETADDRINFO */ #endif /* GETADDRINFO_H */ RPostgreSQL/src/libpq/thread.c0000644000176000001440000001051512124517222015740 0ustar ripleyusers/*------------------------------------------------------------------------- * * thread.c * * Prototypes and macros around system calls, used to help make * threaded libraries reentrant and safe to use from threaded applications. * * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * * src/port/thread.c * *------------------------------------------------------------------------- */ #include "c.h" #include /* * Threading sometimes requires specially-named versions of functions * that return data in static buffers, like strerror_r() instead of * strerror(). Other operating systems use pthread_setspecific() * and pthread_getspecific() internally to allow standard library * functions to return static data to threaded applications. And some * operating systems have neither. * * Additional confusion exists because many operating systems that * use pthread_setspecific/pthread_getspecific() also have *_r versions * of standard library functions for compatibility with operating systems * that require them. However, internally, these *_r functions merely * call the thread-safe standard library functions. * * For example, BSD/OS 4.3 uses Bind 8.2.3 for getpwuid(). Internally, * getpwuid() calls pthread_setspecific/pthread_getspecific() to return * static data to the caller in a thread-safe manner. However, BSD/OS * also has getpwuid_r(), which merely calls getpwuid() and shifts * around the arguments to match the getpwuid_r() function declaration. * Therefore, while BSD/OS has getpwuid_r(), it isn't required. It also * doesn't have strerror_r(), so we can't fall back to only using *_r * functions for threaded programs. * * The current setup is to try threading in this order: * * use *_r function names if they exit * (*_THREADSAFE=yes) * use non-*_r functions if they are thread-safe * * One thread-safe solution for gethostbyname() might be to use getaddrinfo(). * * Run src/test/thread to test if your operating system has thread-safe * non-*_r functions. */ /* * Wrapper around strerror and strerror_r to use the former if it is * available and also return a more useful value (the error string). */ char * pqStrerror(int errnum, char *strerrbuf, size_t buflen) { #if defined(FRONTEND) && defined(ENABLE_THREAD_SAFETY) && defined(HAVE_STRERROR_R) /* reentrant strerror_r is available */ #ifdef STRERROR_R_INT /* SUSv3 version */ if (strerror_r(errnum, strerrbuf, buflen) == 0) return strerrbuf; else return "Unknown error"; #else /* GNU libc */ return strerror_r(errnum, strerrbuf, buflen); #endif #else /* no strerror_r() available, just use strerror */ strlcpy(strerrbuf, strerror(errnum), buflen); return strerrbuf; #endif } /* * Wrapper around getpwuid() or getpwuid_r() to mimic POSIX getpwuid_r() * behaviour, if it is not available or required. */ #ifndef WIN32 int pqGetpwuid(uid_t uid, struct passwd * resultbuf, char *buffer, size_t buflen, struct passwd ** result) { #if defined(FRONTEND) && defined(ENABLE_THREAD_SAFETY) && defined(HAVE_GETPWUID_R) #ifdef GETPWUID_R_5ARG /* POSIX version */ getpwuid_r(uid, resultbuf, buffer, buflen, result); #else /* * Early POSIX draft of getpwuid_r() returns 'struct passwd *'. * getpwuid_r(uid, resultbuf, buffer, buflen) */ *result = getpwuid_r(uid, resultbuf, buffer, buflen); #endif #else /* no getpwuid_r() available, just use getpwuid() */ *result = getpwuid(uid); #endif return (*result == NULL) ? -1 : 0; } #endif /* * Wrapper around gethostbyname() or gethostbyname_r() to mimic * POSIX gethostbyname_r() behaviour, if it is not available or required. * This function is called _only_ by our getaddinfo() portability function. */ #ifndef HAVE_GETADDRINFO int pqGethostbyname(const char *name, struct hostent * resultbuf, char *buffer, size_t buflen, struct hostent ** result, int *herrno) { #if defined(FRONTEND) && defined(ENABLE_THREAD_SAFETY) && defined(HAVE_GETHOSTBYNAME_R) /* * broken (well early POSIX draft) gethostbyname_r() which returns 'struct * hostent *' */ *result = gethostbyname_r(name, resultbuf, buffer, buflen, herrno); return (*result == NULL) ? -1 : 0; #else /* no gethostbyname_r(), just use gethostbyname() */ *result = gethostbyname(name); if (*result != NULL) *herrno = h_errno; if (*result != NULL) return 0; else return -1; #endif } #endif RPostgreSQL/src/libpq/fe-misc.c0000644000176000001440000006671312124517222016027 0ustar ripleyusers/*------------------------------------------------------------------------- * * FILE * fe-misc.c * * DESCRIPTION * miscellaneous useful functions * * The communication routines here are analogous to the ones in * backend/libpq/pqcomm.c and backend/libpq/pqcomprim.c, but operate * in the considerably different environment of the frontend libpq. * In particular, we work with a bare nonblock-mode socket, rather than * a stdio stream, so that we can avoid unwanted blocking of the application. * * XXX: MOVE DEBUG PRINTOUT TO HIGHER LEVEL. As is, block and restart * will cause repeat printouts. * * We must speak the same transmitted data representations as the backend * routines. * * * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION * src/interfaces/libpq/fe-misc.c * *------------------------------------------------------------------------- */ #include "postgres_fe.h" #include #include #include #include #ifdef WIN32 #include "win32.h" #else #include #include #endif #ifdef HAVE_POLL_H #include #endif #ifdef HAVE_SYS_POLL_H #include #endif #ifdef HAVE_SYS_SELECT_H #include #endif #include "libpq-fe.h" #include "libpq-int.h" #include "pqsignal.h" #include "mb/pg_wchar.h" #include "pg_config_paths.h" static int pqPutMsgBytes(const void *buf, size_t len, PGconn *conn); static int pqSendSome(PGconn *conn, int len); static int pqSocketCheck(PGconn *conn, int forRead, int forWrite, time_t end_time); static int pqSocketPoll(int sock, int forRead, int forWrite, time_t end_time); /* * PQlibVersion: return the libpq version number */ int PQlibVersion(void) { return PG_VERSION_NUM; } /* * fputnbytes: print exactly N bytes to a file * * We avoid using %.*s here because it can misbehave if the data * is not valid in what libc thinks is the prevailing encoding. */ static void fputnbytes(FILE *f, const char *str, size_t n) { while (n-- > 0) fputc(*str++, f); } /* * pqGetc: get 1 character from the connection * * All these routines return 0 on success, EOF on error. * Note that for the Get routines, EOF only means there is not enough * data in the buffer, not that there is necessarily a hard error. */ int pqGetc(char *result, PGconn *conn) { if (conn->inCursor >= conn->inEnd) return EOF; *result = conn->inBuffer[conn->inCursor++]; if (conn->Pfdebug) fprintf(conn->Pfdebug, "From backend> %c\n", *result); return 0; } /* * pqPutc: write 1 char to the current message */ int pqPutc(char c, PGconn *conn) { if (pqPutMsgBytes(&c, 1, conn)) return EOF; if (conn->Pfdebug) fprintf(conn->Pfdebug, "To backend> %c\n", c); return 0; } /* * pqGets[_append]: * get a null-terminated string from the connection, * and store it in an expansible PQExpBuffer. * If we run out of memory, all of the string is still read, * but the excess characters are silently discarded. */ static int pqGets_internal(PQExpBuffer buf, PGconn *conn, bool resetbuffer) { /* Copy conn data to locals for faster search loop */ char *inBuffer = conn->inBuffer; int inCursor = conn->inCursor; int inEnd = conn->inEnd; int slen; while (inCursor < inEnd && inBuffer[inCursor]) inCursor++; if (inCursor >= inEnd) return EOF; slen = inCursor - conn->inCursor; if (resetbuffer) resetPQExpBuffer(buf); appendBinaryPQExpBuffer(buf, inBuffer + conn->inCursor, slen); conn->inCursor = ++inCursor; if (conn->Pfdebug) fprintf(conn->Pfdebug, "From backend> \"%s\"\n", buf->data); return 0; } int pqGets(PQExpBuffer buf, PGconn *conn) { return pqGets_internal(buf, conn, true); } int pqGets_append(PQExpBuffer buf, PGconn *conn) { return pqGets_internal(buf, conn, false); } /* * pqPuts: write a null-terminated string to the current message */ int pqPuts(const char *s, PGconn *conn) { if (pqPutMsgBytes(s, strlen(s) + 1, conn)) return EOF; if (conn->Pfdebug) fprintf(conn->Pfdebug, "To backend> \"%s\"\n", s); return 0; } /* * pqGetnchar: * get a string of exactly len bytes in buffer s, no null termination */ int pqGetnchar(char *s, size_t len, PGconn *conn) { if (len > (size_t) (conn->inEnd - conn->inCursor)) return EOF; memcpy(s, conn->inBuffer + conn->inCursor, len); /* no terminating null */ conn->inCursor += len; if (conn->Pfdebug) { fprintf(conn->Pfdebug, "From backend (%lu)> ", (unsigned long) len); fputnbytes(conn->Pfdebug, s, len); fprintf(conn->Pfdebug, "\n"); } return 0; } /* * pqPutnchar: * write exactly len bytes to the current message */ int pqPutnchar(const char *s, size_t len, PGconn *conn) { if (pqPutMsgBytes(s, len, conn)) return EOF; if (conn->Pfdebug) { fprintf(conn->Pfdebug, "To backend> "); fputnbytes(conn->Pfdebug, s, len); fprintf(conn->Pfdebug, "\n"); } return 0; } /* * pqGetInt * read a 2 or 4 byte integer and convert from network byte order * to local byte order */ int pqGetInt(int *result, size_t bytes, PGconn *conn) { uint16 tmp2; uint32 tmp4; switch (bytes) { case 2: if (conn->inCursor + 2 > conn->inEnd) return EOF; memcpy(&tmp2, conn->inBuffer + conn->inCursor, 2); conn->inCursor += 2; *result = (int) ntohs(tmp2); break; case 4: if (conn->inCursor + 4 > conn->inEnd) return EOF; memcpy(&tmp4, conn->inBuffer + conn->inCursor, 4); conn->inCursor += 4; *result = (int) ntohl(tmp4); break; default: pqInternalNotice(&conn->noticeHooks, "integer of size %lu not supported by pqGetInt", (unsigned long) bytes); return EOF; } if (conn->Pfdebug) fprintf(conn->Pfdebug, "From backend (#%lu)> %d\n", (unsigned long) bytes, *result); return 0; } /* * pqPutInt * write an integer of 2 or 4 bytes, converting from host byte order * to network byte order. */ int pqPutInt(int value, size_t bytes, PGconn *conn) { uint16 tmp2; uint32 tmp4; switch (bytes) { case 2: tmp2 = htons((uint16) value); if (pqPutMsgBytes((const char *) &tmp2, 2, conn)) return EOF; break; case 4: tmp4 = htonl((uint32) value); if (pqPutMsgBytes((const char *) &tmp4, 4, conn)) return EOF; break; default: pqInternalNotice(&conn->noticeHooks, "integer of size %lu not supported by pqPutInt", (unsigned long) bytes); return EOF; } if (conn->Pfdebug) fprintf(conn->Pfdebug, "To backend (%lu#)> %d\n", (unsigned long) bytes, value); return 0; } /* * Make sure conn's output buffer can hold bytes_needed bytes (caller must * include already-stored data into the value!) * * Returns 0 on success, EOF if failed to enlarge buffer */ int pqCheckOutBufferSpace(size_t bytes_needed, PGconn *conn) { int newsize = conn->outBufSize; char *newbuf; if (bytes_needed <= (size_t) newsize) return 0; /* * If we need to enlarge the buffer, we first try to double it in size; if * that doesn't work, enlarge in multiples of 8K. This avoids thrashing * the malloc pool by repeated small enlargements. * * Note: tests for newsize > 0 are to catch integer overflow. */ do { newsize *= 2; } while (newsize > 0 && bytes_needed > (size_t) newsize); if (newsize > 0 && bytes_needed <= (size_t) newsize) { newbuf = realloc(conn->outBuffer, newsize); if (newbuf) { /* realloc succeeded */ conn->outBuffer = newbuf; conn->outBufSize = newsize; return 0; } } newsize = conn->outBufSize; do { newsize += 8192; } while (newsize > 0 && bytes_needed > (size_t) newsize); if (newsize > 0 && bytes_needed <= (size_t) newsize) { newbuf = realloc(conn->outBuffer, newsize); if (newbuf) { /* realloc succeeded */ conn->outBuffer = newbuf; conn->outBufSize = newsize; return 0; } } /* realloc failed. Probably out of memory */ printfPQExpBuffer(&conn->errorMessage, "cannot allocate memory for output buffer\n"); return EOF; } /* * Make sure conn's input buffer can hold bytes_needed bytes (caller must * include already-stored data into the value!) * * Returns 0 on success, EOF if failed to enlarge buffer */ int pqCheckInBufferSpace(size_t bytes_needed, PGconn *conn) { int newsize = conn->inBufSize; char *newbuf; if (bytes_needed <= (size_t) newsize) return 0; /* * If we need to enlarge the buffer, we first try to double it in size; if * that doesn't work, enlarge in multiples of 8K. This avoids thrashing * the malloc pool by repeated small enlargements. * * Note: tests for newsize > 0 are to catch integer overflow. */ do { newsize *= 2; } while (newsize > 0 && bytes_needed > (size_t) newsize); if (newsize > 0 && bytes_needed <= (size_t) newsize) { newbuf = realloc(conn->inBuffer, newsize); if (newbuf) { /* realloc succeeded */ conn->inBuffer = newbuf; conn->inBufSize = newsize; return 0; } } newsize = conn->inBufSize; do { newsize += 8192; } while (newsize > 0 && bytes_needed > (size_t) newsize); if (newsize > 0 && bytes_needed <= (size_t) newsize) { newbuf = realloc(conn->inBuffer, newsize); if (newbuf) { /* realloc succeeded */ conn->inBuffer = newbuf; conn->inBufSize = newsize; return 0; } } /* realloc failed. Probably out of memory */ printfPQExpBuffer(&conn->errorMessage, "cannot allocate memory for input buffer\n"); return EOF; } /* * pqPutMsgStart: begin construction of a message to the server * * msg_type is the message type byte, or 0 for a message without type byte * (only startup messages have no type byte) * * force_len forces the message to have a length word; otherwise, we add * a length word if protocol 3. * * Returns 0 on success, EOF on error * * The idea here is that we construct the message in conn->outBuffer, * beginning just past any data already in outBuffer (ie, at * outBuffer+outCount). We enlarge the buffer as needed to hold the message. * When the message is complete, we fill in the length word (if needed) and * then advance outCount past the message, making it eligible to send. * * The state variable conn->outMsgStart points to the incomplete message's * length word: it is either outCount or outCount+1 depending on whether * there is a type byte. If we are sending a message without length word * (pre protocol 3.0 only), then outMsgStart is -1. The state variable * conn->outMsgEnd is the end of the data collected so far. */ int pqPutMsgStart(char msg_type, bool force_len, PGconn *conn) { int lenPos; int endPos; /* allow room for message type byte */ if (msg_type) endPos = conn->outCount + 1; else endPos = conn->outCount; /* do we want a length word? */ if (force_len || PG_PROTOCOL_MAJOR(conn->pversion) >= 3) { lenPos = endPos; /* allow room for message length */ endPos += 4; } else lenPos = -1; /* make sure there is room for message header */ if (pqCheckOutBufferSpace(endPos, conn)) return EOF; /* okay, save the message type byte if any */ if (msg_type) conn->outBuffer[conn->outCount] = msg_type; /* set up the message pointers */ conn->outMsgStart = lenPos; conn->outMsgEnd = endPos; /* length word, if needed, will be filled in by pqPutMsgEnd */ if (conn->Pfdebug) fprintf(conn->Pfdebug, "To backend> Msg %c\n", msg_type ? msg_type : ' '); return 0; } /* * pqPutMsgBytes: add bytes to a partially-constructed message * * Returns 0 on success, EOF on error */ static int pqPutMsgBytes(const void *buf, size_t len, PGconn *conn) { /* make sure there is room for it */ if (pqCheckOutBufferSpace(conn->outMsgEnd + len, conn)) return EOF; /* okay, save the data */ memcpy(conn->outBuffer + conn->outMsgEnd, buf, len); conn->outMsgEnd += len; /* no Pfdebug call here, caller should do it */ return 0; } /* * pqPutMsgEnd: finish constructing a message and possibly send it * * Returns 0 on success, EOF on error * * We don't actually send anything here unless we've accumulated at least * 8K worth of data (the typical size of a pipe buffer on Unix systems). * This avoids sending small partial packets. The caller must use pqFlush * when it's important to flush all the data out to the server. */ int pqPutMsgEnd(PGconn *conn) { if (conn->Pfdebug) fprintf(conn->Pfdebug, "To backend> Msg complete, length %u\n", conn->outMsgEnd - conn->outCount); /* Fill in length word if needed */ if (conn->outMsgStart >= 0) { uint32 msgLen = conn->outMsgEnd - conn->outMsgStart; msgLen = htonl(msgLen); memcpy(conn->outBuffer + conn->outMsgStart, &msgLen, 4); } /* Make message eligible to send */ conn->outCount = conn->outMsgEnd; if (conn->outCount >= 8192) { int toSend = conn->outCount - (conn->outCount % 8192); if (pqSendSome(conn, toSend) < 0) return EOF; /* in nonblock mode, don't complain if unable to send it all */ } return 0; } /* ---------- * pqReadData: read more data, if any is available * Possible return values: * 1: successfully loaded at least one more byte * 0: no data is presently available, but no error detected * -1: error detected (including EOF = connection closure); * conn->errorMessage set * NOTE: callers must not assume that pointers or indexes into conn->inBuffer * remain valid across this call! * ---------- */ int pqReadData(PGconn *conn) { int someread = 0; int nread; if (conn->sock < 0) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("connection not open\n")); return -1; } /* Left-justify any data in the buffer to make room */ if (conn->inStart < conn->inEnd) { if (conn->inStart > 0) { memmove(conn->inBuffer, conn->inBuffer + conn->inStart, conn->inEnd - conn->inStart); conn->inEnd -= conn->inStart; conn->inCursor -= conn->inStart; conn->inStart = 0; } } else { /* buffer is logically empty, reset it */ conn->inStart = conn->inCursor = conn->inEnd = 0; } /* * If the buffer is fairly full, enlarge it. We need to be able to enlarge * the buffer in case a single message exceeds the initial buffer size. We * enlarge before filling the buffer entirely so as to avoid asking the * kernel for a partial packet. The magic constant here should be large * enough for a TCP packet or Unix pipe bufferload. 8K is the usual pipe * buffer size, so... */ if (conn->inBufSize - conn->inEnd < 8192) { if (pqCheckInBufferSpace(conn->inEnd + (size_t) 8192, conn)) { /* * We don't insist that the enlarge worked, but we need some room */ if (conn->inBufSize - conn->inEnd < 100) return -1; /* errorMessage already set */ } } /* OK, try to read some data */ retry3: nread = pqsecure_read(conn, conn->inBuffer + conn->inEnd, conn->inBufSize - conn->inEnd); if (nread < 0) { if (SOCK_ERRNO == EINTR) goto retry3; /* Some systems return EAGAIN/EWOULDBLOCK for no data */ #ifdef EAGAIN if (SOCK_ERRNO == EAGAIN) return someread; #endif #if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN)) if (SOCK_ERRNO == EWOULDBLOCK) return someread; #endif /* We might get ECONNRESET here if using TCP and backend died */ #ifdef ECONNRESET if (SOCK_ERRNO == ECONNRESET) goto definitelyFailed; #endif /* pqsecure_read set the error message for us */ return -1; } if (nread > 0) { conn->inEnd += nread; /* * Hack to deal with the fact that some kernels will only give us back * 1 packet per recv() call, even if we asked for more and there is * more available. If it looks like we are reading a long message, * loop back to recv() again immediately, until we run out of data or * buffer space. Without this, the block-and-restart behavior of * libpq's higher levels leads to O(N^2) performance on long messages. * * Since we left-justified the data above, conn->inEnd gives the * amount of data already read in the current message. We consider * the message "long" once we have acquired 32k ... */ if (conn->inEnd > 32768 && (conn->inBufSize - conn->inEnd) >= 8192) { someread = 1; goto retry3; } return 1; } if (someread) return 1; /* got a zero read after successful tries */ /* * A return value of 0 could mean just that no data is now available, or * it could mean EOF --- that is, the server has closed the connection. * Since we have the socket in nonblock mode, the only way to tell the * difference is to see if select() is saying that the file is ready. * Grumble. Fortunately, we don't expect this path to be taken much, * since in normal practice we should not be trying to read data unless * the file selected for reading already. * * In SSL mode it's even worse: SSL_read() could say WANT_READ and then * data could arrive before we make the pqReadReady() test. So we must * play dumb and assume there is more data, relying on the SSL layer to * detect true EOF. */ #ifdef USE_SSL if (conn->ssl) return 0; #endif switch (pqReadReady(conn)) { case 0: /* definitely no data available */ return 0; case 1: /* ready for read */ break; default: printfPQExpBuffer(&conn->errorMessage, libpq_gettext( "server closed the connection unexpectedly\n" "\tThis probably means the server terminated abnormally\n" "\tbefore or while processing the request.\n")); goto definitelyFailed; } /* * Still not sure that it's EOF, because some data could have just * arrived. */ retry4: nread = pqsecure_read(conn, conn->inBuffer + conn->inEnd, conn->inBufSize - conn->inEnd); if (nread < 0) { if (SOCK_ERRNO == EINTR) goto retry4; /* Some systems return EAGAIN/EWOULDBLOCK for no data */ #ifdef EAGAIN if (SOCK_ERRNO == EAGAIN) return 0; #endif #if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN)) if (SOCK_ERRNO == EWOULDBLOCK) return 0; #endif /* We might get ECONNRESET here if using TCP and backend died */ #ifdef ECONNRESET if (SOCK_ERRNO == ECONNRESET) goto definitelyFailed; #endif /* pqsecure_read set the error message for us */ return -1; } if (nread > 0) { conn->inEnd += nread; return 1; } /* * OK, we are getting a zero read even though select() says ready. This * means the connection has been closed. Cope. Note that errorMessage * has been set already. */ definitelyFailed: conn->status = CONNECTION_BAD; /* No more connection to backend */ pqsecure_close(conn); closesocket(conn->sock); conn->sock = -1; return -1; } /* * pqSendSome: send data waiting in the output buffer. * * len is how much to try to send (typically equal to outCount, but may * be less). * * Return 0 on success, -1 on failure and 1 when not all data could be sent * because the socket would block and the connection is non-blocking. */ static int pqSendSome(PGconn *conn, int len) { char *ptr = conn->outBuffer; int remaining = conn->outCount; int result = 0; if (conn->sock < 0) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("connection not open\n")); return -1; } /* while there's still data to send */ while (len > 0) { int sent; #ifndef WIN32 sent = pqsecure_write(conn, ptr, len); #else /* * Windows can fail on large sends, per KB article Q201213. The * failure-point appears to be different in different versions of * Windows, but 64k should always be safe. */ sent = pqsecure_write(conn, ptr, Min(len, 65536)); #endif if (sent < 0) { /* Anything except EAGAIN/EWOULDBLOCK/EINTR is trouble */ switch (SOCK_ERRNO) { #ifdef EAGAIN case EAGAIN: break; #endif #if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN)) case EWOULDBLOCK: break; #endif case EINTR: continue; default: /* pqsecure_write set the error message for us */ /* * We used to close the socket here, but that's a bad idea * since there might be unread data waiting (typically, a * NOTICE message from the backend telling us it's * committing hara-kiri...). Leave the socket open until * pqReadData finds no more data can be read. But abandon * attempt to send data. */ conn->outCount = 0; return -1; } } else { ptr += sent; len -= sent; remaining -= sent; } if (len > 0) { /* * We didn't send it all, wait till we can send more. * * If the connection is in non-blocking mode we don't wait, but * return 1 to indicate that data is still pending. */ if (pqIsnonblocking(conn)) { result = 1; break; } /* * There are scenarios in which we can't send data because the * communications channel is full, but we cannot expect the server * to clear the channel eventually because it's blocked trying to * send data to us. (This can happen when we are sending a large * amount of COPY data, and the server has generated lots of * NOTICE responses.) To avoid a deadlock situation, we must be * prepared to accept and buffer incoming data before we try * again. Furthermore, it is possible that such incoming data * might not arrive until after we've gone to sleep. Therefore, * we wait for either read ready or write ready. */ if (pqReadData(conn) < 0) { result = -1; /* error message already set up */ break; } if (pqWait(TRUE, TRUE, conn)) { result = -1; break; } } } /* shift the remaining contents of the buffer */ if (remaining > 0) memmove(conn->outBuffer, ptr, remaining); conn->outCount = remaining; return result; } /* * pqFlush: send any data waiting in the output buffer * * Return 0 on success, -1 on failure and 1 when not all data could be sent * because the socket would block and the connection is non-blocking. */ int pqFlush(PGconn *conn) { if (conn->Pfdebug) fflush(conn->Pfdebug); if (conn->outCount > 0) return pqSendSome(conn, conn->outCount); return 0; } /* * pqWait: wait until we can read or write the connection socket * * JAB: If SSL enabled and used and forRead, buffered bytes short-circuit the * call to select(). * * We also stop waiting and return if the kernel flags an exception condition * on the socket. The actual error condition will be detected and reported * when the caller tries to read or write the socket. */ int pqWait(int forRead, int forWrite, PGconn *conn) { return pqWaitTimed(forRead, forWrite, conn, (time_t) -1); } /* * pqWaitTimed: wait, but not past finish_time. * * If finish_time is exceeded then we return failure (EOF). This is like * the response for a kernel exception because we don't want the caller * to try to read/write in that case. * * finish_time = ((time_t) -1) disables the wait limit. */ int pqWaitTimed(int forRead, int forWrite, PGconn *conn, time_t finish_time) { int result; result = pqSocketCheck(conn, forRead, forWrite, finish_time); if (result < 0) return EOF; /* errorMessage is already set */ if (result == 0) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("timeout expired\n")); return EOF; } return 0; } /* * pqReadReady: is select() saying the file is ready to read? * Returns -1 on failure, 0 if not ready, 1 if ready. */ int pqReadReady(PGconn *conn) { return pqSocketCheck(conn, 1, 0, (time_t) 0); } /* * pqWriteReady: is select() saying the file is ready to write? * Returns -1 on failure, 0 if not ready, 1 if ready. */ int pqWriteReady(PGconn *conn) { return pqSocketCheck(conn, 0, 1, (time_t) 0); } /* * Checks a socket, using poll or select, for data to be read, written, * or both. Returns >0 if one or more conditions are met, 0 if it timed * out, -1 if an error occurred. * * If SSL is in use, the SSL buffer is checked prior to checking the socket * for read data directly. */ static int pqSocketCheck(PGconn *conn, int forRead, int forWrite, time_t end_time) { int result; if (!conn) return -1; if (conn->sock < 0) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("socket not open\n")); return -1; } #ifdef USE_SSL /* Check for SSL library buffering read bytes */ if (forRead && conn->ssl && SSL_pending(conn->ssl) > 0) { /* short-circuit the select */ return 1; } #endif /* We will retry as long as we get EINTR */ do result = pqSocketPoll(conn->sock, forRead, forWrite, end_time); while (result < 0 && SOCK_ERRNO == EINTR); if (result < 0) { char sebuf[256]; printfPQExpBuffer(&conn->errorMessage, libpq_gettext("select() failed: %s\n"), SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); } return result; } /* * Check a file descriptor for read and/or write data, possibly waiting. * If neither forRead nor forWrite are set, immediately return a timeout * condition (without waiting). Return >0 if condition is met, 0 * if a timeout occurred, -1 if an error or interrupt occurred. * * Timeout is infinite if end_time is -1. Timeout is immediate (no blocking) * if end_time is 0 (or indeed, any time before now). */ static int pqSocketPoll(int sock, int forRead, int forWrite, time_t end_time) { /* We use poll(2) if available, otherwise select(2) */ #ifdef HAVE_POLL struct pollfd input_fd; int timeout_ms; if (!forRead && !forWrite) return 0; input_fd.fd = sock; input_fd.events = POLLERR; input_fd.revents = 0; if (forRead) input_fd.events |= POLLIN; if (forWrite) input_fd.events |= POLLOUT; /* Compute appropriate timeout interval */ if (end_time == ((time_t) -1)) timeout_ms = -1; else { time_t now = time(NULL); if (end_time > now) timeout_ms = (end_time - now) * 1000; else timeout_ms = 0; } return poll(&input_fd, 1, timeout_ms); #else /* !HAVE_POLL */ fd_set input_mask; fd_set output_mask; fd_set except_mask; struct timeval timeout; struct timeval *ptr_timeout; if (!forRead && !forWrite) return 0; FD_ZERO(&input_mask); FD_ZERO(&output_mask); FD_ZERO(&except_mask); if (forRead) FD_SET(sock, &input_mask); if (forWrite) FD_SET(sock, &output_mask); FD_SET(sock, &except_mask); /* Compute appropriate timeout interval */ if (end_time == ((time_t) -1)) ptr_timeout = NULL; else { time_t now = time(NULL); if (end_time > now) timeout.tv_sec = end_time - now; else timeout.tv_sec = 0; timeout.tv_usec = 0; ptr_timeout = &timeout; } return select(sock + 1, &input_mask, &output_mask, &except_mask, ptr_timeout); #endif /* HAVE_POLL */ } /* * A couple of "miscellaneous" multibyte related functions. They used * to be in fe-print.c but that file is doomed. */ /* * returns the byte length of the word beginning s, using the * specified encoding. */ int PQmblen(const char *s, int encoding) { return pg_encoding_mblen(encoding, s); } /* * returns the display length of the word beginning s, using the * specified encoding. */ int PQdsplen(const char *s, int encoding) { return pg_encoding_dsplen(encoding, s); } /* * Get encoding id from environment variable PGCLIENTENCODING. */ int PQenv2encoding(void) { char *str; int encoding = PG_SQL_ASCII; str = getenv("PGCLIENTENCODING"); if (str && *str != '\0') { encoding = pg_char_to_encoding(str); if (encoding < 0) encoding = PG_SQL_ASCII; } return encoding; } #ifdef ENABLE_NLS char * libpq_gettext(const char *msgid) { static bool already_bound = false; if (!already_bound) { /* dgettext() preserves errno, but bindtextdomain() doesn't */ #ifdef WIN32 int save_errno = GetLastError(); #else int save_errno = errno; #endif const char *ldir; already_bound = true; /* No relocatable lookup here because the binary could be anywhere */ ldir = getenv("PGLOCALEDIR"); if (!ldir) ldir = LOCALEDIR; bindtextdomain(PG_TEXTDOMAIN("libpq"), ldir); #ifdef WIN32 SetLastError(save_errno); #else errno = save_errno; #endif } return dgettext(PG_TEXTDOMAIN("libpq"), msgid); } #endif /* ENABLE_NLS */ RPostgreSQL/src/libpq/win32error.c0000644000176000001440000000552712124517222016514 0ustar ripleyusers/*------------------------------------------------------------------------- * * win32error.c * Map win32 error codes to errno values * * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * * IDENTIFICATION * src/port/win32error.c * *------------------------------------------------------------------------- */ #ifndef FRONTEND #include "postgres.h" #else #include "postgres_fe.h" #endif static const struct { DWORD winerr; int doserr; } doserrors[] = { { ERROR_INVALID_FUNCTION, EINVAL }, { ERROR_FILE_NOT_FOUND, ENOENT }, { ERROR_PATH_NOT_FOUND, ENOENT }, { ERROR_TOO_MANY_OPEN_FILES, EMFILE }, { ERROR_ACCESS_DENIED, EACCES }, { ERROR_INVALID_HANDLE, EBADF }, { ERROR_ARENA_TRASHED, ENOMEM }, { ERROR_NOT_ENOUGH_MEMORY, ENOMEM }, { ERROR_INVALID_BLOCK, ENOMEM }, { ERROR_BAD_ENVIRONMENT, E2BIG }, { ERROR_BAD_FORMAT, ENOEXEC }, { ERROR_INVALID_ACCESS, EINVAL }, { ERROR_INVALID_DATA, EINVAL }, { ERROR_INVALID_DRIVE, ENOENT }, { ERROR_CURRENT_DIRECTORY, EACCES }, { ERROR_NOT_SAME_DEVICE, EXDEV }, { ERROR_NO_MORE_FILES, ENOENT }, { ERROR_LOCK_VIOLATION, EACCES }, { ERROR_SHARING_VIOLATION, EACCES }, { ERROR_BAD_NETPATH, ENOENT }, { ERROR_NETWORK_ACCESS_DENIED, EACCES }, { ERROR_BAD_NET_NAME, ENOENT }, { ERROR_FILE_EXISTS, EEXIST }, { ERROR_CANNOT_MAKE, EACCES }, { ERROR_FAIL_I24, EACCES }, { ERROR_INVALID_PARAMETER, EINVAL }, { ERROR_NO_PROC_SLOTS, EAGAIN }, { ERROR_DRIVE_LOCKED, EACCES }, { ERROR_BROKEN_PIPE, EPIPE }, { ERROR_DISK_FULL, ENOSPC }, { ERROR_INVALID_TARGET_HANDLE, EBADF }, { ERROR_INVALID_HANDLE, EINVAL }, { ERROR_WAIT_NO_CHILDREN, ECHILD }, { ERROR_CHILD_NOT_COMPLETE, ECHILD }, { ERROR_DIRECT_ACCESS_HANDLE, EBADF }, { ERROR_NEGATIVE_SEEK, EINVAL }, { ERROR_SEEK_ON_DEVICE, EACCES }, { ERROR_DIR_NOT_EMPTY, ENOTEMPTY }, { ERROR_NOT_LOCKED, EACCES }, { ERROR_BAD_PATHNAME, ENOENT }, { ERROR_MAX_THRDS_REACHED, EAGAIN }, { ERROR_LOCK_FAILED, EACCES }, { ERROR_ALREADY_EXISTS, EEXIST }, { ERROR_FILENAME_EXCED_RANGE, ENOENT }, { ERROR_NESTING_NOT_ALLOWED, EAGAIN }, { ERROR_NOT_ENOUGH_QUOTA, ENOMEM } }; void _dosmaperr(unsigned long e) { int i; if (e == 0) { errno = 0; return; } for (i = 0; i < lengthof(doserrors); i++) { if (doserrors[i].winerr == e) { errno = doserrors[i].doserr; #ifndef FRONTEND ereport(DEBUG5, (errmsg_internal("mapped win32 error code %lu to %d", e, errno))); #elif FRONTEND_DEBUG fprintf(stderr, _("mapped win32 error code %lu to %d"), e, errno); #endif return; } } #ifndef FRONTEND ereport(LOG, (errmsg_internal("unrecognized win32 error code: %lu", e))); #else fprintf(stderr, _("unrecognized win32 error code: %lu"), e); #endif errno = EINVAL; return; } RPostgreSQL/src/libpq/pg_config_paths.h.darwin0000644000176000001440000000104011663173071021113 0ustar ripleyusers#define PGBINDIR "/usr/local/pgsql/bin" #define PGSHAREDIR "/usr/local/pgsql/share" #define SYSCONFDIR "/usr/local/pgsql/etc" #define INCLUDEDIR "/usr/local/pgsql/include" #define PKGINCLUDEDIR "/usr/local/pgsql/include" #define INCLUDEDIRSERVER "/usr/local/pgsql/include/server" #define LIBDIR "/usr/local/pgsql/lib" #define PKGLIBDIR "/usr/local/pgsql/lib" #define LOCALEDIR "/usr/local/pgsql/share/locale" #define DOCDIR "/usr/local/pgsql/share/doc/" #define HTMLDIR "/usr/local/pgsql/share/doc/" #define MANDIR "/usr/local/pgsql/share/man" RPostgreSQL/src/libpq/bcc32.mak0000644000176000001440000001644111660061757015732 0ustar ripleyusers# Makefile for Borland C++ 5.5 # Will build a Win32 static library libpq.lib # and a Win32 dynamic library libpq.dll with import library libpqdll.lib # Borland C++ base install directory goes here # BCB=c:\Borland\Bcc55 !IF "$(BCB)" == "" !MESSAGE You must edit bcc32.mak and define BCB at the top !ERROR misssing BCB !ENDIF !IF "$(__NMAKE__)" == "" !MESSAGE You must use the -N compatibility flag, e.g. make -N -f bcc32.make !ERROR missing -N !ENDIF !MESSAGE Building the Win32 DLL and Static Library... !MESSAGE !IF "$(CFG)" == "" CFG=Release !MESSAGE No configuration specified. Defaulting to Release. !MESSAGE !ELSE !MESSAGE Configuration "$(CFG)" !MESSAGE !ENDIF !IF "$(CFG)" != "Release" && "$(CFG)" != "Debug" !MESSAGE Invalid configuration "$(CFG)" specified. !MESSAGE You can specify a configuration when running MAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE make -N -DCFG=[Release | Debug] -f bcc32.mak !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "Release" (Win32 Release DLL and Static Library) !MESSAGE "Debug" (Win32 Debug DLL and Static Library) !MESSAGE !ERROR An invalid configuration was specified. !ENDIF !IF "$(OS)" == "Windows_NT" NULL= !ELSE NULL=nul !ENDIF !IF "$(CFG)" == "Debug" DEBUG=1 OUTDIR=.\Debug INTDIR=.\Debug !ELSE OUTDIR=.\Release INTDIR=.\Release !ENDIF OUTFILENAME=blibpq USERDEFINES=FRONTEND;NDEBUG;WIN32;_WINDOWS CPP=bcc32.exe CPP_PROJ = -I..\..\include\port\win32_msvc;$(BCB)\include;..\..\include;..\..\include\port\win32;..\..\port -n"$(INTDIR)" -WD -c -D$(USERDEFINES) -tWM \ -a8 -X -w-use -w-par -w-pia -w-csu -w-aus -w-ccc !IFDEF DEBUG CPP_PROJ = $(CPP_PROJ) -Od -r- -k -v -y -vi- -D_DEBUG !else CPP_PROJ = $(CPP_PROJ) -O -Oi -OS -DNDEBUG !endif ALL : config "$(OUTDIR)" "$(OUTDIR)\blibpq.dll" "$(OUTDIR)\blibpq.lib" CLEAN : -@erase "$(INTDIR)\getaddrinfo.obj" -@erase "$(INTDIR)\pgstrcasecmp.obj" -@erase "$(INTDIR)\thread.obj" -@erase "$(INTDIR)\inet_aton.obj" -@erase "$(INTDIR)\crypt.obj" -@erase "$(INTDIR)\noblock.obj" -@erase "$(INTDIR)\chklocale.obj" -@erase "$(INTDIR)\inet_net_ntop.obj" -@erase "$(INTDIR)\md5.obj" -@erase "$(INTDIR)\ip.obj" -@erase "$(INTDIR)\fe-auth.obj" -@erase "$(INTDIR)\fe-protocol2.obj" -@erase "$(INTDIR)\fe-protocol3.obj" -@erase "$(INTDIR)\fe-connect.obj" -@erase "$(INTDIR)\fe-exec.obj" -@erase "$(INTDIR)\fe-lobj.obj" -@erase "$(INTDIR)\fe-misc.obj" -@erase "$(INTDIR)\fe-print.obj" -@erase "$(INTDIR)\fe-secure.obj" -@erase "$(INTDIR)\libpq-events.obj" -@erase "$(INTDIR)\pqexpbuffer.obj" -@erase "$(INTDIR)\pqsignal.obj" -@erase "$(INTDIR)\win32.obj" -@erase "$(INTDIR)\wchar.obj" -@erase "$(INTDIR)\encnames.obj" -@erase "$(INTDIR)\pthread-win32.obj" -@erase "$(INTDIR)\snprintf.obj" -@erase "$(INTDIR)\strlcpy.obj" -@erase "$(INTDIR)\dirent.obj" -@erase "$(INTDIR)\dirmod.obj" -@erase "$(INTDIR)\pgsleep.obj" -@erase "$(INTDIR)\open.obj" -@erase "$(INTDIR)\win32error.obj" -@erase "$(OUTDIR)\$(OUTFILENAME).lib" -@erase "$(OUTDIR)\$(OUTFILENAME)dll.lib" -@erase "$(OUTDIR)\libpq.res" -@erase "$(OUTDIR)\$(OUTFILENAME).dll" -@erase "$(OUTDIR)\$(OUTFILENAME).tds" -@erase "$(INTDIR)\pg_config_paths.h" LIB32=tlib.exe LIB32_FLAGS= LIB32_OBJS= \ "$(INTDIR)\win32.obj" \ "$(INTDIR)\getaddrinfo.obj" \ "$(INTDIR)\pgstrcasecmp.obj" \ "$(INTDIR)\thread.obj" \ "$(INTDIR)\inet_aton.obj" \ "$(INTDIR)\crypt.obj" \ "$(INTDIR)\noblock.obj" \ "$(INTDIR)\chklocale.obj" \ "$(INTDIR)\inet_net_ntop.obj" \ "$(INTDIR)\md5.obj" \ "$(INTDIR)\ip.obj" \ "$(INTDIR)\fe-auth.obj" \ "$(INTDIR)\fe-protocol2.obj" \ "$(INTDIR)\fe-protocol3.obj" \ "$(INTDIR)\fe-connect.obj" \ "$(INTDIR)\fe-exec.obj" \ "$(INTDIR)\fe-lobj.obj" \ "$(INTDIR)\fe-misc.obj" \ "$(INTDIR)\fe-print.obj" \ "$(INTDIR)\fe-secure.obj" \ "$(INTDIR)\libpq-events.obj" \ "$(INTDIR)\pqexpbuffer.obj" \ "$(INTDIR)\pqsignal.obj" \ "$(INTDIR)\wchar.obj" \ "$(INTDIR)\encnames.obj" \ "$(INTDIR)\snprintf.obj" \ "$(INTDIR)\strlcpy.obj" \ "$(INTDIR)\dirent.obj" \ "$(INTDIR)\dirmod.obj" \ "$(INTDIR)\pgsleep.obj" \ "$(INTDIR)\open.obj" \ "$(INTDIR)\win32error.obj" \ "$(INTDIR)\pthread-win32.obj" config: ..\..\include\pg_config.h ..\..\include\pg_config_os.h pg_config_paths.h ..\..\include\pg_config.h: ..\..\include\pg_config.h.win32 copy ..\..\include\pg_config.h.win32 ..\..\include\pg_config.h ..\..\include\pg_config_os.h: ..\..\include\port\win32.h copy ..\..\include\port\win32.h ..\..\include\pg_config_os.h # Have to use \# so # isn't treated as a comment, but MSVC doesn't like this pg_config_paths.h: bcc32.mak echo \#define SYSCONFDIR "" > pg_config_paths.h "$(OUTDIR)" : @if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" RSC=brcc32.exe RSC_PROJ=-l 0x409 -i$(BCB)\include -fo"$(INTDIR)\libpq.res" LINK32=ilink32.exe LINK32_FLAGS = -Gn -L$(BCB)\lib;$(INTDIR); -x -Tpd -v # @<< is a Response file, http://www.opussoftware.com/tutorial/TutMakefile.htm "$(OUTDIR)\blibpq.dll": "$(OUTDIR)\blibpq.lib" "$(INTDIR)\libpq.res" blibpqdll.def $(LINK32) @<< $(LINK32_FLAGS) + c0d32.obj , + $@,, + "$(OUTDIR)\blibpq.lib" import32.lib cw32mt.lib, + blibpqdll.def,"$(INTDIR)\libpq.res" << implib -w "$(OUTDIR)\blibpqdll.lib" blibpqdll.def $@ "$(INTDIR)\libpq.res" : "$(INTDIR)" libpq-dist.rc $(RSC) $(RSC_PROJ) libpq-dist.rc "$(OUTDIR)\blibpq.lib": $(LIB32_OBJS) $(LIB32) $@ @<< +-"$(**: =" &^ +-")" << "$(INTDIR)\getaddrinfo.obj" : ..\..\port\getaddrinfo.c $(CPP) @<< $(CPP_PROJ) ..\..\port\getaddrinfo.c << "$(INTDIR)\pgstrcasecmp.obj" : ..\..\port\pgstrcasecmp.c $(CPP) @<< $(CPP_PROJ) ..\..\port\pgstrcasecmp.c << "$(INTDIR)\thread.obj" : ..\..\port\thread.c $(CPP) @<< $(CPP_PROJ) ..\..\port\thread.c << "$(INTDIR)\inet_aton.obj" : ..\..\port\inet_aton.c $(CPP) @<< $(CPP_PROJ) ..\..\port\inet_aton.c << "$(INTDIR)\crypt.obj" : ..\..\port\crypt.c $(CPP) @<< $(CPP_PROJ) ..\..\port\crypt.c << "$(INTDIR)\noblock.obj" : ..\..\port\noblock.c $(CPP) @<< $(CPP_PROJ) ..\..\port\noblock.c << "$(INTDIR)\chklocale.obj" : ..\..\port\chklocale.c $(CPP) @<< $(CPP_PROJ) ..\..\port\chklocale.c << "$(INTDIR)\inet_net_ntop.obj" : ..\..\port\inet_net_ntop.c $(CPP) @<< $(CPP_PROJ) ..\..\port\inet_net_ntop.c << "$(INTDIR)\md5.obj" : ..\..\backend\libpq\md5.c $(CPP) @<< $(CPP_PROJ) ..\..\backend\libpq\md5.c << "$(INTDIR)\ip.obj" : ..\..\backend\libpq\ip.c $(CPP) @<< $(CPP_PROJ) ..\..\backend\libpq\ip.c << "$(INTDIR)\wchar.obj" : ..\..\backend\utils\mb\wchar.c $(CPP) @<< $(CPP_PROJ) /I"." ..\..\backend\utils\mb\wchar.c << "$(INTDIR)\encnames.obj" : ..\..\backend\utils\mb\encnames.c $(CPP) @<< $(CPP_PROJ) /I"." ..\..\backend\utils\mb\encnames.c << "$(INTDIR)\snprintf.obj" : ..\..\port\snprintf.c $(CPP) @<< $(CPP_PROJ) /I"." ..\..\port\snprintf.c << "$(INTDIR)\strlcpy.obj" : ..\..\port\strlcpy.c $(CPP) @<< $(CPP_PROJ) /I"." ..\..\port\strlcpy.c << "$(INTDIR)\dirent.obj" : ..\..\port\dirent.c $(CPP) @<< $(CPP_PROJ) /I"." ..\..\port\dirent.c << "$(INTDIR)\dirmod.obj" : ..\..\port\dirmod.c $(CPP) @<< $(CPP_PROJ) /I"." ..\..\port\dirmod.c << "$(INTDIR)\pgsleep.obj" : ..\..\port\pgsleep.c $(CPP) @<< $(CPP_PROJ) /I"." ..\..\port\pgsleep.c << "$(INTDIR)\open.obj" : ..\..\port\open.c $(CPP) @<< $(CPP_PROJ) /I"." ..\..\port\open.c << "$(INTDIR)\win32error.obj" : ..\..\port\win32error.c $(CPP) @<< $(CPP_PROJ) /I"." ..\..\port\win32error.c << .c.obj: $(CPP) $(CPP_PROJ) $< RPostgreSQL/src/libpq/README0000644000176000001440000000015411660061757015216 0ustar ripleyuserssrc/interfaces/libpq/README This directory contains the C version of Libpq, the POSTGRES frontend library. RPostgreSQL/src/libpq/crypt.c0000644000176000001440000007303312124517222015636 0ustar ripleyusers/* src/port/crypt.c */ /* $NetBSD: crypt.c,v 1.18 2001/03/01 14:37:35 wiz Exp $ */ /* * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Tom Truscott. * * 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. Neither the name of the University 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 REGENTS 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 REGENTS 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. */ #if defined(LIBC_SCCS) && !defined(lint) #if 0 static char sccsid[] = "@(#)crypt.c 8.1.1.1 (Berkeley) 8/18/93"; #else __RCSID("$NetBSD: crypt.c,v 1.18 2001/03/01 14:37:35 wiz Exp $"); #endif #endif /* not lint */ #include "c.h" #include #ifndef WIN32 #include #endif static int des_setkey(const char *key); static int des_cipher(const char *in, char *out, long salt, int num_iter); /* * UNIX password, and DES, encryption. * By Tom Truscott, trt@rti.rti.org, * from algorithms by Robert W. Baldwin and James Gillogly. * * References: * "Mathematical Cryptology for Computer Scientists and Mathematicians," * by Wayne Patterson, 1987, ISBN 0-8476-7438-X. * * "Password Security: A Case History," R. Morris and Ken Thompson, * Communications of the ACM, vol. 22, pp. 594-597, Nov. 1979. * * "DES will be Totally Insecure within Ten Years," M.E. Hellman, * IEEE Spectrum, vol. 16, pp. 32-39, July 1979. */ /* ===== Configuration ==================== */ /* * define "MUST_ALIGN" if your compiler cannot load/store * long integers at arbitrary (e.g. odd) memory locations. * (Either that or never pass unaligned addresses to des_cipher!) */ /* #define MUST_ALIGN */ #ifdef CHAR_BITS #if CHAR_BITS != 8 #error C_block structure assumes 8 bit characters #endif #endif /* * define "B64" to be the declaration for a 64 bit integer. * XXX this feature is currently unused, see "endian" comment below. */ #define B64 __int64 /* * define "LARGEDATA" to get faster permutations, by using about 72 kilobytes * of lookup tables. This speeds up des_setkey() and des_cipher(), but has * little effect on crypt(). */ /* #define LARGEDATA */ /* compile with "-DSTATIC=void" when profiling */ #ifndef STATIC #define STATIC static void #endif /* * Define the "int32_t" type for integral type with a width of at least * 32 bits. */ typedef int int32_t; /* ==================================== */ #define _PASSWORD_EFMT1 '_' /* extended encryption format */ /* * Cipher-block representation (Bob Baldwin): * * DES operates on groups of 64 bits, numbered 1..64 (sigh). One * representation is to store one bit per byte in an array of bytes. Bit N of * the NBS spec is stored as the LSB of the Nth byte (index N-1) in the array. * Another representation stores the 64 bits in 8 bytes, with bits 1..8 in the * first byte, 9..16 in the second, and so on. The DES spec apparently has * bit 1 in the MSB of the first byte, but that is particularly noxious so we * bit-reverse each byte so that bit 1 is the LSB of the first byte, bit 8 is * the MSB of the first byte. Specifically, the 64-bit input data and key are * converted to LSB format, and the output 64-bit block is converted back into * MSB format. * * DES operates internally on groups of 32 bits which are expanded to 48 bits * by permutation E and shrunk back to 32 bits by the S boxes. To speed up * the computation, the expansion is applied only once, the expanded * representation is maintained during the encryption, and a compression * permutation is applied only at the end. To speed up the S-box lookups, * the 48 bits are maintained as eight 6 bit groups, one per byte, which * directly feed the eight S-boxes. Within each byte, the 6 bits are the * most significant ones. The low two bits of each byte are zero. (Thus, * bit 1 of the 48 bit E expansion is stored as the "4"-valued bit of the * first byte in the eight byte representation, bit 2 of the 48 bit value is * the "8"-valued bit, and so on.) In fact, a combined "SPE"-box lookup is * used, in which the output is the 64 bit result of an S-box lookup which * has been permuted by P and expanded by E, and is ready for use in the next * iteration. Two 32-bit wide tables, SPE[0] and SPE[1], are used for this * lookup. Since each byte in the 48 bit path is a multiple of four, indexed * lookup of SPE[0] and SPE[1] is simple and fast. The key schedule and * "salt" are also converted to this 8*(6+2) format. The SPE table size is * 8*64*8 = 4K bytes. * * To speed up bit-parallel operations (such as XOR), the 8 byte * representation is "union"ed with 32 bit values "i0" and "i1", and, on * machines which support it, a 64 bit value "b64". This data structure, * "C_block", has two problems. First, alignment restrictions must be * honored. Second, the byte-order (e.g. little-endian or big-endian) of * the architecture becomes visible. * * The byte-order problem is unfortunate, since on the one hand it is good * to have a machine-independent C_block representation (bits 1..8 in the * first byte, etc.), and on the other hand it is good for the LSB of the * first byte to be the LSB of i0. We cannot have both these things, so we * currently use the "little-endian" representation and avoid any multi-byte * operations that depend on byte order. This largely precludes use of the * 64-bit datatype since the relative order of i0 and i1 are unknown. It * also inhibits grouping the SPE table to look up 12 bits at a time. (The * 12 bits can be stored in a 16-bit field with 3 low-order zeroes and 1 * high-order zero, providing fast indexing into a 64-bit wide SPE.) On the * other hand, 64-bit datatypes are currently rare, and a 12-bit SPE lookup * requires a 128 kilobyte table, so perhaps this is not a big loss. * * Permutation representation (Jim Gillogly): * * A transformation is defined by its effect on each of the 8 bytes of the * 64-bit input. For each byte we give a 64-bit output that has the bits in * the input distributed appropriately. The transformation is then the OR * of the 8 sets of 64-bits. This uses 8*256*8 = 16K bytes of storage for * each transformation. Unless LARGEDATA is defined, however, a more compact * table is used which looks up 16 4-bit "chunks" rather than 8 8-bit chunks. * The smaller table uses 16*16*8 = 2K bytes for each transformation. This * is slower but tolerable, particularly for password encryption in which * the SPE transformation is iterated many times. The small tables total 9K * bytes, the large tables total 72K bytes. * * The transformations used are: * IE3264: MSB->LSB conversion, initial permutation, and expansion. * This is done by collecting the 32 even-numbered bits and applying * a 32->64 bit transformation, and then collecting the 32 odd-numbered * bits and applying the same transformation. Since there are only * 32 input bits, the IE3264 transformation table is half the size of * the usual table. * CF6464: Compression, final permutation, and LSB->MSB conversion. * This is done by two trivial 48->32 bit compressions to obtain * a 64-bit block (the bit numbering is given in the "CIFP" table) * followed by a 64->64 bit "cleanup" transformation. (It would * be possible to group the bits in the 64-bit block so that 2 * identical 32->32 bit transformations could be used instead, * saving a factor of 4 in space and possibly 2 in time, but * byte-ordering and other complications rear their ugly head. * Similar opportunities/problems arise in the key schedule * transforms.) * PC1ROT: MSB->LSB, PC1 permutation, rotate, and PC2 permutation. * This admittedly baroque 64->64 bit transformation is used to * produce the first code (in 8*(6+2) format) of the key schedule. * PC2ROT[0]: Inverse PC2 permutation, rotate, and PC2 permutation. * It would be possible to define 15 more transformations, each * with a different rotation, to generate the entire key schedule. * To save space, however, we instead permute each code into the * next by using a transformation that "undoes" the PC2 permutation, * rotates the code, and then applies PC2. Unfortunately, PC2 * transforms 56 bits into 48 bits, dropping 8 bits, so PC2 is not * invertible. We get around that problem by using a modified PC2 * which retains the 8 otherwise-lost bits in the unused low-order * bits of each byte. The low-order bits are cleared when the * codes are stored into the key schedule. * PC2ROT[1]: Same as PC2ROT[0], but with two rotations. * This is faster than applying PC2ROT[0] twice, * * The Bell Labs "salt" (Bob Baldwin): * * The salting is a simple permutation applied to the 48-bit result of E. * Specifically, if bit i (1 <= i <= 24) of the salt is set then bits i and * i+24 of the result are swapped. The salt is thus a 24 bit number, with * 16777216 possible values. (The original salt was 12 bits and could not * swap bits 13..24 with 36..48.) * * It is possible, but ugly, to warp the SPE table to account for the salt * permutation. Fortunately, the conditional bit swapping requires only * about four machine instructions and can be done on-the-fly with about an * 8% performance penalty. */ typedef union { unsigned char b[8]; struct { int32_t i0; int32_t i1; } b32; #if defined(B64) B64 b64; #endif } C_block; /* * Convert twenty-four-bit long in host-order * to six bits (and 2 low-order zeroes) per char little-endian format. */ #define TO_SIX_BIT(rslt, src) { \ C_block cvt; \ cvt.b[0] = src; src >>= 6; \ cvt.b[1] = src; src >>= 6; \ cvt.b[2] = src; src >>= 6; \ cvt.b[3] = src; \ rslt = (cvt.b32.i0 & 0x3f3f3f3fL) << 2; \ } /* * These macros may someday permit efficient use of 64-bit integers. */ #define ZERO(d,d0,d1) d0 = 0, d1 = 0 #define LOAD(d,d0,d1,bl) d0 = (bl).b32.i0, d1 = (bl).b32.i1 #define LOADREG(d,d0,d1,s,s0,s1) d0 = s0, d1 = s1 #define OR(d,d0,d1,bl) d0 |= (bl).b32.i0, d1 |= (bl).b32.i1 #define STORE(s,s0,s1,bl) (bl).b32.i0 = s0, (bl).b32.i1 = s1 #define DCL_BLOCK(d,d0,d1) int32_t d0, d1 #if defined(LARGEDATA) /* Waste memory like crazy. Also, do permutations in line */ #define LGCHUNKBITS 3 #define CHUNKBITS (1<> 4]; OR(D, D0, D1, *tp); p += (1 << CHUNKBITS); } while (--chars_in > 0); STORE(D, D0, D1, *out); } #endif /* LARGEDATA */ /* ===== (mostly) Standard DES Tables ==================== */ static const unsigned char IP[] = { /* initial permutation */ 58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4, 62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8, 57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3, 61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7, }; /* The final permutation is the inverse of IP - no table is necessary */ static const unsigned char ExpandTr[] = { /* expansion operation */ 32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9, 8, 9, 10, 11, 12, 13, 12, 13, 14, 15, 16, 17, 16, 17, 18, 19, 20, 21, 20, 21, 22, 23, 24, 25, 24, 25, 26, 27, 28, 29, 28, 29, 30, 31, 32, 1, }; static const unsigned char PC1[] = { /* permuted choice table 1 */ 57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36, 63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4, }; static const unsigned char Rotates[] = { /* PC1 rotation schedule */ 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1, }; /* note: each "row" of PC2 is left-padded with bits that make it invertible */ static const unsigned char PC2[] = { /* permuted choice table 2 */ 9, 18, 14, 17, 11, 24, 1, 5, 22, 25, 3, 28, 15, 6, 21, 10, 35, 38, 23, 19, 12, 4, 26, 8, 43, 54, 16, 7, 27, 20, 13, 2, 0, 0, 41, 52, 31, 37, 47, 55, 0, 0, 30, 40, 51, 45, 33, 48, 0, 0, 44, 49, 39, 56, 34, 53, 0, 0, 46, 42, 50, 36, 29, 32, }; static const unsigned char S[8][64] = { /* 48->32 bit substitution tables */ /* S[1] */ {14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7, 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8, 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0, 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13}, /* S[2] */ {15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10, 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5, 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15, 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9}, /* S[3] */ {10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8, 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1, 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7, 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12}, /* S[4] */ {7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15, 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9, 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4, 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14}, /* S[5] */ {2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9, 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6, 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14, 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3}, /* S[6] */ {12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11, 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8, 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6, 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13}, /* S[7] */ {4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1, 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6, 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2, 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12}, /* S[8] */ {13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7, 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2, 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8, 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11} }; static const unsigned char P32Tr[] = { /* 32-bit permutation function */ 16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10, 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25, }; static const unsigned char CIFP[] = { /* compressed/interleaved permutation */ 1, 2, 3, 4, 17, 18, 19, 20, 5, 6, 7, 8, 21, 22, 23, 24, 9, 10, 11, 12, 25, 26, 27, 28, 13, 14, 15, 16, 29, 30, 31, 32, 33, 34, 35, 36, 49, 50, 51, 52, 37, 38, 39, 40, 53, 54, 55, 56, 41, 42, 43, 44, 57, 58, 59, 60, 45, 46, 47, 48, 61, 62, 63, 64, }; static const unsigned char itoa64[] = /* 0..63 => ascii-64 */ "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; /* ===== Tables that are initialized at run time ==================== */ static unsigned char a64toi[128]; /* ascii-64 => 0..63 */ /* Initial key schedule permutation */ static C_block PC1ROT[64 / CHUNKBITS][1 << CHUNKBITS]; /* Subsequent key schedule rotation permutations */ static C_block PC2ROT[2][64 / CHUNKBITS][1 << CHUNKBITS]; /* Initial permutation/expansion table */ static C_block IE3264[32 / CHUNKBITS][1 << CHUNKBITS]; /* Table that combines the S, P, and E operations. */ static int32_t SPE[2][8][64]; /* compressed/interleaved => final permutation table */ static C_block CF6464[64 / CHUNKBITS][1 << CHUNKBITS]; /* ==================================== */ static C_block constdatablock; /* encryption constant */ static char cryptresult[1 + 4 + 4 + 11 + 1]; /* encrypted result */ extern char *__md5crypt(const char *, const char *); /* XXX */ extern char *__bcrypt(const char *, const char *); /* XXX */ /* * Return a pointer to static data consisting of the "setting" * followed by an encryption produced by the "key" and "setting". */ char * crypt(key, setting) const char *key; const char *setting; { char *encp; int32_t i; int t; int32_t salt; int num_iter, salt_size; C_block keyblock, rsltblock; #if 0 /* Non-DES encryption schemes hook in here. */ if (setting[0] == _PASSWORD_NONDES) { switch (setting[1]) { case '2': return (__bcrypt(key, setting)); case '1': default: return (__md5crypt(key, setting)); } } #endif for (i = 0; i < 8; i++) { if ((t = 2 * (unsigned char) (*key)) != 0) key++; keyblock.b[i] = t; } if (des_setkey((char *) keyblock.b)) /* also initializes "a64toi" */ return (NULL); encp = &cryptresult[0]; switch (*setting) { case _PASSWORD_EFMT1: /* * Involve the rest of the password 8 characters at a time. */ while (*key) { if (des_cipher((char *) (void *) &keyblock, (char *) (void *) &keyblock, 0L, 1)) return (NULL); for (i = 0; i < 8; i++) { if ((t = 2 * (unsigned char) (*key)) != 0) key++; keyblock.b[i] ^= t; } if (des_setkey((char *) keyblock.b)) return (NULL); } *encp++ = *setting++; /* get iteration count */ num_iter = 0; for (i = 4; --i >= 0;) { if ((t = (unsigned char) setting[i]) == '\0') t = '.'; encp[i] = t; num_iter = (num_iter << 6) | a64toi[t]; } setting += 4; encp += 4; salt_size = 4; break; default: num_iter = 25; salt_size = 2; } salt = 0; for (i = salt_size; --i >= 0;) { if ((t = (unsigned char) setting[i]) == '\0') t = '.'; encp[i] = t; salt = (salt << 6) | a64toi[t]; } encp += salt_size; if (des_cipher((char *) (void *) &constdatablock, (char *) (void *) &rsltblock, salt, num_iter)) return (NULL); /* * Encode the 64 cipher bits as 11 ascii characters. */ i = ((int32_t) ((rsltblock.b[0] << 8) | rsltblock.b[1]) << 8) | rsltblock.b[2]; encp[3] = itoa64[i & 0x3f]; i >>= 6; encp[2] = itoa64[i & 0x3f]; i >>= 6; encp[1] = itoa64[i & 0x3f]; i >>= 6; encp[0] = itoa64[i]; encp += 4; i = ((int32_t) ((rsltblock.b[3] << 8) | rsltblock.b[4]) << 8) | rsltblock.b[5]; encp[3] = itoa64[i & 0x3f]; i >>= 6; encp[2] = itoa64[i & 0x3f]; i >>= 6; encp[1] = itoa64[i & 0x3f]; i >>= 6; encp[0] = itoa64[i]; encp += 4; i = ((int32_t) ((rsltblock.b[6]) << 8) | rsltblock.b[7]) << 2; encp[2] = itoa64[i & 0x3f]; i >>= 6; encp[1] = itoa64[i & 0x3f]; i >>= 6; encp[0] = itoa64[i]; encp[3] = 0; return (cryptresult); } /* * The Key Schedule, filled in by des_setkey() or setkey(). */ #define KS_SIZE 16 static C_block KS[KS_SIZE]; static volatile int des_ready = 0; /* * Set up the key schedule from the key. */ static int des_setkey(key) const char *key; { DCL_BLOCK(K, K0, K1); C_block *ptabp; int i; if (!des_ready) init_des(); PERM6464(K, K0, K1, (unsigned char *) key, (C_block *) PC1ROT); key = (char *) &KS[0]; STORE(K & ~0x03030303L, K0 & ~0x03030303L, K1, *(C_block *) key); for (i = 1; i < 16; i++) { key += sizeof(C_block); STORE(K, K0, K1, *(C_block *) key); ptabp = (C_block *) PC2ROT[Rotates[i] - 1]; PERM6464(K, K0, K1, (unsigned char *) key, ptabp); STORE(K & ~0x03030303L, K0 & ~0x03030303L, K1, *(C_block *) key); } return (0); } /* * Encrypt (or decrypt if num_iter < 0) the 8 chars at "in" with abs(num_iter) * iterations of DES, using the given 24-bit salt and the pre-computed key * schedule, and store the resulting 8 chars at "out" (in == out is permitted). * * NOTE: the performance of this routine is critically dependent on your * compiler and machine architecture. */ static int des_cipher(in, out, salt, num_iter) const char *in; char *out; long salt; int num_iter; { /* variables that we want in registers, most important first */ #if defined(pdp11) int j; #endif int32_t L0, L1, R0, R1, k; C_block *kp; int ks_inc, loop_count; C_block B; L0 = salt; TO_SIX_BIT(salt, L0); /* convert to 4*(6+2) format */ #if defined(__vax__) || defined(pdp11) salt = ~salt; /* "x &~ y" is faster than "x & y". */ #define SALT (~salt) #else #define SALT salt #endif #if defined(MUST_ALIGN) B.b[0] = in[0]; B.b[1] = in[1]; B.b[2] = in[2]; B.b[3] = in[3]; B.b[4] = in[4]; B.b[5] = in[5]; B.b[6] = in[6]; B.b[7] = in[7]; LOAD(L, L0, L1, B); #else LOAD(L, L0, L1, *(C_block *) in); #endif LOADREG(R, R0, R1, L, L0, L1); L0 &= 0x55555555L; L1 &= 0x55555555L; L0 = (L0 << 1) | L1; /* L0 is the even-numbered input bits */ R0 &= 0xaaaaaaaaL; R1 = (R1 >> 1) & 0x55555555L; L1 = R0 | R1; /* L1 is the odd-numbered input bits */ STORE(L, L0, L1, B); PERM3264(L, L0, L1, B.b, (C_block *) IE3264); /* even bits */ PERM3264(R, R0, R1, B.b + 4, (C_block *) IE3264); /* odd bits */ if (num_iter >= 0) { /* encryption */ kp = &KS[0]; ks_inc = sizeof(*kp); } else { /* decryption */ num_iter = -num_iter; kp = &KS[KS_SIZE - 1]; ks_inc = -(long) sizeof(*kp); } while (--num_iter >= 0) { loop_count = 8; do { #define SPTAB(t, i) \ (*(int32_t *)((unsigned char *)(t) + (i)*(sizeof(int32_t)/4))) #if defined(gould) /* use this if B.b[i] is evaluated just once ... */ #define DOXOR(x,y,i) x^=SPTAB(SPE[0][i],B.b[i]); y^=SPTAB(SPE[1][i],B.b[i]); #else #if defined(pdp11) /* use this if your "long" int indexing is slow */ #define DOXOR(x,y,i) j=B.b[i]; x^=SPTAB(SPE[0][i],j); y^=SPTAB(SPE[1][i],j); #else /* use this if "k" is allocated to a register ... */ #define DOXOR(x,y,i) k=B.b[i]; x^=SPTAB(SPE[0][i],k); y^=SPTAB(SPE[1][i],k); #endif #endif #define CRUNCH(p0, p1, q0, q1) \ k = ((q0) ^ (q1)) & SALT; \ B.b32.i0 = k ^ (q0) ^ kp->b32.i0; \ B.b32.i1 = k ^ (q1) ^ kp->b32.i1; \ kp = (C_block *)((char *)kp+ks_inc); \ \ DOXOR(p0, p1, 0); \ DOXOR(p0, p1, 1); \ DOXOR(p0, p1, 2); \ DOXOR(p0, p1, 3); \ DOXOR(p0, p1, 4); \ DOXOR(p0, p1, 5); \ DOXOR(p0, p1, 6); \ DOXOR(p0, p1, 7); CRUNCH(L0, L1, R0, R1); CRUNCH(R0, R1, L0, L1); } while (--loop_count != 0); kp = (C_block *) ((char *) kp - (ks_inc * KS_SIZE)); /* swap L and R */ L0 ^= R0; L1 ^= R1; R0 ^= L0; R1 ^= L1; L0 ^= R0; L1 ^= R1; } /* store the encrypted (or decrypted) result */ L0 = ((L0 >> 3) & 0x0f0f0f0fL) | ((L1 << 1) & 0xf0f0f0f0L); L1 = ((R0 >> 3) & 0x0f0f0f0fL) | ((R1 << 1) & 0xf0f0f0f0L); STORE(L, L0, L1, B); PERM6464(L, L0, L1, B.b, (C_block *) CF6464); #if defined(MUST_ALIGN) STORE(L, L0, L1, B); out[0] = B.b[0]; out[1] = B.b[1]; out[2] = B.b[2]; out[3] = B.b[3]; out[4] = B.b[4]; out[5] = B.b[5]; out[6] = B.b[6]; out[7] = B.b[7]; #else STORE(L, L0, L1, *(C_block *) out); #endif return (0); } /* * Initialize various tables. This need only be done once. It could even be * done at compile time, if the compiler were capable of that sort of thing. */ STATIC init_des() { int i, j; int32_t k; int tableno; static unsigned char perm[64], tmp32[32]; /* "static" for speed */ /* static volatile long init_start = 0; not used */ /* * table that converts chars "./0-9A-Za-z"to integers 0-63. */ for (i = 0; i < 64; i++) a64toi[itoa64[i]] = i; /* * PC1ROT - bit reverse, then PC1, then Rotate, then PC2. */ for (i = 0; i < 64; i++) perm[i] = 0; for (i = 0; i < 64; i++) { if ((k = PC2[i]) == 0) continue; k += Rotates[0] - 1; if ((k % 28) < Rotates[0]) k -= 28; k = PC1[k]; if (k > 0) { k--; k = (k | 07) - (k & 07); k++; } perm[i] = k; } #ifdef DEBUG prtab("pc1tab", perm, 8); #endif init_perm(PC1ROT, perm, 8, 8); /* * PC2ROT - PC2 inverse, then Rotate (once or twice), then PC2. */ for (j = 0; j < 2; j++) { unsigned char pc2inv[64]; for (i = 0; i < 64; i++) perm[i] = pc2inv[i] = 0; for (i = 0; i < 64; i++) { if ((k = PC2[i]) == 0) continue; pc2inv[k - 1] = i + 1; } for (i = 0; i < 64; i++) { if ((k = PC2[i]) == 0) continue; k += j; if ((k % 28) <= j) k -= 28; perm[i] = pc2inv[k]; } #ifdef DEBUG prtab("pc2tab", perm, 8); #endif init_perm(PC2ROT[j], perm, 8, 8); } /* * Bit reverse, then initial permutation, then expansion. */ for (i = 0; i < 8; i++) { for (j = 0; j < 8; j++) { k = (j < 2) ? 0 : IP[ExpandTr[i * 6 + j - 2] - 1]; if (k > 32) k -= 32; else if (k > 0) k--; if (k > 0) { k--; k = (k | 07) - (k & 07); k++; } perm[i * 8 + j] = k; } } #ifdef DEBUG prtab("ietab", perm, 8); #endif init_perm(IE3264, perm, 4, 8); /* * Compression, then final permutation, then bit reverse. */ for (i = 0; i < 64; i++) { k = IP[CIFP[i] - 1]; if (k > 0) { k--; k = (k | 07) - (k & 07); k++; } perm[k - 1] = i + 1; } #ifdef DEBUG prtab("cftab", perm, 8); #endif init_perm(CF6464, perm, 8, 8); /* * SPE table */ for (i = 0; i < 48; i++) perm[i] = P32Tr[ExpandTr[i] - 1]; for (tableno = 0; tableno < 8; tableno++) { for (j = 0; j < 64; j++) { k = (((j >> 0) & 01) << 5) | (((j >> 1) & 01) << 3) | (((j >> 2) & 01) << 2) | (((j >> 3) & 01) << 1) | (((j >> 4) & 01) << 0) | (((j >> 5) & 01) << 4); k = S[tableno][k]; k = (((k >> 3) & 01) << 0) | (((k >> 2) & 01) << 1) | (((k >> 1) & 01) << 2) | (((k >> 0) & 01) << 3); for (i = 0; i < 32; i++) tmp32[i] = 0; for (i = 0; i < 4; i++) tmp32[4 * tableno + i] = (k >> i) & 01; k = 0; for (i = 24; --i >= 0;) k = (k << 1) | tmp32[perm[i] - 1]; TO_SIX_BIT(SPE[0][tableno][j], k); k = 0; for (i = 24; --i >= 0;) k = (k << 1) | tmp32[perm[i + 24] - 1]; TO_SIX_BIT(SPE[1][tableno][j], k); } } des_ready = 1; } /* * Initialize "perm" to represent transformation "p", which rearranges * (perhaps with expansion and/or contraction) one packed array of bits * (of size "chars_in" characters) into another array (of size "chars_out" * characters). * * "perm" must be all-zeroes on entry to this routine. */ STATIC init_perm(perm, p, chars_in, chars_out) C_block perm[64 / CHUNKBITS][1 << CHUNKBITS]; unsigned char p[64]; int chars_in, chars_out; { int i, j, k, l; for (k = 0; k < chars_out * 8; k++) { /* each output bit position */ l = p[k] - 1; /* where this bit comes from */ if (l < 0) continue; /* output bit is always 0 */ i = l >> LGCHUNKBITS; /* which chunk this bit comes from */ l = 1 << (l & (CHUNKBITS - 1)); /* mask for this bit */ for (j = 0; j < (1 << CHUNKBITS); j++) { /* each chunk value */ if ((j & l) != 0) perm[i][j].b[k >> 3] |= 1 << (k & 07); } } } /* * "setkey" routine (for backwards compatibility) */ #ifdef NOT_USED int setkey(key) const char *key; { int i, j, k; C_block keyblock; for (i = 0; i < 8; i++) { k = 0; for (j = 0; j < 8; j++) { k <<= 1; k |= (unsigned char) *key++; } keyblock.b[i] = k; } return (des_setkey((char *) keyblock.b)); } /* * "encrypt" routine (for backwards compatibility) */ static int encrypt(block, flag) char *block; int flag; { int i, j, k; C_block cblock; for (i = 0; i < 8; i++) { k = 0; for (j = 0; j < 8; j++) { k <<= 1; k |= (unsigned char) *block++; } cblock.b[i] = k; } if (des_cipher((char *) &cblock, (char *) &cblock, 0L, (flag ? -1 : 1))) return (1); for (i = 7; i >= 0; i--) { k = cblock.b[i]; for (j = 7; j >= 0; j--) { *--block = k & 01; k >>= 1; } } return (0); } #endif #ifdef DEBUG STATIC prtab(s, t, num_rows) char *s; unsigned char *t; int num_rows; { int i, j; (void) printf("%s:\n", s); for (i = 0; i < num_rows; i++) { for (j = 0; j < 8; j++) (void) printf("%3d", t[i * 8 + j]); (void) printf("\n"); } (void) printf("\n"); } #endif RPostgreSQL/src/libpq/pg_config_os.h.darwin0000644000176000001440000000023511663173071020422 0ustar ripleyusers/* src/include/port/darwin.h */ #define __darwin__ 1 #if HAVE_DECL_F_FULLFSYNC /* not present before OS X 10.3 */ #define HAVE_FSYNC_WRITETHROUGH #endif RPostgreSQL/src/libpq/c.h0000644000176000001440000005752212124517222014731 0ustar ripleyusers/*------------------------------------------------------------------------- * * c.h * Fundamental C definitions. This is included by every .c file in * PostgreSQL (via either postgres.h or postgres_fe.h, as appropriate). * * Note that the definitions here are not intended to be exposed to clients * of the frontend interface libraries --- so we don't worry much about * polluting the namespace with lots of stuff... * * * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/c.h * *------------------------------------------------------------------------- */ /* *---------------------------------------------------------------- * TABLE OF CONTENTS * * When adding stuff to this file, please try to put stuff * into the relevant section, or add new sections as appropriate. * * section description * ------- ------------------------------------------------ * 0) pg_config.h and standard system headers * 1) hacks to cope with non-ANSI C compilers * 2) bool, true, false, TRUE, FALSE, NULL * 3) standard system types * 4) IsValid macros for system types * 5) offsetof, lengthof, endof, alignment * 6) widely useful macros * 7) random stuff * 8) system-specific hacks * * NOTE: since this file is included by both frontend and backend modules, it's * almost certainly wrong to put an "extern" declaration here. typedefs and * macros are the kind of thing that might go here. * *---------------------------------------------------------------- */ #ifndef C_H #define C_H /* * We have to include stdlib.h here because it defines many of these macros * on some platforms, and we only want our definitions used if stdlib.h doesn't * have its own. The same goes for stddef and stdarg if present. */ #include "pg_config.h" #include "pg_config_manual.h" /* must be after pg_config.h */ #if !defined(WIN32) && !defined(__CYGWIN__) /* win32 will include further * down */ #include "pg_config_os.h" /* must be before any system header files */ #endif #include "postgres_ext.h" #if _MSC_VER >= 1400 || defined(WIN64) #define errcode __msvc_errcode #include #undef errcode #endif #include #include #include #include #include #ifdef HAVE_STRINGS_H #include #endif #ifdef HAVE_STDINT_H #include #endif #include #include #if defined(WIN32) || defined(__CYGWIN__) #include /* ensure O_BINARY is available */ #endif #ifdef HAVE_SUPPORTDEFS_H #include #endif #if defined(WIN32) || defined(__CYGWIN__) /* We have to redefine some system functions after they are included above. */ #include "pg_config_os.h" #endif /* Must be before gettext() games below */ #include #define _(x) gettext(x) #ifdef ENABLE_NLS #include #else #define gettext(x) (x) #define dgettext(d,x) (x) #define ngettext(s,p,n) ((n) == 1 ? (s) : (p)) #define dngettext(d,s,p,n) ((n) == 1 ? (s) : (p)) #endif /* * Use this to mark string constants as needing translation at some later * time, rather than immediately. This is useful for cases where you need * access to the original string and translated string, and for cases where * immediate translation is not possible, like when initializing global * variables. * http://www.gnu.org/software/autoconf/manual/gettext/Special-cases.html */ #define gettext_noop(x) (x) /* ---------------------------------------------------------------- * Section 1: hacks to cope with non-ANSI C compilers * * type prefixes (const, signed, volatile, inline) are handled in pg_config.h. * ---------------------------------------------------------------- */ /* * CppAsString * Convert the argument to a string, using the C preprocessor. * CppConcat * Concatenate two arguments together, using the C preprocessor. * * Note: the standard Autoconf macro AC_C_STRINGIZE actually only checks * whether #identifier works, but if we have that we likely have ## too. */ #if defined(HAVE_STRINGIZE) #define CppAsString(identifier) #identifier #define CppConcat(x, y) x##y #else /* !HAVE_STRINGIZE */ #define CppAsString(identifier) "identifier" /* * CppIdentity -- On Reiser based cpp's this is used to concatenate * two tokens. That is * CppIdentity(A)B ==> AB * We renamed it to _private_CppIdentity because it should not * be referenced outside this file. On other cpp's it * produces A B. */ #define _priv_CppIdentity(x)x #define CppConcat(x, y) _priv_CppIdentity(x)y #endif /* !HAVE_STRINGIZE */ /* * dummyret is used to set return values in macros that use ?: to make * assignments. gcc wants these to be void, other compilers like char */ #ifdef __GNUC__ /* GNU cc */ #define dummyret void #else #define dummyret char #endif #ifndef __GNUC__ #define __attribute__(_arg_) #endif /* ---------------------------------------------------------------- * Section 2: bool, true, false, TRUE, FALSE, NULL * ---------------------------------------------------------------- */ /* * bool * Boolean value, either true or false. * * XXX for C++ compilers, we assume the compiler has a compatible * built-in definition of bool. */ #ifndef __cplusplus #ifndef bool typedef char bool; #endif #ifndef true #define true ((bool) 1) #endif #ifndef false #define false ((bool) 0) #endif #endif /* not C++ */ typedef bool *BoolPtr; #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif /* * NULL * Null pointer. */ #ifndef NULL #define NULL ((void *) 0) #endif /* ---------------------------------------------------------------- * Section 3: standard system types * ---------------------------------------------------------------- */ /* * Pointer * Variable holding address of any memory resident object. * * XXX Pointer arithmetic is done with this, so it can't be void * * under "true" ANSI compilers. */ typedef char *Pointer; /* * intN * Signed integer, EXACTLY N BITS IN SIZE, * used for numerical computations and the * frontend/backend protocol. */ #ifndef HAVE_INT8 typedef signed char int8; /* == 8 bits */ typedef signed short int16; /* == 16 bits */ typedef signed int int32; /* == 32 bits */ #endif /* not HAVE_INT8 */ /* * uintN * Unsigned integer, EXACTLY N BITS IN SIZE, * used for numerical computations and the * frontend/backend protocol. */ #ifndef HAVE_UINT8 typedef unsigned char uint8; /* == 8 bits */ typedef unsigned short uint16; /* == 16 bits */ typedef unsigned int uint32; /* == 32 bits */ #endif /* not HAVE_UINT8 */ /* * bitsN * Unit of bitwise operation, AT LEAST N BITS IN SIZE. */ typedef uint8 bits8; /* >= 8 bits */ typedef uint16 bits16; /* >= 16 bits */ typedef uint32 bits32; /* >= 32 bits */ /* * 64-bit integers */ #ifdef HAVE_LONG_INT_64 /* Plain "long int" fits, use it */ #ifndef HAVE_INT64 typedef long int int64; #endif #ifndef HAVE_UINT64 typedef unsigned long int uint64; #endif #elif defined(HAVE_LONG_LONG_INT_64) /* We have working support for "long long int", use that */ #ifndef HAVE_INT64 typedef long long int int64; #endif #ifndef HAVE_UINT64 typedef unsigned long long int uint64; #endif #else /* neither HAVE_LONG_INT_64 nor HAVE_LONG_LONG_INT_64 */ #error must have a working 64-bit integer datatype #endif /* Decide if we need to decorate 64-bit constants */ #ifdef HAVE_LL_CONSTANTS #define INT64CONST(x) ((int64) x##LL) #define UINT64CONST(x) ((uint64) x##ULL) #else #define INT64CONST(x) ((int64) x) #define UINT64CONST(x) ((uint64) x) #endif /* Select timestamp representation (float8 or int64) */ #ifdef USE_INTEGER_DATETIMES #define HAVE_INT64_TIMESTAMP #endif /* sig_atomic_t is required by ANSI C, but may be missing on old platforms */ #ifndef HAVE_SIG_ATOMIC_T typedef int sig_atomic_t; #endif /* * Size * Size of any memory resident object, as returned by sizeof. */ typedef size_t Size; /* * Index * Index into any memory resident array. * * Note: * Indices are non negative. */ typedef unsigned int Index; /* * Offset * Offset into any memory resident array. * * Note: * This differs from an Index in that an Index is always * non negative, whereas Offset may be negative. */ typedef signed int Offset; /* * Common Postgres datatype names (as used in the catalogs) */ typedef int16 int2; typedef int32 int4; typedef float float4; typedef double float8; /* * Oid, RegProcedure, TransactionId, SubTransactionId, MultiXactId, * CommandId */ /* typedef Oid is in postgres_ext.h */ /* * regproc is the type name used in the include/catalog headers, but * RegProcedure is the preferred name in C code. */ typedef Oid regproc; typedef regproc RegProcedure; typedef uint32 TransactionId; typedef uint32 LocalTransactionId; typedef uint32 SubTransactionId; #define InvalidSubTransactionId ((SubTransactionId) 0) #define TopSubTransactionId ((SubTransactionId) 1) /* MultiXactId must be equivalent to TransactionId, to fit in t_xmax */ typedef TransactionId MultiXactId; typedef uint32 MultiXactOffset; typedef uint32 CommandId; #define FirstCommandId ((CommandId) 0) /* * Array indexing support */ #define MAXDIM 6 typedef struct { int indx[MAXDIM]; } IntArray; /* ---------------- * Variable-length datatypes all share the 'struct varlena' header. * * NOTE: for TOASTable types, this is an oversimplification, since the value * may be compressed or moved out-of-line. However datatype-specific routines * are mostly content to deal with de-TOASTed values only, and of course * client-side routines should never see a TOASTed value. But even in a * de-TOASTed value, beware of touching vl_len_ directly, as its representation * is no longer convenient. It's recommended that code always use the VARDATA, * VARSIZE, and SET_VARSIZE macros instead of relying on direct mentions of * the struct fields. See postgres.h for details of the TOASTed form. * ---------------- */ struct varlena { char vl_len_[4]; /* Do not touch this field directly! */ char vl_dat[1]; }; #define VARHDRSZ ((int32) sizeof(int32)) /* * These widely-used datatypes are just a varlena header and the data bytes. * There is no terminating null or anything like that --- the data length is * always VARSIZE(ptr) - VARHDRSZ. */ typedef struct varlena bytea; typedef struct varlena text; typedef struct varlena BpChar; /* blank-padded char, ie SQL char(n) */ typedef struct varlena VarChar; /* var-length char, ie SQL varchar(n) */ /* * Specialized array types. These are physically laid out just the same * as regular arrays (so that the regular array subscripting code works * with them). They exist as distinct types mostly for historical reasons: * they have nonstandard I/O behavior which we don't want to change for fear * of breaking applications that look at the system catalogs. There is also * an implementation issue for oidvector: it's part of the primary key for * pg_proc, and we can't use the normal btree array support routines for that * without circularity. */ typedef struct { int32 vl_len_; /* these fields must match ArrayType! */ int ndim; /* always 1 for int2vector */ int32 dataoffset; /* always 0 for int2vector */ Oid elemtype; int dim1; int lbound1; int2 values[1]; /* VARIABLE LENGTH ARRAY */ } int2vector; /* VARIABLE LENGTH STRUCT */ typedef struct { int32 vl_len_; /* these fields must match ArrayType! */ int ndim; /* always 1 for oidvector */ int32 dataoffset; /* always 0 for oidvector */ Oid elemtype; int dim1; int lbound1; Oid values[1]; /* VARIABLE LENGTH ARRAY */ } oidvector; /* VARIABLE LENGTH STRUCT */ /* * Representation of a Name: effectively just a C string, but null-padded to * exactly NAMEDATALEN bytes. The use of a struct is historical. */ typedef struct nameData { char data[NAMEDATALEN]; } NameData; typedef NameData *Name; #define NameStr(name) ((name).data) /* * Support macros for escaping strings. escape_backslash should be TRUE * if generating a non-standard-conforming string. Prefixing a string * with ESCAPE_STRING_SYNTAX guarantees it is non-standard-conforming. * Beware of multiple evaluation of the "ch" argument! */ #define SQL_STR_DOUBLE(ch, escape_backslash) \ ((ch) == '\'' || ((ch) == '\\' && (escape_backslash))) #define ESCAPE_STRING_SYNTAX 'E' /* ---------------------------------------------------------------- * Section 4: IsValid macros for system types * ---------------------------------------------------------------- */ /* * BoolIsValid * True iff bool is valid. */ #define BoolIsValid(boolean) ((boolean) == false || (boolean) == true) /* * PointerIsValid * True iff pointer is valid. */ #define PointerIsValid(pointer) ((void*)(pointer) != NULL) /* * PointerIsAligned * True iff pointer is properly aligned to point to the given type. */ #define PointerIsAligned(pointer, type) \ (((intptr_t)(pointer) % (sizeof (type))) == 0) #define OidIsValid(objectId) ((bool) ((objectId) != InvalidOid)) #define RegProcedureIsValid(p) OidIsValid(p) /* ---------------------------------------------------------------- * Section 5: offsetof, lengthof, endof, alignment * ---------------------------------------------------------------- */ /* * offsetof * Offset of a structure/union field within that structure/union. * * XXX This is supposed to be part of stddef.h, but isn't on * some systems (like SunOS 4). */ #ifndef offsetof #define offsetof(type, field) ((long) &((type *)0)->field) #endif /* offsetof */ /* * lengthof * Number of elements in an array. */ #define lengthof(array) (sizeof (array) / sizeof ((array)[0])) /* * endof * Address of the element one past the last in an array. */ #define endof(array) (&(array)[lengthof(array)]) /* ---------------- * Alignment macros: align a length or address appropriately for a given type. * The fooALIGN() macros round up to a multiple of the required alignment, * while the fooALIGN_DOWN() macros round down. The latter are more useful * for problems like "how many X-sized structures will fit in a page?". * * NOTE: TYPEALIGN[_DOWN] will not work if ALIGNVAL is not a power of 2. * That case seems extremely unlikely to be needed in practice, however. * ---------------- */ #define TYPEALIGN(ALIGNVAL,LEN) \ (((intptr_t) (LEN) + ((ALIGNVAL) - 1)) & ~((intptr_t) ((ALIGNVAL) - 1))) #define SHORTALIGN(LEN) TYPEALIGN(ALIGNOF_SHORT, (LEN)) #define INTALIGN(LEN) TYPEALIGN(ALIGNOF_INT, (LEN)) #define LONGALIGN(LEN) TYPEALIGN(ALIGNOF_LONG, (LEN)) #define DOUBLEALIGN(LEN) TYPEALIGN(ALIGNOF_DOUBLE, (LEN)) #define MAXALIGN(LEN) TYPEALIGN(MAXIMUM_ALIGNOF, (LEN)) /* MAXALIGN covers only built-in types, not buffers */ #define BUFFERALIGN(LEN) TYPEALIGN(ALIGNOF_BUFFER, (LEN)) #define TYPEALIGN_DOWN(ALIGNVAL,LEN) \ (((intptr_t) (LEN)) & ~((intptr_t) ((ALIGNVAL) - 1))) #define SHORTALIGN_DOWN(LEN) TYPEALIGN_DOWN(ALIGNOF_SHORT, (LEN)) #define INTALIGN_DOWN(LEN) TYPEALIGN_DOWN(ALIGNOF_INT, (LEN)) #define LONGALIGN_DOWN(LEN) TYPEALIGN_DOWN(ALIGNOF_LONG, (LEN)) #define DOUBLEALIGN_DOWN(LEN) TYPEALIGN_DOWN(ALIGNOF_DOUBLE, (LEN)) #define MAXALIGN_DOWN(LEN) TYPEALIGN_DOWN(MAXIMUM_ALIGNOF, (LEN)) /* ---------------------------------------------------------------- * Section 6: widely useful macros * ---------------------------------------------------------------- */ /* * Max * Return the maximum of two numbers. */ #define Max(x, y) ((x) > (y) ? (x) : (y)) /* * Min * Return the minimum of two numbers. */ #define Min(x, y) ((x) < (y) ? (x) : (y)) /* * Abs * Return the absolute value of the argument. */ #define Abs(x) ((x) >= 0 ? (x) : -(x)) /* * StrNCpy * Like standard library function strncpy(), except that result string * is guaranteed to be null-terminated --- that is, at most N-1 bytes * of the source string will be kept. * Also, the macro returns no result (too hard to do that without * evaluating the arguments multiple times, which seems worse). * * BTW: when you need to copy a non-null-terminated string (like a text * datum) and add a null, do not do it with StrNCpy(..., len+1). That * might seem to work, but it fetches one byte more than there is in the * text object. One fine day you'll have a SIGSEGV because there isn't * another byte before the end of memory. Don't laugh, we've had real * live bug reports from real live users over exactly this mistake. * Do it honestly with "memcpy(dst,src,len); dst[len] = '\0';", instead. */ #define StrNCpy(dst,src,len) \ do \ { \ char * _dst = (dst); \ Size _len = (len); \ \ if (_len > 0) \ { \ strncpy(_dst, (src), _len); \ _dst[_len-1] = '\0'; \ } \ } while (0) /* Get a bit mask of the bits set in non-long aligned addresses */ #define LONG_ALIGN_MASK (sizeof(long) - 1) /* * MemSet * Exactly the same as standard library function memset(), but considerably * faster for zeroing small word-aligned structures (such as parsetree nodes). * This has to be a macro because the main point is to avoid function-call * overhead. However, we have also found that the loop is faster than * native libc memset() on some platforms, even those with assembler * memset() functions. More research needs to be done, perhaps with * MEMSET_LOOP_LIMIT tests in configure. */ #define MemSet(start, val, len) \ do \ { \ /* must be void* because we don't know if it is integer aligned yet */ \ void *_vstart = (void *) (start); \ int _val = (val); \ Size _len = (len); \ \ if ((((intptr_t) _vstart) & LONG_ALIGN_MASK) == 0 && \ (_len & LONG_ALIGN_MASK) == 0 && \ _val == 0 && \ _len <= MEMSET_LOOP_LIMIT && \ /* \ * If MEMSET_LOOP_LIMIT == 0, optimizer should find \ * the whole "if" false at compile time. \ */ \ MEMSET_LOOP_LIMIT != 0) \ { \ long *_start = (long *) _vstart; \ long *_stop = (long *) ((char *) _start + _len); \ while (_start < _stop) \ *_start++ = 0; \ } \ else \ memset(_vstart, _val, _len); \ } while (0) /* * MemSetAligned is the same as MemSet except it omits the test to see if * "start" is word-aligned. This is okay to use if the caller knows a-priori * that the pointer is suitably aligned (typically, because he just got it * from palloc(), which always delivers a max-aligned pointer). */ #define MemSetAligned(start, val, len) \ do \ { \ long *_start = (long *) (start); \ int _val = (val); \ Size _len = (len); \ \ if ((_len & LONG_ALIGN_MASK) == 0 && \ _val == 0 && \ _len <= MEMSET_LOOP_LIMIT && \ MEMSET_LOOP_LIMIT != 0) \ { \ long *_stop = (long *) ((char *) _start + _len); \ while (_start < _stop) \ *_start++ = 0; \ } \ else \ memset(_start, _val, _len); \ } while (0) /* * MemSetTest/MemSetLoop are a variant version that allow all the tests in * MemSet to be done at compile time in cases where "val" and "len" are * constants *and* we know the "start" pointer must be word-aligned. * If MemSetTest succeeds, then it is okay to use MemSetLoop, otherwise use * MemSetAligned. Beware of multiple evaluations of the arguments when using * this approach. */ #define MemSetTest(val, len) \ ( ((len) & LONG_ALIGN_MASK) == 0 && \ (len) <= MEMSET_LOOP_LIMIT && \ MEMSET_LOOP_LIMIT != 0 && \ (val) == 0 ) #define MemSetLoop(start, val, len) \ do \ { \ long * _start = (long *) (start); \ long * _stop = (long *) ((char *) _start + (Size) (len)); \ \ while (_start < _stop) \ *_start++ = 0; \ } while (0) /* ---------------------------------------------------------------- * Section 7: random stuff * ---------------------------------------------------------------- */ /* msb for char */ #define HIGHBIT (0x80) #define IS_HIGHBIT_SET(ch) ((unsigned char)(ch) & HIGHBIT) #define STATUS_OK (0) #define STATUS_ERROR (-1) #define STATUS_EOF (-2) #define STATUS_FOUND (1) #define STATUS_WAITING (2) /* gettext domain name mangling */ /* * To better support parallel installations of major PostgeSQL * versions as well as parallel installations of major library soname * versions, we mangle the gettext domain name by appending those * version numbers. The coding rule ought to be that whereever the * domain name is mentioned as a literal, it must be wrapped into * PG_TEXTDOMAIN(). The macros below do not work on non-literals; but * that is somewhat intentional because it avoids having to worry * about multiple states of premangling and postmangling as the values * are being passed around. * * Make sure this matches the installation rules in nls-global.mk. */ /* need a second indirection because we want to stringize the macro value, not the name */ #define CppAsString2(x) CppAsString(x) #ifdef SO_MAJOR_VERSION #define PG_TEXTDOMAIN(domain) (domain CppAsString2(SO_MAJOR_VERSION) "-" PG_MAJORVERSION) #else #define PG_TEXTDOMAIN(domain) (domain "-" PG_MAJORVERSION) #endif /* ---------------------------------------------------------------- * Section 8: system-specific hacks * * This should be limited to things that absolutely have to be * included in every source file. The port-specific header file * is usually a better place for this sort of thing. * ---------------------------------------------------------------- */ /* * NOTE: this is also used for opening text files. * WIN32 treats Control-Z as EOF in files opened in text mode. * Therefore, we open files in binary mode on Win32 so we can read * literal control-Z. The other affect is that we see CRLF, but * that is OK because we can already handle those cleanly. */ #if defined(WIN32) || defined(__CYGWIN__) #define PG_BINARY O_BINARY #define PG_BINARY_A "ab" #define PG_BINARY_R "rb" #define PG_BINARY_W "wb" #else #define PG_BINARY 0 #define PG_BINARY_A "a" #define PG_BINARY_R "r" #define PG_BINARY_W "w" #endif /* * Provide prototypes for routines not present in a particular machine's * standard C library. */ #if !HAVE_DECL_SNPRINTF extern int snprintf(char *str, size_t count, const char *fmt,...) /* This extension allows gcc to check the format string */ __attribute__((format(PG_PRINTF_ATTRIBUTE, 3, 4))); #endif #if !HAVE_DECL_VSNPRINTF extern int vsnprintf(char *str, size_t count, const char *fmt, va_list args); #endif #if !defined(HAVE_MEMMOVE) && !defined(memmove) #define memmove(d, s, c) bcopy(s, d, c) #endif /* no special DLL markers on most ports */ #ifndef PGDLLIMPORT #define PGDLLIMPORT #endif #ifndef PGDLLEXPORT #define PGDLLEXPORT #endif /* * The following is used as the arg list for signal handlers. Any ports * that take something other than an int argument should override this in * their pg_config_os.h file. Note that variable names are required * because it is used in both the prototypes as well as the definitions. * Note also the long name. We expect that this won't collide with * other names causing compiler warnings. */ #ifndef SIGNAL_ARGS #define SIGNAL_ARGS int postgres_signal_arg #endif /* * When there is no sigsetjmp, its functionality is provided by plain * setjmp. Incidentally, nothing provides setjmp's functionality in * that case. */ #ifndef HAVE_SIGSETJMP #define sigjmp_buf jmp_buf #define sigsetjmp(x,y) setjmp(x) #define siglongjmp longjmp #endif #if defined(HAVE_FDATASYNC) && !HAVE_DECL_FDATASYNC extern int fdatasync(int fildes); #endif /* If strtoq() exists, rename it to the more standard strtoll() */ #if defined(HAVE_LONG_LONG_INT_64) && !defined(HAVE_STRTOLL) && defined(HAVE_STRTOQ) #define strtoll strtoq #define HAVE_STRTOLL 1 #endif /* If strtouq() exists, rename it to the more standard strtoull() */ #if defined(HAVE_LONG_LONG_INT_64) && !defined(HAVE_STRTOULL) && defined(HAVE_STRTOUQ) #define strtoull strtouq #define HAVE_STRTOULL 1 #endif /* * We assume if we have these two functions, we have their friends too, and * can use the wide-character functions. */ #if defined(HAVE_WCSTOMBS) && defined(HAVE_TOWLOWER) #define USE_WIDE_UPPER_LOWER #endif /* EXEC_BACKEND defines */ #ifdef EXEC_BACKEND #define NON_EXEC_STATIC #else #define NON_EXEC_STATIC static #endif /* /port compatibility functions */ #include "port.h" #endif /* C_H */ RPostgreSQL/src/libpq/pqexpbuffer.h0000644000176000001440000001416412124517222017031 0ustar ripleyusers/*------------------------------------------------------------------------- * * pqexpbuffer.h * Declarations/definitions for "PQExpBuffer" functions. * * PQExpBuffer provides an indefinitely-extensible string data type. * It can be used to buffer either ordinary C strings (null-terminated text) * or arbitrary binary data. All storage is allocated with malloc(). * * This module is essentially the same as the backend's StringInfo data type, * but it is intended for use in frontend libpq and client applications. * Thus, it does not rely on palloc() nor elog(). * * It does rely on vsnprintf(); if configure finds that libc doesn't provide * a usable vsnprintf(), then a copy of our own implementation of it will * be linked into libpq. * * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/interfaces/libpq/pqexpbuffer.h * *------------------------------------------------------------------------- */ #ifndef PQEXPBUFFER_H #define PQEXPBUFFER_H /*------------------------- * PQExpBufferData holds information about an extensible string. * data is the current buffer for the string (allocated with malloc). * len is the current string length. There is guaranteed to be * a terminating '\0' at data[len], although this is not very * useful when the string holds binary data rather than text. * maxlen is the allocated size in bytes of 'data', i.e. the maximum * string size (including the terminating '\0' char) that we can * currently store in 'data' without having to reallocate * more space. We must always have maxlen > len. * * An exception occurs if we failed to allocate enough memory for the string * buffer. In that case data points to a statically allocated empty string, * and len = maxlen = 0. *------------------------- */ typedef struct PQExpBufferData { char *data; size_t len; size_t maxlen; } PQExpBufferData; typedef PQExpBufferData *PQExpBuffer; /*------------------------ * Test for a broken (out of memory) PQExpBuffer. * When a buffer is "broken", all operations except resetting or deleting it * are no-ops. *------------------------ */ #define PQExpBufferBroken(str) \ ((str) == NULL || (str)->maxlen == 0) /*------------------------ * Initial size of the data buffer in a PQExpBuffer. * NB: this must be large enough to hold error messages that might * be returned by PQrequestCancel(). *------------------------ */ #define INITIAL_EXPBUFFER_SIZE 256 /*------------------------ * There are two ways to create a PQExpBuffer object initially: * * PQExpBuffer stringptr = createPQExpBuffer(); * Both the PQExpBufferData and the data buffer are malloc'd. * * PQExpBufferData string; * initPQExpBuffer(&string); * The data buffer is malloc'd but the PQExpBufferData is presupplied. * This is appropriate if the PQExpBufferData is a field of another * struct. *------------------------- */ /*------------------------ * createPQExpBuffer * Create an empty 'PQExpBufferData' & return a pointer to it. */ extern PQExpBuffer createPQExpBuffer(void); /*------------------------ * initPQExpBuffer * Initialize a PQExpBufferData struct (with previously undefined contents) * to describe an empty string. */ extern void initPQExpBuffer(PQExpBuffer str); /*------------------------ * To destroy a PQExpBuffer, use either: * * destroyPQExpBuffer(str); * free()s both the data buffer and the PQExpBufferData. * This is the inverse of createPQExpBuffer(). * * termPQExpBuffer(str) * free()s the data buffer but not the PQExpBufferData itself. * This is the inverse of initPQExpBuffer(). * * NOTE: some routines build up a string using PQExpBuffer, and then * release the PQExpBufferData but return the data string itself to their * caller. At that point the data string looks like a plain malloc'd * string. */ extern void destroyPQExpBuffer(PQExpBuffer str); extern void termPQExpBuffer(PQExpBuffer str); /*------------------------ * resetPQExpBuffer * Reset a PQExpBuffer to empty * * Note: if possible, a "broken" PQExpBuffer is returned to normal. */ extern void resetPQExpBuffer(PQExpBuffer str); /*------------------------ * enlargePQExpBuffer * Make sure there is enough space for 'needed' more bytes in the buffer * ('needed' does not include the terminating null). * * Returns 1 if OK, 0 if failed to enlarge buffer. (In the latter case * the buffer is left in "broken" state.) */ extern int enlargePQExpBuffer(PQExpBuffer str, size_t needed); /*------------------------ * printfPQExpBuffer * Format text data under the control of fmt (an sprintf-like format string) * and insert it into str. More space is allocated to str if necessary. * This is a convenience routine that does the same thing as * resetPQExpBuffer() followed by appendPQExpBuffer(). */ extern void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...) /* This extension allows gcc to check the format string */ __attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 3))); /*------------------------ * appendPQExpBuffer * Format text data under the control of fmt (an sprintf-like format string) * and append it to whatever is already in str. More space is allocated * to str if necessary. This is sort of like a combination of sprintf and * strcat. */ extern void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...) /* This extension allows gcc to check the format string */ __attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 3))); /*------------------------ * appendPQExpBufferStr * Append the given string to a PQExpBuffer, allocating more space * if necessary. */ extern void appendPQExpBufferStr(PQExpBuffer str, const char *data); /*------------------------ * appendPQExpBufferChar * Append a single byte to str. * Like appendPQExpBuffer(str, "%c", ch) but much faster. */ extern void appendPQExpBufferChar(PQExpBuffer str, char ch); /*------------------------ * appendBinaryPQExpBuffer * Append arbitrary binary data to a PQExpBuffer, allocating more space * if necessary. */ extern void appendBinaryPQExpBuffer(PQExpBuffer str, const char *data, size_t datalen); #endif /* PQEXPBUFFER_H */ RPostgreSQL/src/libpq/getaddrinfo.c0000644000176000001440000002213712124517222016762 0ustar ripleyusers/*------------------------------------------------------------------------- * * getaddrinfo.c * Support getaddrinfo() on platforms that don't have it. * * We also supply getnameinfo() here, assuming that the platform will have * it if and only if it has getaddrinfo(). If this proves false on some * platform, we'll need to split this file and provide a separate configure * test for getnameinfo(). * * Windows may or may not have these routines, so we handle Windows specially * by dynamically checking for their existence. If they already exist, we * use the Windows native routines, but if not, we use our own. * * * Copyright (c) 2003-2011, PostgreSQL Global Development Group * * IDENTIFICATION * src/port/getaddrinfo.c * *------------------------------------------------------------------------- */ /* This is intended to be used in both frontend and backend, so use c.h */ #include "c.h" #include #include #include #include #include "getaddrinfo.h" #include "libpq/pqcomm.h" /* needed for struct sockaddr_storage */ #ifdef WIN32 /* * The native routines may or may not exist on the Windows platform we are on, * so we dynamically look up the routines, and call them via function pointers. * Here we need to declare what the function pointers look like */ typedef int (__stdcall * getaddrinfo_ptr_t) (const char *nodename, const char *servname, const struct addrinfo * hints, struct addrinfo ** res); typedef void (__stdcall * freeaddrinfo_ptr_t) (struct addrinfo * ai); typedef int (__stdcall * getnameinfo_ptr_t) (const struct sockaddr * sa, int salen, char *host, int hostlen, char *serv, int servlen, int flags); /* static pointers to the native routines, so we only do the lookup once. */ static getaddrinfo_ptr_t getaddrinfo_ptr = NULL; static freeaddrinfo_ptr_t freeaddrinfo_ptr = NULL; static getnameinfo_ptr_t getnameinfo_ptr = NULL; static bool haveNativeWindowsIPv6routines(void) { void *hLibrary = NULL; static bool alreadyLookedForIpv6routines = false; if (alreadyLookedForIpv6routines) return (getaddrinfo_ptr != NULL); /* * For Windows XP and Windows 2003 (and longhorn/vista), the IPv6 routines * are present in the WinSock 2 library (ws2_32.dll). Try that first */ hLibrary = LoadLibraryA("ws2_32"); if (hLibrary == NULL || GetProcAddress(hLibrary, "getaddrinfo") == NULL) { /* * Well, ws2_32 doesn't exist, or more likely doesn't have * getaddrinfo. */ if (hLibrary != NULL) FreeLibrary(hLibrary); /* * In Windows 2000, there was only the IPv6 Technology Preview look in * the IPv6 WinSock library (wship6.dll). */ hLibrary = LoadLibraryA("wship6"); } /* If hLibrary is null, we couldn't find a dll with functions */ if (hLibrary != NULL) { /* We found a dll, so now get the addresses of the routines */ getaddrinfo_ptr = (getaddrinfo_ptr_t) GetProcAddress(hLibrary, "getaddrinfo"); freeaddrinfo_ptr = (freeaddrinfo_ptr_t) GetProcAddress(hLibrary, "freeaddrinfo"); getnameinfo_ptr = (getnameinfo_ptr_t) GetProcAddress(hLibrary, "getnameinfo"); /* * If any one of the routines is missing, let's play it safe and * ignore them all */ if (getaddrinfo_ptr == NULL || freeaddrinfo_ptr == NULL || getnameinfo_ptr == NULL) { FreeLibrary(hLibrary); hLibrary = NULL; getaddrinfo_ptr = NULL; freeaddrinfo_ptr = NULL; getnameinfo_ptr = NULL; } } alreadyLookedForIpv6routines = true; return (getaddrinfo_ptr != NULL); } #endif /* * get address info for ipv4 sockets. * * Bugs: - only one addrinfo is set even though hintp is NULL or * ai_socktype is 0 * - AI_CANONNAME is not supported. * - servname can only be a number, not text. */ int getaddrinfo(const char *node, const char *service, const struct addrinfo * hintp, struct addrinfo ** res) { struct addrinfo *ai; struct sockaddr_in sin, *psin; struct addrinfo hints; #ifdef WIN32 /* * If Windows has native IPv6 support, use the native Windows routine. * Otherwise, fall through and use our own code. */ if (haveNativeWindowsIPv6routines()) return (*getaddrinfo_ptr) (node, service, hintp, res); #endif if (hintp == NULL) { memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; } else memcpy(&hints, hintp, sizeof(hints)); if (hints.ai_family != AF_INET && hints.ai_family != AF_UNSPEC) return EAI_FAMILY; if (hints.ai_socktype == 0) hints.ai_socktype = SOCK_STREAM; if (!node && !service) return EAI_NONAME; memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; if (node) { if (node[0] == '\0') sin.sin_addr.s_addr = htonl(INADDR_ANY); else if (hints.ai_flags & AI_NUMERICHOST) { if (!inet_aton(node, &sin.sin_addr)) return EAI_FAIL; } else { struct hostent *hp; #ifdef FRONTEND struct hostent hpstr; char buf[BUFSIZ]; int herrno = 0; pqGethostbyname(node, &hpstr, buf, sizeof(buf), &hp, &herrno); #else hp = gethostbyname(node); #endif if (hp == NULL) { switch (h_errno) { case HOST_NOT_FOUND: case NO_DATA: return EAI_NONAME; case TRY_AGAIN: return EAI_AGAIN; case NO_RECOVERY: default: return EAI_FAIL; } } if (hp->h_addrtype != AF_INET) return EAI_FAIL; memcpy(&(sin.sin_addr), hp->h_addr, hp->h_length); } } else { if (hints.ai_flags & AI_PASSIVE) sin.sin_addr.s_addr = htonl(INADDR_ANY); else sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); } if (service) sin.sin_port = htons((unsigned short) atoi(service)); #ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN sin.sin_len = sizeof(sin); #endif ai = malloc(sizeof(*ai)); if (!ai) return EAI_MEMORY; psin = malloc(sizeof(*psin)); if (!psin) { free(ai); return EAI_MEMORY; } memcpy(psin, &sin, sizeof(*psin)); ai->ai_flags = 0; ai->ai_family = AF_INET; ai->ai_socktype = hints.ai_socktype; ai->ai_protocol = hints.ai_protocol; ai->ai_addrlen = sizeof(*psin); ai->ai_addr = (struct sockaddr *) psin; ai->ai_canonname = NULL; ai->ai_next = NULL; *res = ai; return 0; } void freeaddrinfo(struct addrinfo * res) { if (res) { #ifdef WIN32 /* * If Windows has native IPv6 support, use the native Windows routine. * Otherwise, fall through and use our own code. */ if (haveNativeWindowsIPv6routines()) { (*freeaddrinfo_ptr) (res); return; } #endif if (res->ai_addr) free(res->ai_addr); free(res); } } const char * gai_strerror(int errcode) { #ifdef HAVE_HSTRERROR int hcode; switch (errcode) { case EAI_NONAME: hcode = HOST_NOT_FOUND; break; case EAI_AGAIN: hcode = TRY_AGAIN; break; case EAI_FAIL: default: hcode = NO_RECOVERY; break; } return hstrerror(hcode); #else /* !HAVE_HSTRERROR */ switch (errcode) { case EAI_NONAME: return "Unknown host"; case EAI_AGAIN: return "Host name lookup failure"; /* Errors below are probably WIN32 only */ #ifdef EAI_BADFLAGS case EAI_BADFLAGS: return "Invalid argument"; #endif #ifdef EAI_FAMILY case EAI_FAMILY: return "Address family not supported"; #endif #ifdef EAI_MEMORY case EAI_MEMORY: return "Not enough memory"; #endif #ifdef EAI_NODATA #if EAI_NODATA != EAI_NONAME #if !defined(WIN64) && !defined(WIN32_ONLY_COMPILER) /* MSVC/WIN64 duplicate */ case EAI_NODATA: return "No host data of that type was found"; #endif #endif #endif #ifdef EAI_SERVICE case EAI_SERVICE: return "Class type not found"; #endif #ifdef EAI_SOCKTYPE case EAI_SOCKTYPE: return "Socket type not supported"; #endif default: return "Unknown server error"; } #endif /* HAVE_HSTRERROR */ } /* * Convert an ipv4 address to a hostname. * * Bugs: - Only supports NI_NUMERICHOST and NI_NUMERICSERV * It will never resolv a hostname. * - No IPv6 support. */ int getnameinfo(const struct sockaddr * sa, int salen, char *node, int nodelen, char *service, int servicelen, int flags) { #ifdef WIN32 /* * If Windows has native IPv6 support, use the native Windows routine. * Otherwise, fall through and use our own code. */ if (haveNativeWindowsIPv6routines()) return (*getnameinfo_ptr) (sa, salen, node, nodelen, service, servicelen, flags); #endif /* Invalid arguments. */ if (sa == NULL || (node == NULL && service == NULL)) return EAI_FAIL; /* We don't support those. */ if ((node && !(flags & NI_NUMERICHOST)) || (service && !(flags & NI_NUMERICSERV))) return EAI_FAIL; #ifdef HAVE_IPV6 if (sa->sa_family == AF_INET6) return EAI_FAMILY; #endif if (node) { if (sa->sa_family == AF_INET) { if (inet_net_ntop(AF_INET, &((struct sockaddr_in *) sa)->sin_addr, sa->sa_family == AF_INET ? 32 : 128, node, nodelen) == NULL) return EAI_MEMORY; } else return EAI_MEMORY; } if (service) { int ret = -1; if (sa->sa_family == AF_INET) { ret = snprintf(service, servicelen, "%d", ntohs(((struct sockaddr_in *) sa)->sin_port)); } if (ret == -1 || ret > servicelen) return EAI_MEMORY; } return 0; } RPostgreSQL/src/libpq/port.h0000644000176000001440000003430612124517222015466 0ustar ripleyusers/*------------------------------------------------------------------------- * * port.h * Header for src/port/ compatibility functions. * * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/port.h * *------------------------------------------------------------------------- */ #ifndef PG_PORT_H #define PG_PORT_H #include #include #include /* socket has a different definition on WIN32 */ #ifndef WIN32 typedef int pgsocket; #define PGINVALID_SOCKET (-1) #else typedef SOCKET pgsocket; #define PGINVALID_SOCKET INVALID_SOCKET #endif /* non-blocking */ extern bool pg_set_noblock(pgsocket sock); extern bool pg_set_block(pgsocket sock); /* Portable path handling for Unix/Win32 (in path.c) */ extern char *first_dir_separator(const char *filename); extern char *last_dir_separator(const char *filename); extern char *first_path_var_separator(const char *pathlist); extern void join_path_components(char *ret_path, const char *head, const char *tail); extern void canonicalize_path(char *path); extern void make_native_path(char *path); extern bool path_contains_parent_reference(const char *path); extern bool path_is_relative_and_below_cwd(const char *path); extern bool path_is_prefix_of_path(const char *path1, const char *path2); extern const char *get_progname(const char *argv0); extern void get_share_path(const char *my_exec_path, char *ret_path); extern void get_etc_path(const char *my_exec_path, char *ret_path); extern void get_include_path(const char *my_exec_path, char *ret_path); extern void get_pkginclude_path(const char *my_exec_path, char *ret_path); extern void get_includeserver_path(const char *my_exec_path, char *ret_path); extern void get_lib_path(const char *my_exec_path, char *ret_path); extern void get_pkglib_path(const char *my_exec_path, char *ret_path); extern void get_locale_path(const char *my_exec_path, char *ret_path); extern void get_doc_path(const char *my_exec_path, char *ret_path); extern void get_html_path(const char *my_exec_path, char *ret_path); extern void get_man_path(const char *my_exec_path, char *ret_path); extern bool get_home_path(char *ret_path); extern void get_parent_directory(char *path); /* port/dirmod.c */ extern char **pgfnames(const char *path); extern void pgfnames_cleanup(char **filenames); /* * is_absolute_path * * By making this a macro we avoid needing to include path.c in libpq. */ #ifndef WIN32 #define IS_DIR_SEP(ch) ((ch) == '/') #define is_absolute_path(filename) \ ( \ IS_DIR_SEP((filename)[0]) \ ) #else #define IS_DIR_SEP(ch) ((ch) == '/' || (ch) == '\\') /* See path_is_relative_and_below_cwd() for how we handle 'E:abc'. */ #define is_absolute_path(filename) \ ( \ IS_DIR_SEP((filename)[0]) || \ (isalpha((unsigned char) ((filename)[0])) && (filename)[1] == ':' && \ IS_DIR_SEP((filename)[2])) \ ) #endif /* Portable locale initialization (in exec.c) */ extern void set_pglocale_pgservice(const char *argv0, const char *app); /* Portable way to find binaries (in exec.c) */ extern int find_my_exec(const char *argv0, char *retpath); extern int find_other_exec(const char *argv0, const char *target, const char *versionstr, char *retpath); /* Windows security token manipulation (in exec.c) */ #ifdef WIN32 extern BOOL AddUserToTokenDacl(HANDLE hToken); #endif #if defined(WIN32) || defined(__CYGWIN__) #define EXE ".exe" #else #define EXE "" #endif #if defined(WIN32) && !defined(__CYGWIN__) #define DEVNULL "nul" /* "con" does not work from the Msys 1.0.10 console (part of MinGW). */ #define DEVTTY "con" #else #define DEVNULL "/dev/null" #define DEVTTY "/dev/tty" #endif /* * Win32 needs double quotes at the beginning and end of system() * strings. If not, it gets confused with multiple quoted strings. * It also requires double-quotes around the executable name and * any files used for redirection. Other args can use single-quotes. * * Generated using Win32 "CMD /?": * * 1. If all of the following conditions are met, then quote characters * on the command line are preserved: * * - no /S switch * - exactly two quote characters * - no special characters between the two quote characters, where special * is one of: &<>()@^| * - there are one or more whitespace characters between the two quote * characters * - the string between the two quote characters is the name of an * executable file. * * 2. Otherwise, old behavior is to see if the first character is a quote * character and if so, strip the leading character and remove the last * quote character on the command line, preserving any text after the last * quote character. */ #if defined(WIN32) && !defined(__CYGWIN__) #define SYSTEMQUOTE "\"" #else #define SYSTEMQUOTE "" #endif /* Portable delay handling */ extern void pg_usleep(long microsec); /* Portable SQL-like case-independent comparisons and conversions */ extern int pg_strcasecmp(const char *s1, const char *s2); extern int pg_strncasecmp(const char *s1, const char *s2, size_t n); extern unsigned char pg_toupper(unsigned char ch); extern unsigned char pg_tolower(unsigned char ch); extern unsigned char pg_ascii_toupper(unsigned char ch); extern unsigned char pg_ascii_tolower(unsigned char ch); #ifdef USE_REPL_SNPRINTF /* * Versions of libintl >= 0.13 try to replace printf() and friends with * macros to their own versions that understand the %$ format. We do the * same, so disable their macros, if they exist. */ #ifdef vsnprintf #undef vsnprintf #endif #ifdef snprintf #undef snprintf #endif #ifdef sprintf #undef sprintf #endif #ifdef vfprintf #undef vfprintf #endif #ifdef fprintf #undef fprintf #endif #ifdef printf #undef printf #endif extern int pg_vsnprintf(char *str, size_t count, const char *fmt, va_list args); extern int pg_snprintf(char *str, size_t count, const char *fmt,...) /* This extension allows gcc to check the format string */ __attribute__((format(PG_PRINTF_ATTRIBUTE, 3, 4))); extern int pg_sprintf(char *str, const char *fmt,...) /* This extension allows gcc to check the format string */ __attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 3))); extern int pg_vfprintf(FILE *stream, const char *fmt, va_list args); extern int pg_fprintf(FILE *stream, const char *fmt,...) /* This extension allows gcc to check the format string */ __attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 3))); extern int pg_printf(const char *fmt,...) /* This extension allows gcc to check the format string */ __attribute__((format(PG_PRINTF_ATTRIBUTE, 1, 2))); /* * The GCC-specific code below prevents the __attribute__(... 'printf') * above from being replaced, and this is required because gcc doesn't * know anything about pg_printf. */ #ifdef __GNUC__ #define vsnprintf(...) pg_vsnprintf(__VA_ARGS__) #define snprintf(...) pg_snprintf(__VA_ARGS__) #define sprintf(...) pg_sprintf(__VA_ARGS__) #define vfprintf(...) pg_vfprintf(__VA_ARGS__) #define fprintf(...) pg_fprintf(__VA_ARGS__) #define printf(...) pg_printf(__VA_ARGS__) #else #define vsnprintf pg_vsnprintf #define snprintf pg_snprintf #define sprintf pg_sprintf #define vfprintf pg_vfprintf #define fprintf pg_fprintf #define printf pg_printf #endif #endif /* USE_REPL_SNPRINTF */ #if defined(WIN32) /* * Versions of libintl >= 0.18? try to replace setlocale() with a macro * to their own versions. Remove the macro, if it exists, because it * ends up calling the wrong version when the backend and libintl use * different versions of msvcrt. */ #if defined(setlocale) #undef setlocale #endif /* * Define our own wrapper macro around setlocale() to work around bugs in * Windows' native setlocale() function. */ extern char *pgwin32_setlocale(int category, const char *locale); #define setlocale(a,b) pgwin32_setlocale(a,b) #endif /* WIN32 */ /* Portable prompt handling */ extern char *simple_prompt(const char *prompt, int maxlen, bool echo); /* * WIN32 doesn't allow descriptors returned by pipe() to be used in select(), * so for that platform we use socket() instead of pipe(). * There is some inconsistency here because sometimes we require pg*, like * pgpipe, but in other cases we define rename to pgrename just on Win32. */ #ifndef WIN32 /* * The function prototypes are not supplied because every C file * includes this file. */ #define pgpipe(a) pipe(a) #define piperead(a,b,c) read(a,b,c) #define pipewrite(a,b,c) write(a,b,c) #else extern int pgpipe(int handles[2]); extern int piperead(int s, char *buf, int len); #define pipewrite(a,b,c) send(a,b,c,0) #define PG_SIGNAL_COUNT 32 #define kill(pid,sig) pgkill(pid,sig) extern int pgkill(int pid, int sig); #endif extern int pclose_check(FILE *stream); /* Global variable holding time zone information. */ #ifndef __CYGWIN__ #define TIMEZONE_GLOBAL timezone #define TZNAME_GLOBAL tzname #else #define TIMEZONE_GLOBAL _timezone #define TZNAME_GLOBAL _tzname #endif #if defined(WIN32) || defined(__CYGWIN__) /* * Win32 doesn't have reliable rename/unlink during concurrent access. */ extern int pgrename(const char *from, const char *to); extern int pgunlink(const char *path); /* Include this first so later includes don't see these defines */ #ifdef WIN32_ONLY_COMPILER #include #endif #define rename(from, to) pgrename(from, to) #define unlink(path) pgunlink(path) #endif /* defined(WIN32) || defined(__CYGWIN__) */ /* * Win32 also doesn't have symlinks, but we can emulate them with * junction points on newer Win32 versions. * * Cygwin has its own symlinks which work on Win95/98/ME where * junction points don't, so use those instead. We have no way of * knowing what type of system Cygwin binaries will be run on. * Note: Some CYGWIN includes might #define WIN32. */ #if defined(WIN32) && !defined(__CYGWIN__) extern int pgsymlink(const char *oldpath, const char *newpath); extern int pgreadlink(const char *path, char *buf, size_t size); extern bool pgwin32_is_junction(char *path); #define symlink(oldpath, newpath) pgsymlink(oldpath, newpath) #define readlink(path, buf, size) pgreadlink(path, buf, size) #endif extern bool rmtree(const char *path, bool rmtopdir); /* * stat() is not guaranteed to set the st_size field on win32, so we * redefine it to our own implementation that is. * * We must pull in sys/stat.h here so the system header definition * goes in first, and we redefine that, and not the other way around. * * Some frontends don't need the size from stat, so if UNSAFE_STAT_OK * is defined we don't bother with this. */ #if defined(WIN32) && !defined(__CYGWIN__) && !defined(UNSAFE_STAT_OK) #include extern int pgwin32_safestat(const char *path, struct stat * buf); #define stat(a,b) pgwin32_safestat(a,b) #endif #if defined(WIN32) && !defined(__CYGWIN__) /* * open() and fopen() replacements to allow deletion of open files and * passing of other special options. */ #define O_DIRECT 0x80000000 extern int pgwin32_open(const char *, int,...); extern FILE *pgwin32_fopen(const char *, const char *); #ifndef FRONTEND #define open(a,b,c) pgwin32_open(a,b,c) #define fopen(a,b) pgwin32_fopen(a,b) #endif #ifndef popen #define popen(a,b) _popen(a,b) #endif #ifndef pclose #define pclose(a) _pclose(a) #endif /* New versions of MingW have gettimeofday, old mingw and msvc don't */ #ifndef HAVE_GETTIMEOFDAY /* Last parameter not used */ extern int gettimeofday(struct timeval * tp, struct timezone * tzp); #endif #else /* !WIN32 */ /* * Win32 requires a special close for sockets and pipes, while on Unix * close() does them all. */ #define closesocket close #endif /* WIN32 */ /* * Default "extern" declarations or macro substitutes for library routines. * When necessary, these routines are provided by files in src/port/. */ #ifndef HAVE_CRYPT extern char *crypt(const char *key, const char *setting); #endif /* WIN32 handled in port/win32.h */ #ifndef WIN32 #define pgoff_t off_t #if defined(__bsdi__) || defined(__NetBSD__) extern int fseeko(FILE *stream, off_t offset, int whence); extern off_t ftello(FILE *stream); #endif #endif #ifndef HAVE_ERAND48 /* we assume all of these are present or missing together */ extern double erand48(unsigned short xseed[3]); extern long lrand48(void); extern void srand48(long seed); #endif #ifndef HAVE_FSEEKO #define fseeko(a, b, c) fseek(a, b, c) #define ftello(a) ftell(a) #endif #ifndef HAVE_GETOPT extern int getopt(int nargc, char *const * nargv, const char *ostr); #endif #if !defined(HAVE_GETPEEREID) && !defined(WIN32) extern int getpeereid(int sock, uid_t *uid, gid_t *gid); #endif #ifndef HAVE_ISINF extern int isinf(double x); #endif #ifndef HAVE_RINT extern double rint(double x); #endif #ifndef HAVE_INET_ATON #include #include extern int inet_aton(const char *cp, struct in_addr * addr); #endif #ifndef HAVE_STRDUP extern char *strdup(const char *str); #endif #if !HAVE_DECL_STRLCAT extern size_t strlcat(char *dst, const char *src, size_t siz); #endif #if !HAVE_DECL_STRLCPY extern size_t strlcpy(char *dst, const char *src, size_t siz); #endif #if !defined(HAVE_RANDOM) && !defined(__BORLANDC__) extern long random(void); #endif #ifndef HAVE_UNSETENV extern void unsetenv(const char *name); #endif #ifndef HAVE_SRANDOM extern void srandom(unsigned int seed); #endif /* thread.h */ extern char *pqStrerror(int errnum, char *strerrbuf, size_t buflen); #if !defined(WIN32) || defined(__CYGWIN__) extern int pqGetpwuid(uid_t uid, struct passwd * resultbuf, char *buffer, size_t buflen, struct passwd ** result); #endif extern int pqGethostbyname(const char *name, struct hostent * resultbuf, char *buffer, size_t buflen, struct hostent ** result, int *herrno); extern void pg_qsort(void *base, size_t nel, size_t elsize, int (*cmp) (const void *, const void *)); #define qsort(a,b,c,d) pg_qsort(a,b,c,d) typedef int (*qsort_arg_comparator) (const void *a, const void *b, void *arg); extern void qsort_arg(void *base, size_t nel, size_t elsize, qsort_arg_comparator cmp, void *arg); /* port/chklocale.c */ extern int pg_get_encoding_from_locale(const char *ctype, bool write_message); /* port/inet_net_ntop.c */ extern char *inet_net_ntop(int af, const void *src, int bits, char *dst, size_t size); /* port/pgcheckdir.c */ extern int pg_check_dir(const char *dir); /* port/pgmkdirp.c */ extern int pg_mkdir_p(char *path, int omode); #endif /* PG_PORT_H */ RPostgreSQL/src/libpq/Makefile.win0000644000176000001440000001042111711132675016563 0ustar ripleyusers#------------------------------------------------------------------------- # # Makefile for src/interfaces/libpq library # # Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/interfaces/libpq/Makefile # #------------------------------------------------------------------------- subdir = src/interfaces/libpq top_builddir = .. ifeq "$(WIN)" "64" include Makefile.global.win64 else include Makefile.global.win32 endif all: pg_config.h pg_config_os.h pg_config.h: pg_config.h.win cp pg_config.h.win pg_config.h pg_config_os.h: pg_config_os.h.win cp pg_config_os.h.win pg_config_os.h pg_config_paths.h: pg_config_paths.h.win cp pg_config_paths.h.win pg_config_paths.h # shared library parameters NAME= pq SO_MAJOR_VERSION= 5 SO_MINOR_VERSION= 4 override CPPFLAGS := -DFRONTEND -DUNSAFE_STAT_OK -I$(srcdir) $(CPPFLAGS) -Iwininclude ifneq ($(PORTNAME), win32) override CFLAGS += $(PTHREAD_CFLAGS) endif # Need to recompile any external C files because we need # all object files to use the same compile flags as libpq; some # platforms require special flags. LIBS := $(LIBS:-lpgport=) # We can't use Makefile variables here because the MSVC build system scrapes # OBJS from this file. OBJS= fe-auth.o fe-connect.o fe-exec.o fe-misc.o fe-print.o fe-lobj.o \ fe-protocol2.o fe-protocol3.o pqexpbuffer.o pqsignal.o fe-secure.o \ libpq-events.o # libpgport C files we always use OBJS += chklocale.o inet_net_ntop.o noblock.o pgstrcasecmp.o thread.o # libpgport C files that are needed if identified by configure OBJS += $(filter crypt.o getaddrinfo.o getpeereid.o inet_aton.o open.o snprintf.o strerror.o strlcpy.o win32error.o win32setlocale.o, $(LIBOBJS)) # backend/libpq OBJS += ip.o md5.o # utils/mb OBJS += encnames.o wchar.o ifeq ($(PORTNAME), cygwin) override shlib = cyg$(NAME)$(DLSUFFIX) endif ifeq ($(PORTNAME), win32) # pgsleep.o is from libpgport OBJS += pgsleep.o win32.o libpqrc.o libpqrc.o: libpq.rc $(WINDRES) -i $< -o $@ ifeq ($(enable_thread_safety), yes) OBJS += pthread-win32.o endif endif # Add libraries that libpq depends (or might depend) on into the # shared library link. (The order in which you list them here doesn't # matter.) ifneq ($(PORTNAME), win32) SHLIB_LINK += $(filter -lcrypt -ldes -lcom_err -lcrypto -lk5crypto -lkrb5 -lgssapi_krb5 -lgss -lgssapi -lssl -lsocket -lnsl -lresolv -lintl, $(LIBS)) $(LDAP_LIBS_FE) $(PTHREAD_LIBS) else SHLIB_LINK += $(filter -lcrypt -ldes -lcom_err -lcrypto -lk5crypto -lkrb5 -lgssapi32 -lssl -lsocket -lnsl -lresolv -lintl $(PTHREAD_LIBS), $(LIBS)) $(LDAP_LIBS_FE) endif ifeq ($(PORTNAME), win32) SHLIB_LINK += -lshfolder -lwsock32 -lws2_32 -lsecur32 $(filter -leay32 -lssleay32 -lcomerr32 -lkrb5_32, $(LIBS)) endif SHLIB_EXPORTS = exports.txt all: all-static-lib # Shared library stuff include Makefile.shlib distprep: libpq-dist.rc libpq.rc libpq-dist.rc: libpq.rc.in sed -e 's/\(VERSION.*\),0 *$$/\1,'`date '+%y%j' | sed 's/^0*//'`'/' $< >$@ # Depend on Makefile.global to force rebuild on re-run of configure. # (But libpq-dist.rc is shipped in the distribution for shell-less # installations and is only updated by distprep.) # libpq.rc: Makefile.global #not for static port fe-connect.o: fe-connect.c pg_config_paths.h install: all installdirs install-lib $(INSTALL_DATA) $(srcdir)/libpq-fe.h '$(DESTDIR)$(includedir)' $(INSTALL_DATA) $(srcdir)/libpq-events.h '$(DESTDIR)$(includedir)' $(INSTALL_DATA) $(srcdir)/libpq-int.h '$(DESTDIR)$(includedir_internal)' $(INSTALL_DATA) $(srcdir)/pqexpbuffer.h '$(DESTDIR)$(includedir_internal)' $(INSTALL_DATA) $(srcdir)/pg_service.conf.sample '$(DESTDIR)$(datadir)/pg_service.conf.sample' installdirs: installdirs-lib $(MKDIR_P) '$(DESTDIR)$(includedir)' '$(DESTDIR)$(includedir_internal)' uninstall: uninstall-lib rm -f '$(DESTDIR)$(includedir)/libpq-fe.h' rm -f '$(DESTDIR)$(includedir)/libpq-events.h' rm -f '$(DESTDIR)$(includedir_internal)/libpq-int.h' rm -f '$(DESTDIR)$(includedir_internal)/pqexpbuffer.h' rm -f '$(DESTDIR)$(datadir)/pg_service.conf.sample' clean distclean: clean-lib rm -f $(OBJS) pthread.h libpq.rc # Might be left over from a Win32 client-only build rm -f pg_config.h rm -f pg_config_os.h rm -f pg_config_paths.h maintainer-clean: distclean maintainer-clean-lib rm -f libpq-dist.rc RPostgreSQL/src/libpq/pgstrcasecmp.c0000644000176000001440000000701512124517222017165 0ustar ripleyusers/*------------------------------------------------------------------------- * * pgstrcasecmp.c * Portable SQL-like case-independent comparisons and conversions. * * SQL99 specifies Unicode-aware case normalization, which we don't yet * have the infrastructure for. Instead we use tolower() to provide a * locale-aware translation. However, there are some locales where this * is not right either (eg, Turkish may do strange things with 'i' and * 'I'). Our current compromise is to use tolower() for characters with * the high bit set, and use an ASCII-only downcasing for 7-bit * characters. * * NB: this code should match downcase_truncate_identifier() in scansup.c. * * We also provide strict ASCII-only case conversion functions, which can * be used to implement C/POSIX case folding semantics no matter what the * C library thinks the locale is. * * * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * * src/port/pgstrcasecmp.c * *------------------------------------------------------------------------- */ #include "c.h" #include /* * Case-independent comparison of two null-terminated strings. */ int pg_strcasecmp(const char *s1, const char *s2) { for (;;) { unsigned char ch1 = (unsigned char) *s1++; unsigned char ch2 = (unsigned char) *s2++; if (ch1 != ch2) { if (ch1 >= 'A' && ch1 <= 'Z') ch1 += 'a' - 'A'; else if (IS_HIGHBIT_SET(ch1) && isupper(ch1)) ch1 = tolower(ch1); if (ch2 >= 'A' && ch2 <= 'Z') ch2 += 'a' - 'A'; else if (IS_HIGHBIT_SET(ch2) && isupper(ch2)) ch2 = tolower(ch2); if (ch1 != ch2) return (int) ch1 - (int) ch2; } if (ch1 == 0) break; } return 0; } /* * Case-independent comparison of two not-necessarily-null-terminated strings. * At most n bytes will be examined from each string. */ int pg_strncasecmp(const char *s1, const char *s2, size_t n) { while (n-- > 0) { unsigned char ch1 = (unsigned char) *s1++; unsigned char ch2 = (unsigned char) *s2++; if (ch1 != ch2) { if (ch1 >= 'A' && ch1 <= 'Z') ch1 += 'a' - 'A'; else if (IS_HIGHBIT_SET(ch1) && isupper(ch1)) ch1 = tolower(ch1); if (ch2 >= 'A' && ch2 <= 'Z') ch2 += 'a' - 'A'; else if (IS_HIGHBIT_SET(ch2) && isupper(ch2)) ch2 = tolower(ch2); if (ch1 != ch2) return (int) ch1 - (int) ch2; } if (ch1 == 0) break; } return 0; } /* * Fold a character to upper case. * * Unlike some versions of toupper(), this is safe to apply to characters * that aren't lower case letters. Note however that the whole thing is * a bit bogus for multibyte character sets. */ unsigned char pg_toupper(unsigned char ch) { if (ch >= 'a' && ch <= 'z') ch += 'A' - 'a'; else if (IS_HIGHBIT_SET(ch) && islower(ch)) ch = toupper(ch); return ch; } /* * Fold a character to lower case. * * Unlike some versions of tolower(), this is safe to apply to characters * that aren't upper case letters. Note however that the whole thing is * a bit bogus for multibyte character sets. */ unsigned char pg_tolower(unsigned char ch) { if (ch >= 'A' && ch <= 'Z') ch += 'a' - 'A'; else if (IS_HIGHBIT_SET(ch) && isupper(ch)) ch = tolower(ch); return ch; } /* * Fold a character to upper case, following C/POSIX locale rules. */ unsigned char pg_ascii_toupper(unsigned char ch) { if (ch >= 'a' && ch <= 'z') ch += 'A' - 'a'; return ch; } /* * Fold a character to lower case, following C/POSIX locale rules. */ unsigned char pg_ascii_tolower(unsigned char ch) { if (ch >= 'A' && ch <= 'Z') ch += 'a' - 'A'; return ch; } RPostgreSQL/src/libpq/libpq/0000755000176000001440000000000012124517222015432 5ustar ripleyusersRPostgreSQL/src/libpq/libpq/libpq-fs.h0000644000176000001440000000117112124517222017320 0ustar ripleyusers/*------------------------------------------------------------------------- * * libpq-fs.h * definitions for using Inversion file system routines (ie, large objects) * * * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/libpq/libpq-fs.h * *------------------------------------------------------------------------- */ #ifndef LIBPQ_FS_H #define LIBPQ_FS_H /* * Read/write mode flags for inversion (large object) calls */ #define INV_WRITE 0x00020000 #define INV_READ 0x00040000 #endif /* LIBPQ_FS_H */ RPostgreSQL/src/libpq/libpq/auth.h0000644000176000001440000000160712124517222016550 0ustar ripleyusers/*------------------------------------------------------------------------- * * auth.h * Definitions for network authentication routines * * * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/libpq/auth.h * *------------------------------------------------------------------------- */ #ifndef AUTH_H #define AUTH_H #include "libpq/libpq-be.h" extern char *pg_krb_server_keyfile; extern char *pg_krb_srvnam; extern bool pg_krb_caseins_users; extern char *pg_krb_server_hostname; extern char *pg_krb_realm; extern void ClientAuthentication(Port *port); /* Hook for plugins to get control in ClientAuthentication() */ typedef void (*ClientAuthentication_hook_type) (Port *, int); extern PGDLLIMPORT ClientAuthentication_hook_type ClientAuthentication_hook; #endif /* AUTH_H */ RPostgreSQL/src/libpq/libpq/pqsignal.h0000644000176000001440000000242412124517222017423 0ustar ripleyusers/*------------------------------------------------------------------------- * * pqsignal.h * prototypes for the reliable BSD-style signal(2) routine. * * * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/libpq/pqsignal.h * * NOTES * This shouldn't be in libpq, but the monitor and some other * things need it... * *------------------------------------------------------------------------- */ #ifndef PQSIGNAL_H #define PQSIGNAL_H #include #ifdef HAVE_SIGPROCMASK extern sigset_t UnBlockSig, BlockSig, StartupBlockSig; #define PG_SETMASK(mask) sigprocmask(SIG_SETMASK, mask, NULL) #else /* not HAVE_SIGPROCMASK */ extern int UnBlockSig, BlockSig, StartupBlockSig; #ifndef WIN32 #define PG_SETMASK(mask) sigsetmask(*((int*)(mask))) #else #define PG_SETMASK(mask) pqsigsetmask(*((int*)(mask))) int pqsigsetmask(int mask); #endif #define sigaddset(set, signum) (*(set) |= (sigmask(signum))) #define sigdelset(set, signum) (*(set) &= ~(sigmask(signum))) #endif /* not HAVE_SIGPROCMASK */ typedef void (*pqsigfunc) (int); extern void pqinitmask(void); extern pqsigfunc pqsignal(int signo, pqsigfunc func); #endif /* PQSIGNAL_H */ RPostgreSQL/src/libpq/libpq/md5.h0000644000176000001440000000160512124517222016272 0ustar ripleyusers/*------------------------------------------------------------------------- * * md5.h * Interface to libpq/md5.c * * These definitions are needed by both frontend and backend code to work * with MD5-encrypted passwords. * * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/libpq/md5.h * *------------------------------------------------------------------------- */ #ifndef PG_MD5_H #define PG_MD5_H #define MD5_PASSWD_LEN 35 #define isMD5(passwd) (strncmp(passwd, "md5", 3) == 0 && \ strlen(passwd) == MD5_PASSWD_LEN) extern bool pg_md5_hash(const void *buff, size_t len, char *hexsum); extern bool pg_md5_binary(const void *buff, size_t len, void *outbuf); extern bool pg_md5_encrypt(const char *passwd, const char *salt, size_t salt_len, char *buf); #endif RPostgreSQL/src/libpq/libpq/pqformat.h0000644000176000001440000000371512124517222017442 0ustar ripleyusers/*------------------------------------------------------------------------- * * pqformat.h * Definitions for formatting and parsing frontend/backend messages * * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/libpq/pqformat.h * *------------------------------------------------------------------------- */ #ifndef PQFORMAT_H #define PQFORMAT_H #include "lib/stringinfo.h" extern void pq_beginmessage(StringInfo buf, char msgtype); extern void pq_sendbyte(StringInfo buf, int byt); extern void pq_sendbytes(StringInfo buf, const char *data, int datalen); extern void pq_sendcountedtext(StringInfo buf, const char *str, int slen, bool countincludesself); extern void pq_sendtext(StringInfo buf, const char *str, int slen); extern void pq_sendstring(StringInfo buf, const char *str); extern void pq_send_ascii_string(StringInfo buf, const char *str); extern void pq_sendint(StringInfo buf, int i, int b); extern void pq_sendint64(StringInfo buf, int64 i); extern void pq_sendfloat4(StringInfo buf, float4 f); extern void pq_sendfloat8(StringInfo buf, float8 f); extern void pq_endmessage(StringInfo buf); extern void pq_begintypsend(StringInfo buf); extern bytea *pq_endtypsend(StringInfo buf); extern void pq_puttextmessage(char msgtype, const char *str); extern void pq_putemptymessage(char msgtype); extern int pq_getmsgbyte(StringInfo msg); extern unsigned int pq_getmsgint(StringInfo msg, int b); extern int64 pq_getmsgint64(StringInfo msg); extern float4 pq_getmsgfloat4(StringInfo msg); extern float8 pq_getmsgfloat8(StringInfo msg); extern const char *pq_getmsgbytes(StringInfo msg, int datalen); extern void pq_copymsgbytes(StringInfo msg, char *buf, int datalen); extern char *pq_getmsgtext(StringInfo msg, int rawbytes, int *nbytes); extern const char *pq_getmsgstring(StringInfo msg); extern void pq_getmsgend(StringInfo msg); #endif /* PQFORMAT_H */ RPostgreSQL/src/libpq/libpq/libpq.h0000644000176000001440000000445012124517222016715 0ustar ripleyusers/*------------------------------------------------------------------------- * * libpq.h * POSTGRES LIBPQ buffer structure definitions. * * * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/libpq/libpq.h * *------------------------------------------------------------------------- */ #ifndef LIBPQ_H #define LIBPQ_H #include #include #include "lib/stringinfo.h" #include "libpq/libpq-be.h" /* ---------------- * PQArgBlock * Information (pointer to array of this structure) required * for the PQfn() call. (This probably ought to go somewhere else...) * ---------------- */ typedef struct { int len; int isint; union { int *ptr; /* can't use void (dec compiler barfs) */ int integer; } u; } PQArgBlock; /* * External functions. */ /* * prototypes for functions in pqcomm.c */ extern int StreamServerPort(int family, char *hostName, unsigned short portNumber, char *unixSocketName, pgsocket ListenSocket[], int MaxListen); extern int StreamConnection(pgsocket server_fd, Port *port); extern void StreamClose(pgsocket sock); extern void TouchSocketFile(void); extern void pq_init(void); extern void pq_comm_reset(void); extern int pq_getbytes(char *s, size_t len); extern int pq_getstring(StringInfo s); extern int pq_getmessage(StringInfo s, int maxlen); extern int pq_getbyte(void); extern int pq_peekbyte(void); extern int pq_getbyte_if_available(unsigned char *c); extern int pq_putbytes(const char *s, size_t len); extern int pq_flush(void); extern int pq_flush_if_writable(void); extern bool pq_is_send_pending(void); extern int pq_putmessage(char msgtype, const char *s, size_t len); extern void pq_putmessage_noblock(char msgtype, const char *s, size_t len); extern void pq_startcopyout(void); extern void pq_endcopyout(bool errorAbort); /* * prototypes for functions in be-secure.c */ extern int secure_initialize(void); extern bool secure_loaded_verify_locations(void); extern void secure_destroy(void); extern int secure_open_server(Port *port); extern void secure_close(Port *port); extern ssize_t secure_read(Port *port, void *ptr, size_t len); extern ssize_t secure_write(Port *port, void *ptr, size_t len); #endif /* LIBPQ_H */ RPostgreSQL/src/libpq/libpq/be-fsstubs.h0000644000176000001440000000311212124517222017655 0ustar ripleyusers/*------------------------------------------------------------------------- * * be-fsstubs.h * * * * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/libpq/be-fsstubs.h * *------------------------------------------------------------------------- */ #ifndef BE_FSSTUBS_H #define BE_FSSTUBS_H #include "fmgr.h" /* * LO functions available via pg_proc entries */ extern Datum lo_import(PG_FUNCTION_ARGS); extern Datum lo_import_with_oid(PG_FUNCTION_ARGS); extern Datum lo_export(PG_FUNCTION_ARGS); extern Datum lo_creat(PG_FUNCTION_ARGS); extern Datum lo_create(PG_FUNCTION_ARGS); extern Datum lo_open(PG_FUNCTION_ARGS); extern Datum lo_close(PG_FUNCTION_ARGS); extern Datum loread(PG_FUNCTION_ARGS); extern Datum lowrite(PG_FUNCTION_ARGS); extern Datum lo_lseek(PG_FUNCTION_ARGS); extern Datum lo_tell(PG_FUNCTION_ARGS); extern Datum lo_unlink(PG_FUNCTION_ARGS); extern Datum lo_truncate(PG_FUNCTION_ARGS); /* * compatibility option for access control */ extern bool lo_compat_privileges; /* * These are not fmgr-callable, but are available to C code. * Probably these should have had the underscore-free names, * but too late now... */ extern int lo_read(int fd, char *buf, int len); extern int lo_write(int fd, const char *buf, int len); /* * Cleanup LOs at xact commit/abort */ extern void AtEOXact_LargeObject(bool isCommit); extern void AtEOSubXact_LargeObject(bool isCommit, SubTransactionId mySubid, SubTransactionId parentSubid); #endif /* BE_FSSTUBS_H */ RPostgreSQL/src/libpq/libpq/pqcomm.h0000644000176000001440000001325012124517222017100 0ustar ripleyusers/*------------------------------------------------------------------------- * * pqcomm.h * Definitions common to frontends and backends. * * NOTE: for historical reasons, this does not correspond to pqcomm.c. * pqcomm.c's routines are declared in libpq.h. * * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/libpq/pqcomm.h * *------------------------------------------------------------------------- */ #ifndef PQCOMM_H #define PQCOMM_H #include #include #ifdef HAVE_SYS_UN_H #include #endif #include #ifdef HAVE_STRUCT_SOCKADDR_STORAGE #ifndef HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY #ifdef HAVE_STRUCT_SOCKADDR_STORAGE___SS_FAMILY #define ss_family __ss_family #else #error struct sockaddr_storage does not provide an ss_family member #endif #endif #ifdef HAVE_STRUCT_SOCKADDR_STORAGE___SS_LEN #define ss_len __ss_len #define HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN 1 #endif #else /* !HAVE_STRUCT_SOCKADDR_STORAGE */ /* Define a struct sockaddr_storage if we don't have one. */ struct sockaddr_storage { union { struct sockaddr sa; /* get the system-dependent fields */ int64 ss_align; /* ensures struct is properly aligned */ char ss_pad[128]; /* ensures struct has desired size */ } ss_stuff; }; #define ss_family ss_stuff.sa.sa_family /* It should have an ss_len field if sockaddr has sa_len. */ #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN #define ss_len ss_stuff.sa.sa_len #define HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN 1 #endif #endif /* HAVE_STRUCT_SOCKADDR_STORAGE */ typedef struct { struct sockaddr_storage addr; ACCEPT_TYPE_ARG3 salen; } SockAddr; /* Configure the UNIX socket location for the well known port. */ #define UNIXSOCK_PATH(path, port, sockdir) \ snprintf(path, sizeof(path), "%s/.s.PGSQL.%d", \ ((sockdir) && *(sockdir) != '\0') ? (sockdir) : \ DEFAULT_PGSOCKET_DIR, \ (port)) /* * These manipulate the frontend/backend protocol version number. * * The major number should be incremented for incompatible changes. The minor * number should be incremented for compatible changes (eg. additional * functionality). * * If a backend supports version m.n of the protocol it must actually support * versions m.[0..n]. Backend support for version m-1 can be dropped after a * `reasonable' length of time. * * A frontend isn't required to support anything other than the current * version. */ #define PG_PROTOCOL_MAJOR(v) ((v) >> 16) #define PG_PROTOCOL_MINOR(v) ((v) & 0x0000ffff) #define PG_PROTOCOL(m,n) (((m) << 16) | (n)) /* The earliest and latest frontend/backend protocol version supported. */ #define PG_PROTOCOL_EARLIEST PG_PROTOCOL(1,0) #define PG_PROTOCOL_LATEST PG_PROTOCOL(3,0) typedef uint32 ProtocolVersion; /* FE/BE protocol version number */ typedef ProtocolVersion MsgType; /* * Packet lengths are 4 bytes in network byte order. * * The initial length is omitted from the packet layouts appearing below. */ typedef uint32 PacketLen; /* * Old-style startup packet layout with fixed-width fields. This is used in * protocol 1.0 and 2.0, but not in later versions. Note that the fields * in this layout are '\0' terminated only if there is room. */ #define SM_DATABASE 64 #define SM_USER 32 /* We append database name if db_user_namespace true. */ #define SM_DATABASE_USER (SM_DATABASE+SM_USER+1) /* +1 for @ */ #define SM_OPTIONS 64 #define SM_UNUSED 64 #define SM_TTY 64 typedef struct StartupPacket { ProtocolVersion protoVersion; /* Protocol version */ char database[SM_DATABASE]; /* Database name */ /* Db_user_namespace appends dbname */ char user[SM_USER]; /* User name */ char options[SM_OPTIONS]; /* Optional additional args */ char unused[SM_UNUSED]; /* Unused */ char tty[SM_TTY]; /* Tty for debug output */ } StartupPacket; extern bool Db_user_namespace; /* * In protocol 3.0 and later, the startup packet length is not fixed, but * we set an arbitrary limit on it anyway. This is just to prevent simple * denial-of-service attacks via sending enough data to run the server * out of memory. */ #define MAX_STARTUP_PACKET_LENGTH 10000 /* These are the authentication request codes sent by the backend. */ #define AUTH_REQ_OK 0 /* User is authenticated */ #define AUTH_REQ_KRB4 1 /* Kerberos V4. Not supported any more. */ #define AUTH_REQ_KRB5 2 /* Kerberos V5 */ #define AUTH_REQ_PASSWORD 3 /* Password */ #define AUTH_REQ_CRYPT 4 /* crypt password. Not supported any more. */ #define AUTH_REQ_MD5 5 /* md5 password */ #define AUTH_REQ_SCM_CREDS 6 /* transfer SCM credentials */ #define AUTH_REQ_GSS 7 /* GSSAPI without wrap() */ #define AUTH_REQ_GSS_CONT 8 /* Continue GSS exchanges */ #define AUTH_REQ_SSPI 9 /* SSPI negotiate without wrap() */ typedef uint32 AuthRequest; /* * A client can also send a cancel-current-operation request to the postmaster. * This is uglier than sending it directly to the client's backend, but it * avoids depending on out-of-band communication facilities. * * The cancel request code must not match any protocol version number * we're ever likely to use. This random choice should do. */ #define CANCEL_REQUEST_CODE PG_PROTOCOL(1234,5678) typedef struct CancelRequestPacket { /* Note that each field is stored in network byte order! */ MsgType cancelRequestCode; /* code to identify a cancel request */ uint32 backendPID; /* PID of client's backend */ uint32 cancelAuthCode; /* secret key to authorize cancel */ } CancelRequestPacket; /* * A client can also start by sending a SSL negotiation request, to get a * secure channel. */ #define NEGOTIATE_SSL_CODE PG_PROTOCOL(1234,5679) #endif /* PQCOMM_H */ RPostgreSQL/src/libpq/libpq/ip.h0000644000176000001440000000316412124517222016217 0ustar ripleyusers/*------------------------------------------------------------------------- * * ip.h * Definitions for IPv6-aware network access. * * These definitions are used by both frontend and backend code. Be careful * what you include here! * * Copyright (c) 2003-2011, PostgreSQL Global Development Group * * src/include/libpq/ip.h * *------------------------------------------------------------------------- */ #ifndef IP_H #define IP_H #include "getaddrinfo.h" #include "libpq/pqcomm.h" #ifdef HAVE_UNIX_SOCKETS #define IS_AF_UNIX(fam) ((fam) == AF_UNIX) #else #define IS_AF_UNIX(fam) (0) #endif typedef void (*PgIfAddrCallback) (struct sockaddr * addr, struct sockaddr * netmask, void *cb_data); extern int pg_getaddrinfo_all(const char *hostname, const char *servname, const struct addrinfo * hintp, struct addrinfo ** result); extern void pg_freeaddrinfo_all(int hint_ai_family, struct addrinfo * ai); extern int pg_getnameinfo_all(const struct sockaddr_storage * addr, int salen, char *node, int nodelen, char *service, int servicelen, int flags); extern int pg_range_sockaddr(const struct sockaddr_storage * addr, const struct sockaddr_storage * netaddr, const struct sockaddr_storage * netmask); extern int pg_sockaddr_cidr_mask(struct sockaddr_storage * mask, char *numbits, int family); #ifdef HAVE_IPV6 extern void pg_promote_v4_to_v6_addr(struct sockaddr_storage * addr); extern void pg_promote_v4_to_v6_mask(struct sockaddr_storage * addr); #endif extern int pg_foreach_ifaddr(PgIfAddrCallback callback, void *cb_data); #endif /* IP_H */ RPostgreSQL/src/libpq/libpq/crypt.h0000644000176000001440000000104612124517222016745 0ustar ripleyusers/*------------------------------------------------------------------------- * * crypt.h * Interface to libpq/crypt.c * * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/libpq/crypt.h * *------------------------------------------------------------------------- */ #ifndef PG_CRYPT_H #define PG_CRYPT_H #include "libpq/libpq-be.h" extern int md5_crypt_verify(const Port *port, const char *user, char *client_pass); #endif RPostgreSQL/src/libpq/libpq/hba.h0000644000176000001440000000327012124517222016337 0ustar ripleyusers/*------------------------------------------------------------------------- * * hba.h * Interface to hba.c * * * src/include/libpq/hba.h * *------------------------------------------------------------------------- */ #ifndef HBA_H #define HBA_H #include "nodes/pg_list.h" #include "libpq/pqcomm.h" typedef enum UserAuth { uaReject, uaImplicitReject, uaKrb5, uaTrust, uaIdent, uaPassword, uaMD5, uaGSS, uaSSPI, uaPAM, uaLDAP, uaCert, uaRADIUS, uaPeer } UserAuth; typedef enum IPCompareMethod { ipCmpMask, ipCmpSameHost, ipCmpSameNet, ipCmpAll } IPCompareMethod; typedef enum ConnType { ctLocal, ctHost, ctHostSSL, ctHostNoSSL } ConnType; typedef struct { int linenumber; ConnType conntype; char *database; char *role; struct sockaddr_storage addr; struct sockaddr_storage mask; IPCompareMethod ip_cmp_method; char *hostname; UserAuth auth_method; char *usermap; char *pamservice; bool ldaptls; char *ldapserver; int ldapport; char *ldapbinddn; char *ldapbindpasswd; char *ldapsearchattribute; char *ldapbasedn; char *ldapprefix; char *ldapsuffix; bool clientcert; char *krb_server_hostname; char *krb_realm; bool include_realm; char *radiusserver; char *radiussecret; char *radiusidentifier; int radiusport; } HbaLine; /* kluge to avoid including libpq/libpq-be.h here */ typedef struct Port hbaPort; extern bool load_hba(void); extern void load_ident(void); extern int hba_getauthmethod(hbaPort *port); extern int check_usermap(const char *usermap_name, const char *pg_role, const char *auth_user, bool case_sensitive); extern bool pg_isblank(const char c); #endif /* HBA_H */ RPostgreSQL/src/libpq/libpq/libpq-be.h0000644000176000001440000001275712124517222017312 0ustar ripleyusers/*------------------------------------------------------------------------- * * libpq_be.h * This file contains definitions for structures and externs used * by the postmaster during client authentication. * * Note that this is backend-internal and is NOT exported to clients. * Structs that need to be client-visible are in pqcomm.h. * * * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/libpq/libpq-be.h * *------------------------------------------------------------------------- */ #ifndef LIBPQ_BE_H #define LIBPQ_BE_H #ifdef HAVE_SYS_TIME_H #include #endif #ifdef USE_SSL #include #include #endif #ifdef HAVE_NETINET_TCP_H #include #endif #ifdef ENABLE_GSS #if defined(HAVE_GSSAPI_H) #include #else #include #endif /* HAVE_GSSAPI_H */ /* * GSSAPI brings in headers that set a lot of things in the global namespace on win32, * that doesn't match the msvc build. It gives a bunch of compiler warnings that we ignore, * but also defines a symbol that simply does not exist. Undefine it again. */ #ifdef WIN32_ONLY_COMPILER #undef HAVE_GETADDRINFO #endif #endif /* ENABLE_GSS */ #ifdef ENABLE_SSPI #define SECURITY_WIN32 #if defined(WIN32) && !defined(WIN32_ONLY_COMPILER) #include #endif #include #undef SECURITY_WIN32 #ifndef ENABLE_GSS /* * Define a fake structure compatible with GSSAPI on Unix. */ typedef struct { void *value; int length; } gss_buffer_desc; #endif #endif /* ENABLE_SSPI */ #include "libpq/hba.h" #include "libpq/pqcomm.h" #include "utils/timestamp.h" typedef enum CAC_state { CAC_OK, CAC_STARTUP, CAC_SHUTDOWN, CAC_RECOVERY, CAC_TOOMANY, CAC_WAITBACKUP } CAC_state; /* * GSSAPI specific state information */ #if defined(ENABLE_GSS) | defined(ENABLE_SSPI) typedef struct { gss_buffer_desc outbuf; /* GSSAPI output token buffer */ #ifdef ENABLE_GSS gss_cred_id_t cred; /* GSSAPI connection cred's */ gss_ctx_id_t ctx; /* GSSAPI connection context */ gss_name_t name; /* GSSAPI client name */ #endif } pg_gssinfo; #endif /* * This is used by the postmaster in its communication with frontends. It * contains all state information needed during this communication before the * backend is run. The Port structure is kept in malloc'd memory and is * still available when a backend is running (see MyProcPort). The data * it points to must also be malloc'd, or else palloc'd in TopMemoryContext, * so that it survives into PostgresMain execution! */ typedef struct Port { pgsocket sock; /* File descriptor */ bool noblock; /* is the socket in non-blocking mode? */ ProtocolVersion proto; /* FE/BE protocol version */ SockAddr laddr; /* local addr (postmaster) */ SockAddr raddr; /* remote addr (client) */ char *remote_host; /* name (or ip addr) of remote host */ char *remote_hostname;/* name (not ip addr) of remote host, if * available */ int remote_hostname_resolv; /* +1 = remote_hostname is known to * resolve to client's IP address; -1 * = remote_hostname is known NOT to * resolve to client's IP address; 0 = * we have not done the forward DNS * lookup yet */ char *remote_port; /* text rep of remote port */ CAC_state canAcceptConnections; /* postmaster connection status */ /* * Information that needs to be saved from the startup packet and passed * into backend execution. "char *" fields are NULL if not set. * guc_options points to a List of alternating option names and values. */ char *database_name; char *user_name; char *cmdline_options; List *guc_options; /* * Information that needs to be held during the authentication cycle. */ HbaLine *hba; char md5Salt[4]; /* Password salt */ /* * Information that really has no business at all being in struct Port, * but since it gets used by elog.c in the same way as database_name and * other members of this struct, we may as well keep it here. */ TimestampTz SessionStartTime; /* backend start time */ /* * TCP keepalive settings. * * default values are 0 if AF_UNIX or not yet known; current values are 0 * if AF_UNIX or using the default. Also, -1 in a default value means we * were unable to find out the default (getsockopt failed). */ int default_keepalives_idle; int default_keepalives_interval; int default_keepalives_count; int keepalives_idle; int keepalives_interval; int keepalives_count; #if defined(ENABLE_GSS) || defined(ENABLE_SSPI) /* * If GSSAPI is supported, store GSSAPI information. Oterwise, store a * NULL pointer to make sure offsets in the struct remain the same. */ pg_gssinfo *gss; #else void *gss; #endif /* * SSL structures (keep these last so that USE_SSL doesn't affect * locations of other fields) */ #ifdef USE_SSL SSL *ssl; X509 *peer; char peer_dn[128 + 1]; char peer_cn[SM_USER + 1]; unsigned long count; #endif } Port; extern ProtocolVersion FrontendProtocol; /* TCP keepalives configuration. These are no-ops on an AF_UNIX socket. */ extern int pq_getkeepalivesidle(Port *port); extern int pq_getkeepalivesinterval(Port *port); extern int pq_getkeepalivescount(Port *port); extern int pq_setkeepalivesidle(int idle, Port *port); extern int pq_setkeepalivesinterval(int interval, Port *port); extern int pq_setkeepalivescount(int count, Port *port); #endif /* LIBPQ_BE_H */ RPostgreSQL/src/libpq/fe-print.c0000644000176000001440000004071212124517222016217 0ustar ripleyusers/*------------------------------------------------------------------------- * * fe-print.c * functions for pretty-printing query results * * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * These functions were formerly part of fe-exec.c, but they * didn't really belong there. * * IDENTIFICATION * src/interfaces/libpq/fe-print.c * *------------------------------------------------------------------------- */ #include "postgres_fe.h" #include #ifdef WIN32 #include "win32.h" #else #include #include #endif #ifdef HAVE_TERMIOS_H #include #else #ifndef WIN32 #include #endif #endif #include "libpq-fe.h" #include "libpq-int.h" #include "pqsignal.h" static void do_field(const PQprintOpt *po, const PGresult *res, const int i, const int j, const int fs_len, char **fields, const int nFields, const char **fieldNames, unsigned char *fieldNotNum, int *fieldMax, const int fieldMaxLen, FILE *fout); static char *do_header(FILE *fout, const PQprintOpt *po, const int nFields, int *fieldMax, const char **fieldNames, unsigned char *fieldNotNum, const int fs_len, const PGresult *res); static void output_row(FILE *fout, const PQprintOpt *po, const int nFields, char **fields, unsigned char *fieldNotNum, int *fieldMax, char *border, const int row_index); static void fill(int length, int max, char filler, FILE *fp); /* * PQprint() * * Format results of a query for printing. * * PQprintOpt is a typedef (structure) that containes * various flags and options. consult libpq-fe.h for * details * * This function should probably be removed sometime since psql * doesn't use it anymore. It is unclear to what extent this is used * by external clients, however. */ void PQprint(FILE *fout, const PGresult *res, const PQprintOpt *po) { int nFields; nFields = PQnfields(res); if (nFields > 0) { /* only print rows with at least 1 field. */ int i, j; int nTups; int *fieldMax = NULL; /* in case we don't use them */ unsigned char *fieldNotNum = NULL; char *border = NULL; char **fields = NULL; const char **fieldNames; int fieldMaxLen = 0; int numFieldName; int fs_len = strlen(po->fieldSep); int total_line_length = 0; int usePipe = 0; char *pagerenv; #if defined(ENABLE_THREAD_SAFETY) && !defined(WIN32) sigset_t osigset; bool sigpipe_masked = false; bool sigpipe_pending; #endif #if !defined(ENABLE_THREAD_SAFETY) && !defined(WIN32) pqsigfunc oldsigpipehandler = NULL; #endif #ifdef TIOCGWINSZ struct winsize screen_size; #else struct winsize { int ws_row; int ws_col; } screen_size; #endif nTups = PQntuples(res); if (!(fieldNames = (const char **) calloc(nFields, sizeof(char *)))) { fprintf(stderr, libpq_gettext("out of memory\n")); exit(1); } if (!(fieldNotNum = (unsigned char *) calloc(nFields, 1))) { fprintf(stderr, libpq_gettext("out of memory\n")); exit(1); } if (!(fieldMax = (int *) calloc(nFields, sizeof(int)))) { fprintf(stderr, libpq_gettext("out of memory\n")); exit(1); } for (numFieldName = 0; po->fieldName && po->fieldName[numFieldName]; numFieldName++) ; for (j = 0; j < nFields; j++) { int len; const char *s = (j < numFieldName && po->fieldName[j][0]) ? po->fieldName[j] : PQfname(res, j); fieldNames[j] = s; len = s ? strlen(s) : 0; fieldMax[j] = len; len += fs_len; if (len > fieldMaxLen) fieldMaxLen = len; total_line_length += len; } total_line_length += nFields * strlen(po->fieldSep) + 1; if (fout == NULL) fout = stdout; if (po->pager && fout == stdout && isatty(fileno(stdin)) && isatty(fileno(stdout))) { /* * If we think there'll be more than one screen of output, try to * pipe to the pager program. */ #ifdef TIOCGWINSZ if (ioctl(fileno(stdout), TIOCGWINSZ, &screen_size) == -1 || screen_size.ws_col == 0 || screen_size.ws_row == 0) { screen_size.ws_row = 24; screen_size.ws_col = 80; } #else screen_size.ws_row = 24; screen_size.ws_col = 80; #endif pagerenv = getenv("PAGER"); if (pagerenv != NULL && pagerenv[0] != '\0' && !po->html3 && ((po->expanded && nTups * (nFields + 1) >= screen_size.ws_row) || (!po->expanded && nTups * (total_line_length / screen_size.ws_col + 1) * (1 + (po->standard != 0)) >= screen_size.ws_row - (po->header != 0) * (total_line_length / screen_size.ws_col + 1) * 2 - (po->header != 0) * 2 /* row count and newline */ ))) { fout = popen(pagerenv, "w"); if (fout) { usePipe = 1; #ifndef WIN32 #ifdef ENABLE_THREAD_SAFETY if (pq_block_sigpipe(&osigset, &sigpipe_pending) == 0) sigpipe_masked = true; #else oldsigpipehandler = pqsignal(SIGPIPE, SIG_IGN); #endif /* ENABLE_THREAD_SAFETY */ #endif /* WIN32 */ } else fout = stdout; } } if (!po->expanded && (po->align || po->html3)) { if (!(fields = (char **) calloc(nFields * (nTups + 1), sizeof(char *)))) { fprintf(stderr, libpq_gettext("out of memory\n")); exit(1); } } else if (po->header && !po->html3) { if (po->expanded) { if (po->align) fprintf(fout, libpq_gettext("%-*s%s Value\n"), fieldMaxLen - fs_len, libpq_gettext("Field"), po->fieldSep); else fprintf(fout, libpq_gettext("%s%sValue\n"), libpq_gettext("Field"), po->fieldSep); } else { int len = 0; for (j = 0; j < nFields; j++) { const char *s = fieldNames[j]; fputs(s, fout); len += strlen(s) + fs_len; if ((j + 1) < nFields) fputs(po->fieldSep, fout); } fputc('\n', fout); for (len -= fs_len; len--; fputc('-', fout)); fputc('\n', fout); } } if (po->expanded && po->html3) { if (po->caption) fprintf(fout, "

%s

\n", po->caption); else fprintf(fout, "

" "Query retrieved %d rows * %d fields" "

\n", nTups, nFields); } for (i = 0; i < nTups; i++) { if (po->expanded) { if (po->html3) fprintf(fout, "\n", po->tableOpt ? po->tableOpt : "", i); else fprintf(fout, libpq_gettext("-- RECORD %d --\n"), i); } for (j = 0; j < nFields; j++) do_field(po, res, i, j, fs_len, fields, nFields, fieldNames, fieldNotNum, fieldMax, fieldMaxLen, fout); if (po->html3 && po->expanded) fputs("
%d
\n", fout); } if (!po->expanded && (po->align || po->html3)) { if (po->html3) { if (po->header) { if (po->caption) fprintf(fout, "\n", po->tableOpt ? po->tableOpt : "", po->caption); else fprintf(fout, "
%s
\n", po->tableOpt ? po->tableOpt : "", nTups, nFields); } else fprintf(fout, "
" "Retrieved %d rows * %d fields" "
", po->tableOpt ? po->tableOpt : ""); } if (po->header) border = do_header(fout, po, nFields, fieldMax, fieldNames, fieldNotNum, fs_len, res); for (i = 0; i < nTups; i++) output_row(fout, po, nFields, fields, fieldNotNum, fieldMax, border, i); free(fields); if (border) free(border); } if (po->header && !po->html3) fprintf(fout, "(%d row%s)\n\n", PQntuples(res), (PQntuples(res) == 1) ? "" : "s"); free(fieldMax); free(fieldNotNum); free((void *) fieldNames); if (usePipe) { #ifdef WIN32 _pclose(fout); #else pclose(fout); #ifdef ENABLE_THREAD_SAFETY /* we can't easily verify if EPIPE occurred, so say it did */ if (sigpipe_masked) pq_reset_sigpipe(&osigset, sigpipe_pending, true); #else pqsignal(SIGPIPE, oldsigpipehandler); #endif /* ENABLE_THREAD_SAFETY */ #endif /* WIN32 */ } if (po->html3 && !po->expanded) fputs("
\n", fout); } } static void do_field(const PQprintOpt *po, const PGresult *res, const int i, const int j, const int fs_len, char **fields, const int nFields, char const ** fieldNames, unsigned char *fieldNotNum, int *fieldMax, const int fieldMaxLen, FILE *fout) { const char *pval, *p; int plen; bool skipit; plen = PQgetlength(res, i, j); pval = PQgetvalue(res, i, j); if (plen < 1 || !pval || !*pval) { if (po->align || po->expanded) skipit = true; else { skipit = false; goto efield; } } else skipit = false; if (!skipit) { if (po->align && !fieldNotNum[j]) { /* Detect whether field contains non-numeric data */ char ch = '0'; for (p = pval; *p; p += PQmblen(p, res->client_encoding)) { ch = *p; if (!((ch >= '0' && ch <= '9') || ch == '.' || ch == 'E' || ch == 'e' || ch == ' ' || ch == '-')) { fieldNotNum[j] = 1; break; } } /* * Above loop will believe E in first column is numeric; also, we * insist on a digit in the last column for a numeric. This test * is still not bulletproof but it handles most cases. */ if (*pval == 'E' || *pval == 'e' || !(ch >= '0' && ch <= '9')) fieldNotNum[j] = 1; } if (!po->expanded && (po->align || po->html3)) { if (plen > fieldMax[j]) fieldMax[j] = plen; if (!(fields[i * nFields + j] = (char *) malloc(plen + 1))) { fprintf(stderr, libpq_gettext("out of memory\n")); exit(1); } strcpy(fields[i * nFields + j], pval); } else { if (po->expanded) { if (po->html3) fprintf(fout, "
%s%s
%s
%s