diff -Naur /home/hsc/tmp/postgresql-10beta1/src/bin/psql/dburl.c ./dburl.c --- /home/hsc/tmp/postgresql-10beta1/src/bin/psql/dburl.c 1970-01-01 01:00:00.000000000 +0100 +++ ./dburl.c 2017-07-05 13:52:30.823234720 +0200 @@ -0,0 +1,261 @@ +/* + * Compile: + * gcc -Wall -DUNIT_TEST dburl.c -lpcre -o dburl + * + * Test: + * ./dburl 'pgsqls://example/' 'pgsqls://username:password@host:5432/dbname/SELECT * FROM mytable' + * ./dburl 'mysql://username:password@host:3306/dbname/table/column1,column2' + * ./dburl 'odbc+dsn:////table/column1,column2' + */ + +//#define INCLUDE_COMMENTS 1 + +#ifdef UNIT_TEST +#include +#endif + +#include +#include +#include +#include +#include +#include "dburl.h" + +#define OVECCOUNT (50*3) + +#define IDX_SCHEME 1 +#define IDX_DSN IDX_SCHEME+1 +#define IDX_USERNAME IDX_DSN+1 +#define IDX_PASSWORD IDX_USERNAME+1 +#define IDX_HOST IDX_PASSWORD+1 +#define IDX_PORT IDX_HOST+1 +#define IDX_DBNAME IDX_PORT+1 +#define IDX_TABLE IDX_DBNAME+1 +#define IDX_COLUMN IDX_TABLE+1 +#define IDX_SQL IDX_COLUMN+1 + +const char *schemeitems[] = { + "null", + "scheme", + "dsn", + "username", + "password", + "host", + "port", + "dbname", + "table", + "column", + "sql" +}; + +#ifdef INCLUDE_COMMENTS +#define cm(msg) "(?#\n " msg "\n)" +#else +#define cm(msg) +#endif + +const char syntaxdescription[] = +"[sql:][scheme[<+>dsn]]://[[username[:[password]]@][host][:port][/[dbname][/[[table[/[column[,column...]*]]]|sql]]]" +; +const char dburlregularexpression[] = +"^" + cm("Optional prefix 'sql:'") + "(?:sql:)?" + cm("Scheme: pgsql") + "([-.a-z0-9]*)(?:[+]([-.a-z0-9]*))?" + cm("Required: URL identifier") + "://" + cm("Username + password") + "(?:" + cm("Username") + "([-a-z0-9_]+)" + cm("Password") + "(?::([^@]*))?@" + ")?" + cm("Hostname") + "(" + cm("localhost | example") + "(?:[a-z0-9]+(?:-+[-a-z0-9]+)*)" + "|" + cm("Domain name with dot: example.com") + "(?:(?:[a-z0-9]+(?:-+[a-z0-9]+)*\\.)?" + "(?:[a-z0-9]+(?:-+[a-z0-9]+)*\\.)+(?:[a-z]{2,7})\\.?)" + "|" + cm("IPv4 number") + "(?:(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[0-9][0-9]|[0-9])\\.){3}" + "(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[0-9][0-9]|[0-9])" + ")?" + cm("Port number: 3306|5432") + "(?::(\\d{1,5}))?" + cm("DB, table, SQL") + "(?:/" + "(?:" + cm("Dbname: joe|mydb, default $USER") + "(?:([_a-z0-9]+)?" + "(?:/" + "(?:" + cm("Table: mytable") + "(?:([_a-z0-9]+)" + cm("Columns: id, name") + "(?:/" + "((?:[_a-z0-9]+)" + "(?:,[_a-z0-9]+)*" + ")?" + ")?" + ")|(" + cm("SQL: SELECT id, name FROM mytable") + "[^\\h]+\\h.+" + ")?" + ")?" + ")?" + ")?" + ")?" + ")?" +"$" +; + +static char *termstring(char *txt, int *ov, int idx, char *para_def) { + char *tmp = NULL; + + /* if there is a match on this index... */ + if (ov[2*idx+1] > 0) { + int length = ov[2*idx+1] - ov[2*idx]; + if ((tmp = malloc(length+1))) { + strncpy(tmp, &txt[ov[2*idx]], length); + tmp[length] = 0; + } + } + return tmp ? tmp : para_def; +} + +dburl_t *dburlparse(char *dburltext) { + dburl_t *dburl = NULL; + + if (dburltext) { + pcre *re; + const char *error; + int erroffset; + int ovector[OVECCOUNT]; + int rc; + + re = pcre_compile( + dburlregularexpression, + PCRE_CASELESS, + &error, + &erroffset, + NULL); + if (re) { + rc = pcre_exec( + re, + NULL, + dburltext, + strlen(dburltext), + 0, + 0, + ovector, + OVECCOUNT); + if (rc > 0) { +#ifdef UNIT_TEST + int i; + int m = 0; + int color = -1; + printf("Input: '%s'\n", dburltext); + printf(" "); + for (i = 1; i < rc; i++) { + while (m < ovector[2*i]) { + if (color >= 0) { printf("\e[0m"); color = -1; } + printf("_"); + ++m; + } + while (m < ovector[2*i+1]) { + if (color != i % 2) { printf("\e[3%dm", i % 2 ? 5 : 3); color = i % 2; } + printf("%d", i % 10); + ++m; + } + } + if (color >= 0) { printf("\e[0m"); color = -1; } + printf("\n"); + for (i = 0; i < rc; i++) { + char *substring_start = dburltext + ovector[2*i]; + int substring_length = ovector[2*i+1] - ovector[2*i]; + printf("# %2d [%2d %2d]: %.*s\n", i, ovector[2*i], ovector[2*i+1], substring_length, substring_start); + } +#endif + dburl = malloc(sizeof(*dburl)); + memset(dburl, 0, sizeof(*dburl)); + /* Assign all possible elements a value */ + dburl->scheme = termstring(dburltext, ovector, IDX_SCHEME, NULL); + dburl->dsn = termstring(dburltext, ovector, IDX_DSN, NULL); + dburl->username = termstring(dburltext, ovector, IDX_USERNAME, NULL); + dburl->password = termstring(dburltext, ovector, IDX_PASSWORD, NULL); + dburl->host = termstring(dburltext, ovector, IDX_HOST, NULL); + dburl->port = termstring(dburltext, ovector, IDX_PORT, NULL); + dburl->dbname = termstring(dburltext, ovector, IDX_DBNAME, NULL); + dburl->table = termstring(dburltext, ovector, IDX_TABLE, NULL); + dburl->column = termstring(dburltext, ovector, IDX_COLUMN, NULL); + dburl->sql = termstring(dburltext, ovector, IDX_SQL, NULL); + } + pcre_free(re); + } + } + + return dburl; +} + +#ifdef UNIT_TEST +void fieldfree(char *p) { + if (p) { + free(p); + } +} + +int dburlfree(dburl_t *dburl) { + if (dburl) { + fieldfree(dburl->scheme); + fieldfree(dburl->dsn); + fieldfree(dburl->username); + fieldfree(dburl->password); + fieldfree(dburl->host); + fieldfree(dburl->port); + fieldfree(dburl->dbname); + fieldfree(dburl->table); + fieldfree(dburl->column); + fieldfree(dburl->sql); + free(dburl); + dburl = NULL; + } + return 1; +} + +int main(int argc, char **argv) { + int i = 1; + + printf("\n%s\n", syntaxdescription); + printf("\n%s\n\n", dburlregularexpression); + while (ischeme); + printf("%2d. %-10s: %s\n", IDX_DSN, schemeitems[IDX_DSN], url->dsn); + printf("%2d. %-10s: %s\n", IDX_USERNAME, schemeitems[IDX_USERNAME], url->username); + printf("%2d. %-10s: %s\n", IDX_PASSWORD, schemeitems[IDX_PASSWORD], url->password); + printf("%2d. %-10s: %s\n", IDX_HOST, schemeitems[IDX_HOST], url->host); + printf("%2d. %-10s: %s\n", IDX_PORT, schemeitems[IDX_PORT], url->port); + printf("%2d. %-10s: %s\n", IDX_DBNAME, schemeitems[IDX_DBNAME], url->dbname); + printf("%2d. %-10s: %s\n", IDX_TABLE, schemeitems[IDX_TABLE], url->table); + printf("%2d. %-10s: %s\n", IDX_COLUMN, schemeitems[IDX_COLUMN], url->column); + printf("%2d. %-10s: %s\n", IDX_SQL, schemeitems[IDX_SQL], url->sql); + } else { + printf("ERROR parsing '%s'\n", argv[i]); + } + printf("\n"); + + // BUG: Had disable, can not free() constant default like "" + //dburlfree(url); + i++; + } + + return 0; +} +#endif diff -Naur /home/hsc/tmp/postgresql-10beta1/src/bin/psql/dburl.h ./dburl.h --- /home/hsc/tmp/postgresql-10beta1/src/bin/psql/dburl.h 1970-01-01 01:00:00.000000000 +0100 +++ ./dburl.h 2017-07-05 09:24:50.394243999 +0200 @@ -0,0 +1,27 @@ +/* + * psql - the PostgreSQL interactive terminal + * + * Copyright (c) 2017, PostgreSQL Global Development Group + * + * src/bin/psql/dburl.h + */ +#ifndef DBURL_H +#define DBURL_H + +typedef struct { + char *scheme; + char *dsn; + char *username; + char *password; + char *host; + char *port; + char *dbname; + char *table; + char *column; + char *sql; +} dburl_t; + +extern dburl_t *dburlparse(char *dburltext); +extern int dburlfree(dburl_t *dburl); + +#endif diff -Naur /home/hsc/tmp/postgresql-10beta1/src/bin/psql/Makefile ./Makefile --- /home/hsc/tmp/postgresql-10beta1/src/bin/psql/Makefile 2017-05-15 23:20:59.000000000 +0200 +++ ./Makefile 2017-07-05 08:54:26.222243999 +0200 @@ -19,12 +19,12 @@ REFDOCDIR= $(top_srcdir)/doc/src/sgml/ref override CPPFLAGS := -I. -I$(srcdir) -I$(libpq_srcdir) $(CPPFLAGS) -LDFLAGS += -L$(top_builddir)/src/fe_utils -lpgfeutils -lpq +LDFLAGS += -L$(top_builddir)/src/fe_utils -lpgfeutils -lpq -lpcre OBJS= command.o common.o conditional.o copy.o crosstabview.o \ describe.o help.o input.o large_obj.o mainloop.o \ prompt.o psqlscanslash.o sql_help.o startup.o stringutils.o \ - tab-complete.o variables.o \ + tab-complete.o variables.o dburl.o \ $(WIN32RES) diff -Naur /home/hsc/tmp/postgresql-10beta1/src/bin/psql/startup.c ./startup.c --- /home/hsc/tmp/postgresql-10beta1/src/bin/psql/startup.c 2017-05-15 23:20:59.000000000 +0200 +++ ./startup.c 2017-07-05 14:15:22.155234720 +0200 @@ -24,7 +24,7 @@ #include "mainloop.h" #include "fe_utils/print.h" #include "settings.h" - +#include "dburl.h" /* @@ -654,7 +654,20 @@ */ while (argc - optind >= 1) { - if (!options->dbname) + dburl_t *dburlparam; + if (NULL != (dburlparam = dburlparse(argv[optind]))) { + if (dburlparam->dbname) + options->dbname = dburlparam->dbname; + if (dburlparam->username) + options->username = dburlparam->username; + if (dburlparam->host) + options->host = dburlparam->host; + if (dburlparam->port) + options->port = dburlparam->port; + //if (dburlparam->password) + // strncpy(password, dburlparam->password, sizeof(password)); + } + else if (!options->dbname) options->dbname = argv[optind]; else if (!options->username) options->username = argv[optind];