\pset null '(null)' CREATE SERVER fuseki FOREIGN DATA WRAPPER rdf_fdw OPTIONS ( endpoint 'http://fuseki:3030/dt/sparql', update_url 'http://fuseki:3030/dt/update'); CREATE FOREIGN TABLE ft ( subject rdfnode OPTIONS (variable '?s'), predicate rdfnode OPTIONS (variable '?p'), object rdfnode OPTIONS (variable '?o') ) SERVER fuseki OPTIONS ( log_sparql 'true', sparql 'SELECT * WHERE {?s ?p ?o}', sparql_update_pattern '?s ?p ?o .' ); CREATE USER MAPPING FOR postgres SERVER fuseki OPTIONS (user 'admin', password 'secret'); INSERT INTO ft (subject, predicate, object) VALUES ('', '', '"Westfälische Wilhelms-Universität Münster"@de'); INFO: SPARQL query sent to 'fuseki': INSERT DATA { "Westfälische Wilhelms-Universität Münster"@de }; SELECT * FROM ft WHERE subject = ''; INFO: SPARQL query sent to 'fuseki': SELECT ?s ?p ?o {?s ?p ?o ## rdf_fdw pushdown conditions ## FILTER(?s = ) } INFO: SPARQL returned 1 record. subject | predicate | object -------------------------------+----------------------------------------------+------------------------------------------------ | | "Westfälische Wilhelms-Universität Münster"@de (1 row) UPDATE ft SET object = '"University of Münster"@en' WHERE subject = '' AND predicate = ''; INFO: SPARQL query sent to 'fuseki': SELECT ?s ?p ?o {?s ?p ?o ## rdf_fdw pushdown conditions ## FILTER(?s = ) FILTER(?p = ) } INFO: SPARQL returned 1 record. INFO: SPARQL query sent to 'fuseki': DELETE DATA { "Westfälische Wilhelms-Universität Münster"@de }; INSERT DATA { "University of Münster"@en }; SELECT * FROM ft WHERE subject = ''; INFO: SPARQL query sent to 'fuseki': SELECT ?s ?p ?o {?s ?p ?o ## rdf_fdw pushdown conditions ## FILTER(?s = ) } INFO: SPARQL returned 1 record. subject | predicate | object -------------------------------+----------------------------------------------+---------------------------- | | "University of Münster"@en (1 row) UPDATE ft SET object = '""'::rdfnode WHERE subject = '' AND predicate = ''; INFO: SPARQL query sent to 'fuseki': SELECT ?s ?p ?o {?s ?p ?o ## rdf_fdw pushdown conditions ## FILTER(?s = ) FILTER(?p = ) } INFO: SPARQL returned 1 record. INFO: SPARQL query sent to 'fuseki': DELETE DATA { "University of Münster"@en }; INSERT DATA { "" }; SELECT * FROM ft WHERE subject = ''; INFO: SPARQL query sent to 'fuseki': SELECT ?s ?p ?o {?s ?p ?o ## rdf_fdw pushdown conditions ## FILTER(?s = ) } INFO: SPARQL returned 1 record. subject | predicate | object -------------------------------+----------------------------------------------+-------- | | "" (1 row) UPDATE ft SET object = '🐘'::rdfnode WHERE subject = '' AND predicate = ''; INFO: SPARQL query sent to 'fuseki': SELECT ?s ?p ?o {?s ?p ?o ## rdf_fdw pushdown conditions ## FILTER(?s = ) FILTER(?p = ) } INFO: SPARQL returned 1 record. INFO: SPARQL query sent to 'fuseki': DELETE DATA { "" }; INSERT DATA { "🐘" }; SELECT * FROM ft WHERE subject = ''; INFO: SPARQL query sent to 'fuseki': SELECT ?s ?p ?o {?s ?p ?o ## rdf_fdw pushdown conditions ## FILTER(?s = ) } INFO: SPARQL returned 1 record. subject | predicate | object -------------------------------+----------------------------------------------+-------- | | "🐘" (1 row) /* update using existing column */ UPDATE ft SET object = predicate WHERE subject = '' AND predicate = ''; INFO: SPARQL query sent to 'fuseki': SELECT ?s ?p ?o {?s ?p ?o ## rdf_fdw pushdown conditions ## FILTER(?s = ) FILTER(?p = ) } INFO: SPARQL returned 1 record. INFO: SPARQL query sent to 'fuseki': DELETE DATA { "🐘" }; INSERT DATA { }; SELECT * FROM ft WHERE subject = ''; INFO: SPARQL query sent to 'fuseki': SELECT ?s ?p ?o {?s ?p ?o ## rdf_fdw pushdown conditions ## FILTER(?s = ) } INFO: SPARQL returned 1 record. subject | predicate | object -------------------------------+----------------------------------------------+---------------------------------------------- | | (1 row) /* update literals with quotes */ UPDATE ft SET object = '"\"text with quotes\""'::rdfnode WHERE subject = '' AND predicate = ''; INFO: SPARQL query sent to 'fuseki': SELECT ?s ?p ?o {?s ?p ?o ## rdf_fdw pushdown conditions ## FILTER(?s = ) FILTER(?p = ) } INFO: SPARQL returned 1 record. INFO: SPARQL query sent to 'fuseki': DELETE DATA { }; INSERT DATA { "\"text with quotes\"" }; SELECT * FROM ft WHERE subject = ''; INFO: SPARQL query sent to 'fuseki': SELECT ?s ?p ?o {?s ?p ?o ## rdf_fdw pushdown conditions ## FILTER(?s = ) } INFO: SPARQL returned 1 record. subject | predicate | object -------------------------------+----------------------------------------------+------------------------ | | "\"text with quotes\"" (1 row) /* update literals containing newlines */ UPDATE ft SET object = '"text \n newline"'::rdfnode WHERE subject = '' AND predicate = ''; INFO: SPARQL query sent to 'fuseki': SELECT ?s ?p ?o {?s ?p ?o ## rdf_fdw pushdown conditions ## FILTER(?s = ) FILTER(?p = ) } INFO: SPARQL returned 1 record. INFO: SPARQL query sent to 'fuseki': DELETE DATA { "\"text with quotes\"" }; INSERT DATA { "text \n newline" }; SELECT * FROM ft WHERE subject = ''; INFO: SPARQL query sent to 'fuseki': SELECT ?s ?p ?o {?s ?p ?o ## rdf_fdw pushdown conditions ## FILTER(?s = ) } INFO: SPARQL returned 1 record. subject | predicate | object -------------------------------+----------------------------------------------+----------- | | "text + | | newline" (1 row) /* update to xsd:string literal (graphdb might omit xsd:string datatype) */ UPDATE ft SET object = '"text xsd string"^^'::rdfnode WHERE subject = '' AND predicate = ''; INFO: SPARQL query sent to 'fuseki': SELECT ?s ?p ?o {?s ?p ?o ## rdf_fdw pushdown conditions ## FILTER(?s = ) FILTER(?p = ) } INFO: SPARQL returned 1 record. INFO: SPARQL query sent to 'fuseki': DELETE DATA { "text \n newline" }; INSERT DATA { "text xsd string"^^ }; SELECT * FROM ft WHERE subject = ''; INFO: SPARQL query sent to 'fuseki': SELECT ?s ?p ?o {?s ?p ?o ## rdf_fdw pushdown conditions ## FILTER(?s = ) } INFO: SPARQL returned 1 record. subject | predicate | object -------------------------------+----------------------------------------------+------------------- | | "text xsd string" (1 row) /* update to xsd:int literal */ UPDATE ft SET object = 42::rdfnode WHERE subject = '' AND predicate = ''; INFO: SPARQL query sent to 'fuseki': SELECT ?s ?p ?o {?s ?p ?o ## rdf_fdw pushdown conditions ## FILTER(?s = ) FILTER(?p = ) } INFO: SPARQL returned 1 record. INFO: SPARQL query sent to 'fuseki': DELETE DATA { "text xsd string" }; INSERT DATA { "42"^^ }; SELECT * FROM ft WHERE subject = ''; INFO: SPARQL query sent to 'fuseki': SELECT ?s ?p ?o {?s ?p ?o ## rdf_fdw pushdown conditions ## FILTER(?s = ) } INFO: SPARQL returned 1 record. subject | predicate | object -------------------------------+----------------------------------------------+---------------------------------------------- | | "42"^^ (1 row) /* update to xsd:decimal literal */ UPDATE ft SET object = 42.37::rdfnode WHERE subject = '' AND predicate = ''; INFO: SPARQL query sent to 'fuseki': SELECT ?s ?p ?o {?s ?p ?o ## rdf_fdw pushdown conditions ## FILTER(?s = ) FILTER(?p = ) } INFO: SPARQL returned 1 record. INFO: SPARQL query sent to 'fuseki': DELETE DATA { "42"^^ }; INSERT DATA { "42.37"^^ }; SELECT * FROM ft WHERE subject = ''; INFO: SPARQL query sent to 'fuseki': SELECT ?s ?p ?o {?s ?p ?o ## rdf_fdw pushdown conditions ## FILTER(?s = ) } INFO: SPARQL returned 1 record. subject | predicate | object -------------------------------+----------------------------------------------+----------------------------------------------------- | | "42.37"^^ (1 row) /* update to xsd:long literal */ UPDATE ft SET object = 423712345678911::rdfnode WHERE subject = '' AND predicate = ''; INFO: SPARQL query sent to 'fuseki': SELECT ?s ?p ?o {?s ?p ?o ## rdf_fdw pushdown conditions ## FILTER(?s = ) FILTER(?p = ) } INFO: SPARQL returned 1 record. INFO: SPARQL query sent to 'fuseki': DELETE DATA { "42.37"^^ }; INSERT DATA { "423712345678911"^^ }; SELECT * FROM ft WHERE subject = ''; INFO: SPARQL query sent to 'fuseki': SELECT ?s ?p ?o {?s ?p ?o ## rdf_fdw pushdown conditions ## FILTER(?s = ) } INFO: SPARQL returned 1 record. subject | predicate | object -------------------------------+----------------------------------------------+------------------------------------------------------------ | | "423712345678911"^^ (1 row) /* update with NULL - must fail (after SELECT since FDW must fetch OLD values first) */ UPDATE ft SET object = NULL WHERE subject = '' AND predicate = ''; INFO: SPARQL query sent to 'fuseki': SELECT ?s ?p ?o {?s ?p ?o ## rdf_fdw pushdown conditions ## FILTER(?s = ) FILTER(?p = ) } INFO: SPARQL returned 1 record. ERROR: NULL value in column "object" violates RDF constraint DETAIL: SPARQL variable '?o' cannot be NULL in RDF triple patterns HINT: RDF triples require all components to be non-NULL. Filter NULL values in your query or provide default values. SELECT * FROM ft WHERE subject = ''; INFO: SPARQL query sent to 'fuseki': SELECT ?s ?p ?o {?s ?p ?o ## rdf_fdw pushdown conditions ## FILTER(?s = ) } INFO: SPARQL returned 1 record. subject | predicate | object -------------------------------+----------------------------------------------+------------------------------------------------------------ | | "423712345678911"^^ (1 row) /* update rdfnode with a blank node */ UPDATE ft SET object = sparql.bnode() WHERE subject = '' AND predicate = ''; INFO: SPARQL query sent to 'fuseki': SELECT ?s ?p ?o {?s ?p ?o ## rdf_fdw pushdown conditions ## FILTER(?s = ) FILTER(?p = ) } INFO: SPARQL returned 1 record. ERROR: blank nodes are not allowed in UPDATE operations HINT: Blank nodes are document-local and have no global meaning. Use IRIs instead. /* update with RETURNING */ UPDATE ft SET object = '"Westfälische Wilhelms-Universität Münster"@de' WHERE subject = '' AND predicate = '' RETURNING OLD.subject, OLD.predicate, OLD.object, NEW.subject AS new_subject, NEW.predicate AS new_predicate, NEW.object AS new_object; INFO: SPARQL query sent to 'fuseki': SELECT ?s ?p ?o {?s ?p ?o ## rdf_fdw pushdown conditions ## FILTER(?s = ) FILTER(?p = ) } INFO: SPARQL returned 1 record. INFO: SPARQL query sent to 'fuseki': DELETE DATA { "423712345678911"^^ }; INSERT DATA { "Westfälische Wilhelms-Universität Münster"@de }; subject | predicate | object | new_subject | new_predicate | new_object -------------------------------+----------------------------------------------+------------------------------------------------------------+-------------------------------+----------------------------------------------+------------------------------------------------ | | "423712345678911"^^ | | | "Westfälische Wilhelms-Universität Münster"@de (1 row) /* invalid credentials test */ ALTER USER MAPPING FOR postgres SERVER fuseki OPTIONS (SET user 'admin', SET password 'foo'); -- wrong password UPDATE ft SET object = '"University of Münster"@en' WHERE subject = '' AND predicate = ''; INFO: SPARQL query sent to 'fuseki': SELECT ?s ?p ?o {?s ?p ?o ## rdf_fdw pushdown conditions ## FILTER(?s = ) FILTER(?p = ) } INFO: SPARQL returned 1 record. INFO: SPARQL query sent to 'fuseki': DELETE DATA { "Westfälische Wilhelms-Universität Münster"@de }; INSERT DATA { "University of Münster"@en }; ERROR: SERVER authentication failed (HTTP status 401) HINT: Check the user and password set in the USER MAPPING for the PostgreSQL user "postgres" and try again. ALTER USER MAPPING FOR postgres SERVER fuseki OPTIONS (SET user 'admin', SET password 'secret'); -- restore correct password /* cleanup */ DELETE FROM ft; INFO: SPARQL query sent to 'fuseki': SELECT ?s ?p ?o {?s ?p ?o} INFO: SPARQL returned 1 record. INFO: SPARQL query sent to 'fuseki': DELETE DATA { "Westfälische Wilhelms-Universität Münster"@de }; DROP SERVER fuseki CASCADE; NOTICE: drop cascades to 2 other objects DETAIL: drop cascades to foreign table ft drop cascades to user mapping for postgres on server fuseki