I've experimented successfully with synchronizing two nodes of different types with each other, so that when one node is saved, a function is called that checks if a certain field has been updated and then changes the relevant nodes accordingly. This works well when I use it as the rule action "Execute custom PHP code" fired by the event "Before saving content". However, a strange error occurs when I use a modification of the same function and use the event "After saving new content". Everything seems to be in order with the code but when it saves the other node(s) I get the following error:

PDOException: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '34-3-content_access_rid' for key 'PRIMARY': INSERT INTO {node_access} (nid, realm, gid, grant_view, grant_update, grant_delete) VALUES (:db_insert_placeholder_0, :db_insert_placeholder_1, :db_insert_placeholder_2, :db_insert_placeholder_3, :db_insert_placeholder_4, :db_insert_placeholder_5); Array ( [:db_insert_placeholder_0] => 34 [:db_insert_placeholder_1] => content_access_rid [:db_insert_placeholder_2] => 3 [:db_insert_placeholder_3] => 1 [:db_insert_placeholder_4] => 0 [:db_insert_placeholder_5] => 0 ) i node_access_write_grants() (rad 3334 av /hsphere/local/home/triprod/triprod.se/modules/node/node.module)

You can replicate this error by creating the content types "projekt" and "resurs", with "projekt" having a Node reference field with the machine name "field_resurs" that references the "resurs" content type, and the type "resurs" similarly having a node reference field named "field_projekt" which references the "projekt" content type. Then you set up a rule with the event "After saving new content" and the action "Execute custom PHP code", with the value being in this case <? drupalmod_sync_two_content_fields_create($node); ?>. Then you create a custom module with the name "drupalmod" and insert the code below into the .module file. Then you create a new node with either one of the two content types above, and insert a value into the node reference field (this of course means that you must have already created a node of the type that is referenced). I selected the option of unlimited values so that I can add more of them, but I don't believe that it matters. When you finally save the new node you should get a similar error message as the one above. As it says "Duplicate entry '34-3-content_access_rid'" I figured that the error is related to Content Access. Here's the code for the custom module:

function drupalmod_sync_two_content_fields_create(&$one_node_new) {
	//Fälten måste vara en array med strukturen i->"nid"->nid
	$temp = '';
	$allowed_content_types = array(
	"projekt",
	"resurs",
	);
	if(!in_array($one_node_new->type, $allowed_content_types)) { //Fel content type, end.
		return true;
	}
	$content_type = $one_node_new->type;
	switch($content_type) {
		case "resurs":
			$one_field_new = $one_node_new->field_projekt;
		break;
		case "projekt":
			$one_field_new = $one_node_new->field_resurs;
		break;
		default:
		break;
	}
	if(!$one_field_new) { //Det fält vi är intresserade av är tomt, end.
		return true;
	}
	$change = -1;
	$tempkey = array();
	$tempkey = array_keys($one_field_new);
	$one_field_new = $one_field_new[$tempkey[0]];
	$one_nid = $one_node_new->nid;
	$other_nid = array();
	$temp .= 'one_nid: <BR />' . $one_nid . '<BR /><BR />other_nid[]: <BR />';
	foreach($one_field_new as $key1 => $index) {
		foreach($index as $key2 => $value) {
	    	$other_nid[] = $value;
			$temp .= $value . '<BR />';
    	}
  	}
	$temp .= '<BR />';
	foreach($other_nid as $key => $value) {
		$other_node = node_load($value, NULL, TRUE);
		switch($content_type) {
			case "resurs":
				$tempkey = array();
				$tempkey = array_keys($other_node->field_resurs);
				$other_field = &$other_node->field_resurs[$tempkey[0]];
			break;
			case "projekt":
				$tempkey = array();
				$tempkey = array_keys($other_node->field_projekt);
				$other_field = &$other_node->field_projekt[$tempkey[0]];
			break;
			default:
			break;
		}
		$other_field[] = array('nid' => $one_nid);
		node_save($other_node);
	}
	drupal_set_message($temp);
	return true;
}
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

ordermind’s picture

Oh yeah, and for the two content types described above I used Content Access to set the viewing permissions to administrators only.

Itangalo’s picture

I, too, get a similar error message. Also, my use case is much simpler:

1) Enable per-node access settings for a content type.
2) Have a rule trigger on new node save, with an action to add access per role.
-> You end up with the error message.

However, if you have the rule trigger on node view instead, all works fine.

After contemplating (and examining) this bug for a while, I believe that it is caused by the node being saved twice on the same page load – once for Rules, once for something else. And I suspect that the results for content_access_save_per_node_settings is cached somewhere, tricking it into inserting the same entries into {content_access} more than once.

Those are my five cents on what's going on here.

PS: A workaround for me right now is to trigger the rule with a flag instead of node save. If anyone would be helped by it.

good_man’s picture

Can you please retry with the latest dev version? the version of 1st July. If you didn't see the new version, give the packaging script sometime to package it, or get it hot from the git repository.

Itangalo’s picture

Status: Active » Reviewed & tested by the community

Works very fine indeed!

I've tried this on two browsers and two different test cases. Marking it RTBC (though if anyone else would like to test it I don't mind).

good_man’s picture

@Itangalo: cool thanks for testing! we are very close to a beta release.

P.S. Can we work on a screencast when we release, you are the expert in this field :)

Itangalo’s picture

@good_man: I am actually planning a screencast series on Rules 2, where Content Access will be a part. As I see it, Content Access is mostly useful in combination with other modules (though you could of course manage access settings manually, too).

Good enough?

good_man’s picture

Status: Reviewed & tested by the community » Fixed

Ok I'll mark this issue as fixed now, and if you need some help with the screen cast contact me :)

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

jocken’s picture

I'm still getting the error. I'm creating a new node while saving another one.

good_man’s picture

@jocken: are you using the latest dev version of content access?

netivajak’s picture

Apologies for posting to a closed and aging issue but I'm also seeing this error/behaviour. Latest dev version of content_access (Nov 24 2011) used.

I see two errors with the same time stamp, one of type php and one of type node.

good_man’s picture

@netiva jak: No problem, but I need you to tell me what steps you made to get this error (i.e. steps to reproduce it on my test machine so I can fix it)?

netivajak’s picture

Thanks - create a rule that:

updates a node field via set data value
which is triggered on After saving new content or Before saving content
when content_access is enabled

good_man’s picture

Status: Closed (fixed) » Active

This is a core bug, will wait for #1352924: Node grants when triggered twice, return PDO exception to get committed.

netivajak’s picture

Status: Active » Closed (fixed)

Many thanks.

good_man’s picture

Status: Closed (fixed) » Active

Let's keep it open.

majorbenks’s picture

Version: 7.x-1.x-dev » 7.x-1.2-beta1

I get still this error with 7.x-1.2-beta1.
Here is what I'm doing: I have a node A with a node reference to node x. A rule sends me an email when a node A is created.
If I turn off the rule, the error does not occur. If I leave the node reference blank, the error also doesn't occur. The mistake must be somewhere in the combination of these two modules. It seems not to have an impact whether I give access to anonymous user or only to other roles.

Here is the exact errormessage:
PDOException: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '270-0-all' for key 'PRIMARY': INSERT INTO {node_access} (nid, realm, gid, grant_view, grant_update, grant_delete) VALUES (:db_insert_placeholder_0, :db_insert_placeholder_1, :db_insert_placeholder_2, :db_insert_placeholder_3, :db_insert_placeholder_4, :db_insert_placeholder_5); Array ( [:db_insert_placeholder_0] => 270 [:db_insert_placeholder_1] => all [:db_insert_placeholder_2] => 0 [:db_insert_placeholder_3] => 1 [:db_insert_placeholder_4] => 0 [:db_insert_placeholder_5] => 0 ) in node_access_write_grants() (line 3425 of /httpdocs/modules/node/node.module).

sgurlt’s picture

Hello everyone,

actually i am having some trouble with the content access rules integration.
My rule look like this:

Event:
After saving new content

Condition:
User has Role

Action:
Grant access by role

The rule works perfect, but when I translate my page to german, it crashs with the error you see at the button. I imported the german rules and access content translation packs with no success.

When I change the Eventtype to "Before saving content", there is no more error, but the rule stops to work :/

Any idea about that?!

PDOException: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '98-6-content_access_rid' for key 1: INSERT INTO {node_access} (nid, realm, gid, grant_view, grant_update, grant_delete) VALUES (:db_insert_placeholder_0, :db_insert_placeholder_1, :db_insert_placeholder_2, :db_insert_placeholder_3, :db_insert_placeholder_4, :db_insert_placeholder_5), (:db_insert_placeholder_6, :db_insert_placeholder_7, :db_insert_placeholder_8, :db_insert_placeholder_9, :db_insert_placeholder_10, :db_insert_placeholder_11); Array ( [:db_insert_placeholder_0] => 98 [:db_insert_placeholder_1] => content_access_rid [:db_insert_placeholder_2] => 6 [:db_insert_placeholder_3] => 1 [:db_insert_placeholder_4] => 1 [:db_insert_placeholder_5] => 1 [:db_insert_placeholder_6] => 98 [:db_insert_placeholder_7] => all [:db_insert_placeholder_8] => 0 [:db_insert_placeholder_9] => 1 [:db_insert_placeholder_10] => 0 [:db_insert_placeholder_11] => 0 ) in node_access_write_grants() (Zeile 3417 von /srv/www/lebenmittel_test/modules/node/node.module).

Greetz from Ger

SG

aendra’s picture

I'm also getting this:

PDOException: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '163-3-content_access_rid' for key 'PRIMARY': INSERT INTO {node_access} (nid, realm, gid, grant_view, grant_update, grant_delete) VALUES (:db_insert_placeholder_0, :db_insert_placeholder_1, :db_insert_placeholder_2, :db_insert_placeholder_3, :db_insert_placeholder_4, :db_insert_placeholder_5); Array ( [:db_insert_placeholder_0] => 163 [:db_insert_placeholder_1] => content_access_rid [:db_insert_placeholder_2] => 3 [:db_insert_placeholder_3] => 1 [:db_insert_placeholder_4] => 0 [:db_insert_placeholder_5] => 0 ) in node_access_write_grants() (line 3392 of /home/site/public_html/modules/node/node.module).

I'm using EntityReference 7.x-1.0-rc5 and Content Access 7.x-1.2-beta1. The content type I'm referencing uses the EntityReference field in a Rule that sends out an email (nothing really access-related).

Update: As with sg88's rule in http://drupal.org/node/1097248#comment-6382048, mine uses a "After content is saved" event. Changing it to a "before content is saved" event causes everything to work again. Alas, I need a valid nid for my rule to fire properly, so I need that event to work.

Any help with this? This issue is roughly about a year and a half old at this point...

Delty’s picture

Having a similar issue with Rules - seems like a check is needed to update the entry if exists instead of trying to create it. No idea really though, and this issue is quite old and always occurring with the "After content is saved" event.

Any help would be greatly appreciated!

Delty’s picture

I found a link on the Rules page to a thread in the core issue queue with a patch to the D7 core node module that fixed the issue for me when using pretty much any access control module - tested successfully with Workflow Access, Content Access and Private. It should get rolled into the next core dev release, but until then I hope it helps out a few people - took me two days to find it.

http://drupal.org/node/1146244

-=Delty

aendra’s picture

Confirming that the patch at http://drupal.org/node/1146244#comment-6492226 fixes this.

@Delty -- Thank you *so* much. I've spent the last 2-3 hours in Xdebug trying and failing to locate what was going on with this. You are officially my hero and today's King Of The Internet.

mh86’s picture

Version: 7.x-1.2-beta1 » 7.x-1.x-dev
Status: Active » Needs review
FileSize
1.88 KB

When applying the patch from #1146244: node_access integrity constraint violation on module_invoke_all('node_' . $op, $node); (comment 65) you might get troubles with ACL lists, as now the node grants are written before the node hooks are invoked.
Content Access has a very ugly work-around in content_access_action_aquire_grants() for the current version of core,

function content_access_action_aquire_grants($node) {
  // node_save() does implement node_access_acquire_grants() so we don't want
  // to execute it again or we'll get a duplicated key exception
  if (!isset($node->op) ||
      (isset($node->op) && $node->op != 'Save')) {
    node_access_acquire_grants($node);
  }
}

So it only calls node_access_acquire_grants when $node->op is not set or not called 'Save'. $node->op contains the value of the submit button, which can of course be customized or translated. In that case it won't work anyway.

Furthermore, as #1146244: node_access integrity constraint violation on module_invoke_all('node_' . $op, $node); changes the order of the hook invocation, node_access_acquire_grants($node) must be called in any case to update the node access table in case access has been changed with your Rules.

mh86’s picture

And now a patch without a syntax error...

Delty’s picture

Thanks everyone for working on this. Your efforts are much appreciated!

I updated to the latest security release of D7 (7.16) and a cursory look at the code suggests that the patch in #1146244: node_access integrity constraint violation on module_invoke_all('node_' . $op, $node); either was not included or was significantly re-written before being committed. I'm not exactly sure what was changed but it seems that whatever they included provided a fix similar to #1146244 because my node access permissions all seem to be working correctly without generating any errors.

At this point I've only done a cursory test, so if anyone has a chance to do more, please post your findings here.

majorbenks’s picture

Update on #17:
If I use the event "Before content is saved" the error does not appear.

Anyway, I think my specific problem is not a content permission problem: If deinstall content permission, the error does still appear.

StoraH’s picture

Gilad.Gr’s picture

hey, i have encountered this same bug once again..
PDOException: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '2086-7-content_access_rid' for key 'PRIMARY': INSERT INTO {node_access} (nid, realm, gid, grant_view, grant_update, grant_delete) VALUES .......

but this didn't happen with all users what made it very weird.. i finally figured it out so i post here in case someone else will have this problem.

the last fix that solved this was these lines in the "content_access_action_aquire_grants" function:
if (!isset($node->op) ||
(isset($node->op) && $node->op != 'Save')) {
...
}

but my site is multilanguage, so when a user was not on an English site the 'op' held the translation value of "Save" which make these lines worthless, my fix was to use the t() function here, means changing the 'Save' to t('Save') and now it works once again.

thanks for this great module!

Ace Cooper’s picture

The latest Drupal core patch for node in that thread helped me:
https://drupal.org/comment/7290062#comment-7290062

Read the thread, there is are a couple of good explanations.
I will add my efforts to this cause when I finish my current project.

Thank you, StoraH, for the link to the previous patch version.

gisle’s picture