Search Postgresql Archives

Feature proposal, DBURL: psql pgsql://joe:p4zzw0rd@xxxxxxxxxxx:2345/dbname

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi

The dburl (or dburi) has become common to use by many systems connecting to a database. The feature is that one can pass all parameters in a string, which has similar pattern as http-URI do.
Especially when using psql in a script, having the credentials in one string is convenient.

The syntax could be:
  [scheme[<+>dsn]]://[[username[:[password]]@][host][:port][/[dbname][/[[table[/[column[,column...]*]]]|sql]]]

Example of usage:
  psql pgsql://joe:p4zzw0rd@xxxxxxxxxxx:2345/dbname

Where
  Scheme: pgsql
  Username: joe
  Password: p4zzw0rd
  Host: example.org
  Port: 2345
  Database: dbname

I have attached an example of how it could be implemented. It uses libpcre RegEx to pass the dburl.

best regards
Hans
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 <stdio.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <pcre.h>
+#include <errno.h>
+#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 (i<argc) {
+		dburl_t *url = dburlparse(argv[i]);
+
+		if (url) {
+			printf("%2d. %-10s: %s\n", IDX_SCHEME,   schemeitems[IDX_SCHEME],   url->scheme);
+			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 "<scheme>"
+		//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];
-- 
Sent via pgsql-general mailing list (pgsql-general@xxxxxxxxxxxxxx)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-general

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Postgresql Jobs]     [Postgresql Admin]     [Postgresql Performance]     [Linux Clusters]     [PHP Home]     [PHP on Windows]     [Kernel Newbies]     [PHP Classes]     [PHP Books]     [PHP Databases]     [Postgresql & PHP]     [Yosemite]

  Powered by Linux