On Wed, Jul 11, 2018 at 03:13:30PM -0400, Alvaro Herrera wrote: > On 2018-Jun-06, Nico Williams wrote: > > I've finally gotten around to rebasing this patch and making the change > > that was requested, which was: merge the now-would-be-three deferral- > > related bool columns in various pg_catalog tables into one char column. > > > > Instead of (deferrable, initdeferred, alwaysdeferred), now there is just > > (deferral). > > Nice stuff. > > Please add #defines for the chars in pg_constraint.h instead of using > the values directly in the source. Also, catalogs.sgml has a typo in > one of the values. > > What happens if you do SET CONSTRAINTS ALL IMMEDIATE and you have one of > these constraints? I expect that it silently does not alter that > constraint, but you didn't change that manpage.
Correct, that's the idea, that it should be possible to write deferred constraints/triggers which users cannot make immediate. For example, an audit extension that logs changes via FOR EACH ROW ALWAYS DEFERRED, or my PoC COMMIT TRIGGER implementation (which depends on deferred triggers). I missed that there is a page for SET CONSTRAINTS! I'll update it. > I suggest not to include psql/tab-complete changes with your main patch. > If you want to update it, split it out to its own patch. Committer can > choose to include it in one commit or not (I'm mildly inclined not to, > but I'm probably inconsistent about it), but for review IMO it's better > not to mix things -- It's way too easy to get entangled in silly details > while editing that code, and it's not critical anyway. OK, sure, though, of course, the committer could always leave that out themselves, no? To me though it seems that the change should be complete. > > Incidentally, I had to do commit-by-commit rebasing to make the rebase > > easier. I have a shell function I use for this, if anyone wants a copy > > of it -- sometimes it's much easier to do this than to do one huge jump. > > I've done this manually a few times. Please share, I'm curious. OK, attached is my latest version of that script, though this one is a bit changed from the one I used. This version tries to be faster / more efficient by first doing 1 commit, then 2, then 3, and so on, and on conflict aborts and halves N to try again. The idea is to only have to merge conflicts at each commit where conflicts arise, never resolving conflicts across more than one commit -- this makes is much easier to reason about conflicts! Note that the script is actually a shell function, and that it keeps state in shel variables. A better implementation would do the sort of thing that git(1) itself does to keep rebase state. Nico --
# Based on a shell function by Viktor Dukhovni # # slowrebase BRANCH_TO_REBASE ONTO function slowrebase { typeset b N if (($# > 0)) && [[ $1 = -h || $1 = --help ]]; then printf 'Usage: slowrebase BRANCH_TO_REBASE ONTO_HEAD\n' printf ' slowrebase # to continue after resolving conflicts\n' printf '\n\tslowrebase is a shell function that uses the following\n' printf '\tglobal variables to keep state: $S $T $B ${C[@]}\n' printf '\t $slowrebase_window_sz\n' printf '\tDO NOT CHANGE THOSE VARIABLES.\n' return 0 elif (($# > 0 && $# != 2)); then printf 'Usage: slowrebase BRANCH_TO_REBASE ONTO_HEAD\n' 1>&2 printf ' slowrebase # to continue after resolving conflicts\n' printf '\n\tslowrebase is a shell function that uses the following\n' 1>&2 printf '\tglobal variables to keep state: $S $T $B ${C[@]}\n' 1>&2 printf '\t $slowrebase_window_sz\n' 1>&2 printf '\tDO NOT CHANGE THOSE VARIABLES.\n' 1>&2 return 1 fi if (($# == 2)); then slowrebase_window_sz=1 S=$1 T=$2 B=$(git merge-base "$S" "$T") C=( $(git log --oneline "$B".."$2" | awk '{print $1}') ) set -- # Prep git log -n1 "$S" > /dev/null || return 1 if [[ $(git log --oneline -n1 HEAD) != $(git log --oneline -n1 "$S") ]]; then if (($(git status -sb | wc -l) != 1)); then printf 'Error: please clean your workspace\n' return 1 fi git checkout "$S" elif (($(git status -sbuno | wc -l) != 1)); then printf 'Error: please clean your workspace\n' return 1 fi # Fall through to get started elif [[ $(git log --oneline -n1 HEAD) != $(git log --oneline -n1 "$S") ]] && ! git rebase --continue; then N=$(( ${#C[@]} - slowrebase_window_sz )) printf '\nConflicts while rebasing $S (%s) slowly onto $T (%s)\n' "$S" "$T" printf '${C[@]} has the commits left to process (%s left)\n' $N printf '$B is the commit we are rebasing onto right now: %s\n' "$B" printf '$b is the previous commit we had already rebased onto: %s\n' "$b" return 1 fi while ((${#C[@]} > 0)); do printf '%s commits left\n' ${#C[@]} N=$(( ${#C[@]} - slowrebase_window_sz )) b=$B B=${C[$N]} printf 'Rebasing onto %s\n' "$(git log --oneline -n1 "$B")" if git rebase --onto "$B" "$b" "$S"; then # No conflicts. Let's go faster if we can. if ((slowrebase_window_sz < N)); then ((slowrebase_window_sz++)) fi C=(${C[@]:0:$N}) continue fi # We have conflicts; bisect if we can if ((slowrebase_window_sz > 1)); then # Bisect to find the first commit causing the conflicts ((slowrebase_window_sz = (slowrebase_window_sz + 1) / 2)) git rebase --abort continue fi # Finally, we have a commit causing conflicts. The user has to # resolve and invoke this function again. unset C[$N] printf '\nConflicts while rebasing $S (%s) slowly onto $T (%s)\n' "$S" "$T" printf '${C[@]} has the commits left to process (%s left)\n' ${#C[@]} printf '$B is the commit we are rebasing onto right now: %s\n' "$B" printf '$b is the previous commit we had already rebased onto: %s\n' "$b" return 1 done printf '\n\nDONE!\n' return 0 }