Error in a federated database: cannot run schema operations : how to solve it?

Running neo4j enterprise 5.26.2.

I got the following error while try to set KEYS and CONSTRAINTS on a federated database:

Moreover, it looks like I cannot change database while I've choosen one in the list box on top left.

How can I decide throught a query on which database I want to work without having to select it before?

Would something like USE federatednotions.gdpr CREATE CONSTRAINT ... work? The constraints need to be added to all the individual parts instead of the composite database linking them together

Well, this was exactly my goal:

when I write USE federatednotions.gdpr I mean a specific database (that is also part of a federated one).

I undesratnd that I MUST use USE GDPR instead.

But the question the still remain:

Can I switch between one database and the other using cypher and without having to switch it manually thru the browser?

TY

You should be able to use the database’s alias too (federatednotions.gdpr). Your screenshot shows the prompt was the composite database when you tried to create the constraint. As you stated, you needed to switch to the actual database in order to execute these type of commands.

I would use the USE clause to switch the database manually when needed. The drop down seems to just be a convenience which does the same. It does it in a new editor, so you need to ensure you move to that editor before executing your commands. I feel this makes it a more error prone approach.

No, that doesn't work.
I don't want to connect different DB together, but I'd like to be able to work in a federatedDB context being able to switch to each context and work on it.
If I am in a federated DB, the ':use' command not always works:

This example is with :use

while this other was with use

Anyway, your solution returns an error:

Note the different error while using :use and use. :slight_smile:

So, it is absolutely not clear how to use safely federated DB's.

Exactly, I'm able to use the composite database too, but not to set constraints and indexes even if I switch manually.

And, by my point of view this is an error.

The name of a database or any of it's aliases must run the same code: it cannot answer that.

Then, look at these fragments:

Here I'm settled on the federatednotions db. I did it using the USE command and the dropdown show the correct DB.

Now, I entered the command USE federatednotions.gdpr and this is the (BAD) result:

I noted the following errors:

  1. I used :USE federatednotions.gdpr with a colon
  2. the query doesn't return the requested data
  3. Queries from this point and forward are using the database federatednotions.gdpras the target.
  4. the database selected in the dropdown is beverages
  5. but the data under the dropdown refers to the gdpr database

More, if I should have used USE without the colon, the result should be erroneous:

  1. if I doesn't include a return it gives an error (i.e. doesn't switch the database)
  2. if I add a return statement it returns nothing.

Finally, I would affirm that:
1) the composite database alias cannot be selected in the dropdown box;
2) The composite database alias cannot be queried in the browser

If a use a python script, can I solve or bypass these errors?

Try removing the ; after the use clause, in Cypher it isn't its own query but parts of a bigger one which is why you get an error when it's the only thing in your query

USE federatednotations.gdpr
CREATE CONSTRAINT ...

From my last reply:

Would something like USE federatednotions.gdpr CREATE CONSTRAINT ... work? The constraints need to be added to all the individual parts instead of the composite database linking them together

Notice how there isn't a ; between the USE and CREATE CONSTRAINT parts but you have one in your screenshot?

You seem to mix/confuse the browser command :use and the Cypher query clause USE, which are not interchangeable.

The :use is the same as using the drop down menu and is executed in browser to switch what database you are connected to. This can not be combined with a Cypher query, it is its own command.

In difference, the USE in Cypher is part of a query which tells the server to re-route this query from the database you are connected to and over to the requested database. This means it cannot be used on its own and need an actual query to follow it (not separated by ; as that separates different queries to be run after each other).

As for your conclusions, you are right that you can't connect directly to the composite database alias by either the drop down menu or the :use command. This is due to them only being available for querying when connected to the composite database they belong to. However, they can be queried when using the USE clause as part of the query itself, as this is how it was designed to be reached.

The documentation for the Cypher USE clause: USE - Cypher Manual

1 Like

In the query, I tried different solutions looking for the one able to run;
But you're right, this solution works: now I'll embed in a most complex query and let you know if I still have problems.

1 Like

Thank you for sharing working together and sharing knowledge

HI Therese,

after a lot of times I'm again with the same trouble:

now, I got this query:

USE gdpr

CREATE CONSTRAINT cryptoOwner_uuid IF NOT EXISTS FOR (n:CryptoOwner) REQUIRE n.uuid IS UNIQUE
CREATE CONSTRAINT criptoOwner_shortName IF NOT EXISTS FOR (n:CryptoOwner) REQUIRE n.shortName IS UNIQUE

WITH "pikeen" AS owner

WITH owner, pikeen.uuid5(owner,"pikeen.com") as ownerUuid5

    MERGE (node:CryptoOwner { uuid: ownerUuid5, shortName: owner })

......

As you can see, I removed the ; after the USE, but I need the ; after the CREATE CONSTRAINT. because, as it is now, it returns an error.

But, if I put the ; at the end of those lines, it doesn't maintain the changed DB, and run on the currently selected DB.

Any idea on how to solve this problem?

Wouldn’t you just run the create constraint commands once, not mixed with cypher queries?

1 Like

I agree with Gary

CREATE CONSTRAINT is a "schema" statement that executes once (usually by done by a data administrator).

Well, this is a query used to initialize a GDPR db with encrypted values of some nodes.

This is the first initial run of the entire job, and I wanted to be sure that the Constraint and index creation should be run.

We don't have a sysadmin role to manages these things, so I tried to embed them in the initiall query to be sure they will be executed in any case.


By the way, I removed the two commands and, of course, the query had run correctly.

This lead me to a insider question:

If I have more db's the constaint and the index are common to those DB or each db has it's own constraints and indexes?

I'm asking, because the show constraint and the show indexes command both returns the same output when launched on different DBs.

Thank you

Usually database initialisation scripts are completely separate (because they are ran once) and you would have change control running on them different (same will be with granting access and privileges to users).

You are probably looking at the constraints as the database management system can see them and your privileges as an administrator allow ... as I understand, each database is indepedendent.

Let's see if I can add some information around the different new questions.

As you can see, I removed the ; after the USE, but I need the ; after the CREATE CONSTRAINT. because, as it is now, it returns an error.
But, if I put the ; at the end of those lines, it doesn't maintain the changed DB, and run on the currently selected DB.

This is due to the CREATE CONSTRAINT command not being able to be run in the same query/transaction as regular Cypher. The ; separates the queries and I believe things like browser then run each query in a separate transaction. So to have both of them there you'd need to add the Cypher USE clause again for the second query. I'm also not sure if it'll allow you to run both CREATE CONSTRAINT commands in one query or two either so for good measure I split all three into one:

USE gdpr
CREATE CONSTRAINT cryptoOwner_uuid IF NOT EXISTS FOR (n:CryptoOwner) REQUIRE n.uuid IS UNIQUE;

USE gdpr
CREATE CONSTRAINT criptoOwner_shortName IF NOT EXISTS FOR (n:CryptoOwner) REQUIRE n.shortName IS UNIQUE;

USE gdpr
WITH "pikeen" AS owner

WITH owner, pikeen.uuid5(owner,"pikeen.com") as ownerUuid5

    MERGE (node:CryptoOwner { uuid: ownerUuid5, shortName: owner })

......

Then as Gary and Josh says, usually you would have one script to set-up the constraints/indexes and then one for regular queries, even if both are set-up since one will trigger "schema write" transactions and the other "regular" transactions (just to separate what they do, don't think we officially call them that :P)

If I have more db's the constaint and the index are common to those DB or each db has it's own constraints and indexes?

Each DB has it's own indexes and constraints, they are per database and not something shared across the DBMS.

I'm asking, because the show constraint and the show indexes command both returns the same output when launched on different DBs.

Then I guess the ones you've tried have had the same set-up but that's not managed from the database side.

Hope any of that helped provide some extra context to Josh and Gary's answers.
/Therese

In the past, when working on a single DB, my habit was to create constraints and indexes with the same Cypher CSV LOAD used to load the contest.

My intention was to try to maintain the same approach while working with different DBs, and this seemed to be impossible :disappointed_face:

So I will follow @Therese.magnusson's advice.

I am not enthusiastic about this solution: it is not clean enough and is more of a workaround than a real solution. But it's fine all the same.

My idea is that the USE DB_NAME stetement needs to be improved:

From my point of view, it should work more or less as described by the following statement:

"WHEN I issue the USE DBname command, it should remain valid until the end of the BATCH I'm submitting (until the end of the submitted file or query (thus not tied to ;) or, if you want to treat it as a sudo like session until I issue a USE EXIT or USE RETURN command or the query naturally terminates.

The USE command should run like a stack: with USE I PUSH another environment onto the stack which defines the DB.

At the end, the stack will be released with a PULL. If I use another USE DB_name, it should PUSH another stack entry with the new DB_name.

What I also mean, is that the USE command should allow me to use any Cypher command, whether they are basic queries or system queries: it's my responsibility, not your to run rthe correct commands!

I think it should help with this kkind of syntactic nightmare!

The issue with that view is that the Cypher USE clause is defined per query and not per transaction - so each query in your transaction needs to have a USE clause, unless you connect to the 'correct' database -> which you can't do in the multi-database case as you need to be connected to the composite to reach the constituents. I understand that it's frustrating, but some of that frustration comes from having a different viewpoint of what you want the clause to be vs what it is designed to be.

Also the ; splits different queries so

it should remain valid until the end of ... or query (thus not tied to ; )

is not really possible either regardless, the ; literally defines the end of a query.

Then you are mixing multiple queries in your script (and additionally a mix of schema and regular Cypher at that which further complicates things) which means that each query will need a use clause.

I'm surprised if your precious setup worked without a ; between constraint/index creation and the regular Cypher, I don't think it would even parse, but that's beside the point here (or maybe it get split per line or something into separate queries regardless).

1 Like