Changeset: 5bea62ec9cdb for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=5bea62ec9cdb
Modified Files:
sql/backends/monet5/sql.c
sql/include/sql_catalog.h
sql/server/rel_updates.c
sql/server/sql_parser.y
sql/server/sql_scan.c
Branch: copyfromremote
Log Message:
Implement COPY INTO ... FROM 'http://...'
Only if GRANT'ed COPY FROM REMOTE permission.
Adds a new non-reserved keyword FILE as the full name
of the COPY FROM permission is now COPY FROM FILE.
A bare COPY FROM permission is equivalent to COPY FROM FILE.
FROM 'https://' is also supported.
Have to check if and how certificates are checked.
diffs (210 lines):
diff --git a/sql/backends/monet5/sql.c b/sql/backends/monet5/sql.c
--- a/sql/backends/monet5/sql.c
+++ b/sql/backends/monet5/sql.c
@@ -3102,9 +3102,12 @@ mvc_import_table_wrap(Client cntxt, MalB
return msg;
}
} else {
- ss = open_rastream(fname);
+ if (strncmp("http:", fname, 5) == 0 ||
strncmp("https:", fname, 6) == 0)
+ ss = open_urlstream(fname);
+ else
+ ss = open_rastream(fname);
if (ss == NULL || mnstr_errnr(ss)) {
- msg = createException(IO, "sql.copy_from",
SQLSTATE(42000) "Cannot open file '%s': %s", fname, GDKstrerror(errno,
(char[128]){0}, 128));
+ msg = createException(IO, "sql.copy_from",
SQLSTATE(42000) "Cannot open '%s': %s", fname, GDKstrerror(errno,
(char[128]){0}, 128));
close_stream(ss);
return msg;
}
diff --git a/sql/include/sql_catalog.h b/sql/include/sql_catalog.h
--- a/sql/include/sql_catalog.h
+++ b/sql/include/sql_catalog.h
@@ -40,6 +40,7 @@
/* global privs */
#define PRIV_COPYFROMFILE 1
#define PRIV_COPYINTOFILE 2
+#define PRIV_COPYFROMURL 3
typedef enum sql_dependency {
SCHEMA_DEPENDENCY = 1,
diff --git a/sql/server/rel_updates.c b/sql/server/rel_updates.c
--- a/sql/server/rel_updates.c
+++ b/sql/server/rel_updates.c
@@ -416,12 +416,55 @@ insert_allowed(mvc *sql, sql_table *t, c
return t;
}
-static int
-copy_allowed(mvc *sql, int from)
+static int
+copy_from_file_allowed(mvc *sql)
+{
+ return global_privs(sql, PRIV_COPYFROMFILE);
+}
+
+static int
+copy_into_file_allowed(mvc *sql)
+{
+ return global_privs(sql, PRIV_COPYINTOFILE);
+}
+
+static int
+copy_from_src_allowed(mvc *sql, int locked, int onclient, const char *src)
{
- if (!global_privs(sql, (from)?PRIV_COPYFROMFILE:PRIV_COPYINTOFILE))
+ // LOCKED requires admin privileges so it has to go through the decision
+ // procedure below. Apart from that, ON CLIENT is checked by the client
so
+ // it is always ok.
+ if (onclient && !locked)
+ return 1; // let the client figure it out.
+
+ int is_url; // Intentionally left uninitialized.
+ if (src == NULL)
+ is_url = 0;
+ else if (strncmp("http:", src, 5) == 0)
+ is_url = 1;
+ else if (strncmp("https:", src, 6) == 0)
+ is_url = 1;
+ else if (MT_path_absolute(src))
+ is_url = 0;
+ else {
+ char *escaped = ATOMformat(TYPE_str, src);
+ sql_error(
+ sql, 02,
+ SQLSTATE(42000) "COPY INTO: filename must be absolute:
%s",
+ escaped);
+ GDKfree(escaped);
return 0;
- return 1;
+ }
+
+ int allowed = global_privs(sql, is_url ? PRIV_COPYFROMURL :
PRIV_COPYFROMFILE);
+ if (!allowed) {
+ sql_error(sql, 02, SQLSTATE(42000)
+ "COPY INTO: insufficient privileges: "
+ "COPY INTO from file or url requires
database administrator rights, "
+ "use 'COPY INTO ... FROM ... ON
CLIENT' instead");
+ }
+
+ return allowed;
}
sql_table *
@@ -1623,10 +1666,6 @@ copyfrom(sql_query *query, dlist *qname,
return NULL;
/* Only the MONETDB user is allowed copy into with
a lock and only on tables without idx */
- if (locked && !copy_allowed(sql, 1)) {
- return sql_error(sql, 02, SQLSTATE(42000) "COPY INTO:
insufficient privileges: "
- "COPY INTO from .. LOCKED requires database administrator
rights");
- }
if (locked && (!list_empty(t->idxs.set) || !list_empty(t->keys.set))) {
return sql_error(sql, 02, SQLSTATE(42000) "COPY INTO:
insufficient privileges: "
"COPY INTO from .. LOCKED requires tables without indices");
@@ -1698,24 +1737,12 @@ copyfrom(sql_query *query, dlist *qname,
if (files) {
dnode *n = files->h;
- if (!onclient && !copy_allowed(sql, 1)) {
- return sql_error(sql, 02, SQLSTATE(42000)
- "COPY INTO: insufficient privileges: "
- "COPY INTO from file(s) requires
database administrator rights, "
- "use 'COPY INTO \"%s\" FROM file ON
CLIENT' instead", tname);
- }
-
for (; n; n = n->next) {
const char *fname = n->data.sval;
sql_rel *nrel;
- if (!onclient && fname && !MT_path_absolute(fname)) {
- char *fn = ATOMformat(TYPE_str, fname);
- sql_error(sql, 02, SQLSTATE(42000) "COPY INTO:
filename must "
- "have absolute path: %s", fn);
- GDKfree(fn);
+ if (!copy_from_src_allowed(sql, locked, onclient,
fname))
return NULL;
- }
nrel = rel_import(sql, nt, tsep, rsep, ssep, ns, fname,
nr, offset, locked, best_effort, fwf_widths, onclient);
@@ -1730,6 +1757,8 @@ copyfrom(sql_query *query, dlist *qname,
}
} else {
assert(onclient == 0);
+ if (!copy_from_src_allowed(sql, locked, onclient, NULL))
+ return NULL;
rel = rel_import(sql, nt, tsep, rsep, ssep, ns, NULL, nr,
offset, locked, best_effort, NULL, onclient);
}
if (headers) {
@@ -1818,7 +1847,7 @@ bincopyfrom(sql_query *query, dlist *qna
int i;
assert(f);
- if (!copy_allowed(sql, 1))
+ if (!copy_from_file_allowed(sql))
return sql_error(sql, 02, SQLSTATE(42000) "COPY INTO:
insufficient privileges: "
"binary COPY INTO requires database
administrator rights");
@@ -1893,7 +1922,7 @@ copyfromloader(sql_query *query, dlist *
sql_rel* rel = NULL;
sql_table* t;
- if (!copy_allowed(sql, 1))
+ if (!copy_from_file_allowed(sql))
return sql_error(sql, 02, SQLSTATE(42000) "COPY INTO:
insufficient privileges: "
"binary COPY INTO requires database
administrator rights");
if (sname && !(s = mvc_bind_schema(sql, sname)))
@@ -1978,7 +2007,7 @@ copyto(sql_query *query, symbol *sq, con
if (!onclient && filename) {
struct stat fs;
- if (!copy_allowed(sql, 0))
+ if (!copy_into_file_allowed(sql))
return sql_error(sql, 02, SQLSTATE(42000) "COPY INTO:
insufficient privileges: "
"COPY INTO file requires database
administrator rights, "
"use 'COPY ... INTO file ON CLIENT'
instead");
diff --git a/sql/server/sql_parser.y b/sql/server/sql_parser.y
--- a/sql/server/sql_parser.y
+++ b/sql/server/sql_parser.y
@@ -702,7 +702,7 @@ SQLCODE SQLERROR UNDER WHENEVER
%token CASE WHEN THEN ELSE NULLIF COALESCE IF ELSEIF WHILE DO
%token ATOMIC BEGIN END
-%token COPY RECORDS DELIMITERS STDIN STDOUT FWF CLIENT SERVER
+%token COPY sqlFILE RECORDS DELIMITERS STDIN STDOUT FWF CLIENT SERVER
%token INDEX REPLACE
%token AS TRIGGER OF BEFORE AFTER ROW STATEMENT sqlNEW OLD EACH REFERENCING
@@ -1092,8 +1092,11 @@ global_privileges:
;
global_privilege:
- COPY FROM { $$ = PRIV_COPYFROMFILE; }
- | COPY INTO { $$ = PRIV_COPYINTOFILE; }
+ COPY FROM { $$ = PRIV_COPYFROMFILE; }
+ | COPY FROM sqlFILE { $$ = PRIV_COPYFROMFILE; }
+ | COPY FROM REMOTE { $$ = PRIV_COPYFROMURL; }
+ | COPY INTO { $$ = PRIV_COPYINTOFILE; }
+ | COPY INTO sqlFILE { $$ = PRIV_COPYINTOFILE; }
;
object_name:
@@ -5596,6 +5599,7 @@ non_reserved_word:
| DIAGNOSTICS { $$ = sa_strdup(SA, "diagnostics"); }
| SQL_EXPLAIN { $$ = sa_strdup(SA, "explain"); }
| FIRST { $$ = sa_strdup(SA, "first"); }
+| sqlFILE { $$ = sa_strdup(SA, "file"); }
| GEOMETRY { $$ = sa_strdup(SA, "geometry"); }
| IMPRINTS { $$ = sa_strdup(SA, "imprints"); }
| INCREMENT { $$ = sa_strdup(SA, "increment"); }
diff --git a/sql/server/sql_scan.c b/sql/server/sql_scan.c
--- a/sql/server/sql_scan.c
+++ b/sql/server/sql_scan.c
@@ -143,6 +143,7 @@ scanner_init_keywords(void)
failed += keywords_insert("CREATE", CREATE);
failed += keywords_insert("CROSS", CROSS);
failed += keywords_insert("COPY", COPY);
+ failed += keywords_insert("FILE", sqlFILE);
failed += keywords_insert("RECORDS", RECORDS);
failed += keywords_insert("DELIMITERS", DELIMITERS);
failed += keywords_insert("STDIN", STDIN);
_______________________________________________
checkin-list mailing list
[email protected]
https://www.monetdb.org/mailman/listinfo/checkin-list