git diff --patience

Started by Kevin Grittnerover 15 years ago11 messages
#1Kevin Grittner
Kevin.Grittner@wicourts.gov

I just discovered the --patience flag on the git diff command, and
I'd like to suggest that we encourage people to use it when possible
for building patches. I just looked at output with and without it
(and for good measure, before and after filterdiff --format=context
for both), and the results were much better with this switch.

Here's a reference to the algorithm:

http://bramcohen.livejournal.com/73318.html

I think that page understates the benefits, though.

-Kevin

#2Bruce Momjian
bruce@momjian.us
In reply to: Kevin Grittner (#1)
Re: git diff --patience

Kevin Grittner wrote:

I just discovered the --patience flag on the git diff command, and
I'd like to suggest that we encourage people to use it when possible
for building patches. I just looked at output with and without it
(and for good measure, before and after filterdiff --format=context
for both), and the results were much better with this switch.

Here's a reference to the algorithm:

http://bramcohen.livejournal.com/73318.html

I think that page understates the benefits, though.

I have seen the bracket example shown and the --patience output is
clearly nicer.

--
Bruce Momjian <bruce@momjian.us> http://momjian.us
EnterpriseDB http://enterprisedb.com

+ It's impossible for everything to be true. +

#3Peter Eisentraut
peter_e@gmx.net
In reply to: Kevin Grittner (#1)
Re: git diff --patience

On ons, 2010-09-15 at 12:58 -0500, Kevin Grittner wrote:

I just discovered the --patience flag on the git diff command, and
I'd like to suggest that we encourage people to use it when possible
for building patches. I just looked at output with and without it
(and for good measure, before and after filterdiff --format=context
for both), and the results were much better with this switch.

I have tried this switch various times now and haven't seen any
difference at all in the output. Do you have an existing commit where
you see a difference so I can try it and see if there is some other
problem that my local configuration has?

#4Kevin Grittner
Kevin.Grittner@wicourts.gov
In reply to: Peter Eisentraut (#3)
2 attachment(s)
Re: git diff --patience

Peter Eisentraut <peter_e@gmx.net> wrote:

I have tried this switch various times now and haven't seen any
difference at all in the output. Do you have an existing commit
where you see a difference so I can try it and see if there is
some other problem that my local configuration has?

Having looked at it more, I find that the output with the switch is
usually the same as without; but when they differ, I always have
preferred the version with it on. Attached is the diff which caused
me to see if there was a way to make the diff output smarter, and
the result of adding the --patience flag.

This is the unified form that git puts out by default, but the
benefit is there after filterdiff --format=context, too.

-Kevin

Attachments:

patience-off.diffapplication/octet-stream; name=patience-off.diffDownload
diff --git a/src/include/storage/predicate.h b/src/include/storage/predicate.h
index d071c21..7dcc2af 100644
--- a/src/include/storage/predicate.h
+++ b/src/include/storage/predicate.h
@@ -1,7 +1,7 @@
 /*-------------------------------------------------------------------------
  *
  * predicate.h
- *	  POSTGRES predicate locking definitions.
+ *	  POSTGRES public predicate locking definitions.
  *
  *
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
@@ -14,137 +14,15 @@
 #ifndef PREDICATE_H
 #define PREDICATE_H
 
-#include "access/htup.h"
-#include "storage/lock.h"
 #include "utils/relcache.h"
 #include "utils/snapshot.h"
 
-/* GUC variables */
-extern int	max_predicate_locks_per_xact;
-
-/*
- * The SERIALIZABLEXACTTAG struct identifies a serializable transaction.
- */
-typedef struct SERIALIZABLEXACTTAG
-{
-	VirtualTransactionId vxid;	/* We always have one of these. */
-} SERIALIZABLEXACTTAG;
-
-/*
- * Information needed for each serializable database transaction to support SSI techniques.
- * TODO SSI: Should inConflict and outConflict be lists?  That would allow us to reduce
- *			 false positives, *and* would allow us to guarantee that an immediate retry
- *			 of a transaction would never fail on the exact same conflicts.
- *			 The RAM doesn't look like it would be the limiting factor, but CPU time might
- *			 be -- we should have baseline benchmarks before attempting this.
- */
-typedef struct SERIALIZABLEXACT
-{
-	/* hash key */
-	SERIALIZABLEXACTTAG tag;
-
-	/* data */
-	struct SERIALIZABLEXACT *outConflict;		/* ptr to write transaction
-												 * whose data we couldn't
-												 * read. invalid means no
-												 * conflict; self-reference
-												 * means multiple or
-												 * committed. */
-	struct SERIALIZABLEXACT *inConflict;		/* ptr to read transaction
-												 * which couldn't see our
-												 * write. invalid means no
-												 * conflict; self-reference
-												 * means multiple or
-												 * committed. */
-	TransactionId topXid;		/* top level xid for the transaction, if one
-								 * exists */
-	TransactionId finishedBefore;		/* invalid means still running; else
-										 * the struct expires when no tags <
-										 * this. */
-	TransactionId xmin;			/* the transaction's snapshot xmin */
-	SHM_QUEUE	predicateLocks; /* list of associated PREDICATELOCK objects */
-	SHM_QUEUE	xids;			/* list of associated SERIALIZABLEXID objects */
-	SHM_QUEUE	finishedLink;	/* list link in
-								 * FinishedSerializableTransactions */
-	bool		rolledBack;		/* ignore conflicts when true; allows deferred
-								 * cleanup */
-} SERIALIZABLEXACT;
-
-
-typedef enum PredicateLockTargetType
-{
-	PREDLOCKTAG_RELATION,
-	PREDLOCKTAG_PAGE,
-	PREDLOCKTAG_TUPLE
-	/* TODO Other types may be needed for index locking */
-}	PredicateLockTargetType;
 
 /*
- * The PREDICATELOCKTARGETTAG struct is defined to fit into 16
- * bytes with no padding.  Note that this would need adjustment if we were
- * to widen Oid or BlockNumber to more than 32 bits.
- */
-typedef struct PREDICATELOCKTARGETTAG
-{
-	uint32		locktag_field1; /* a 32-bit ID field */
-	uint32		locktag_field2; /* a 32-bit ID field */
-	uint32		locktag_field3; /* a 32-bit ID field */
-	uint16		locktag_field4; /* a 16-bit ID field */
-	uint16		locktag_field5; /* a 16-bit ID field */
-} PREDICATELOCKTARGETTAG;
-
-/*
- * These macros define how we map logical IDs of lockable objects into
- * the physical fields of PREDICATELOCKTARGETTAG.	Use these to set up values,
- * rather than accessing the fields directly.  Note multiple eval of target!
- *
- * TODO SSI: If we always use the same fields for the same type of value,
- * we should rename these.	Holding off until it's clear there are no exceptions.
- * Since indexes are relations with blocks and tuples, it's looking likely that
- * the rename will be possible.  If not, we may need to divide the last field
- * and use part of it for a target type, so that we know how to interpret the
- * data..
+ * GUC variables
  */
-#define SET_PREDICATELOCKTARGETTAG_RELATION(locktag,dboid,reloid) \
-	((locktag).locktag_field1 = (dboid), \
-	 (locktag).locktag_field2 = (reloid), \
-	 (locktag).locktag_field3 = InvalidBlockNumber, \
-	 (locktag).locktag_field4 = InvalidOffsetNumber, \
-	 (locktag).locktag_field5 = 0)
-
-#define SET_PREDICATELOCKTARGETTAG_PAGE(locktag,dboid,reloid,blocknum) \
-	((locktag).locktag_field1 = (dboid), \
-	 (locktag).locktag_field2 = (reloid), \
-	 (locktag).locktag_field3 = (blocknum), \
-	 (locktag).locktag_field4 = InvalidOffsetNumber, \
-	 (locktag).locktag_field5 = 0)
-
-#define SET_PREDICATELOCKTARGETTAG_TUPLE(locktag,dboid,reloid,blocknum,offnum) \
-	((locktag).locktag_field1 = (dboid), \
-	 (locktag).locktag_field2 = (reloid), \
-	 (locktag).locktag_field3 = (blocknum), \
-	 (locktag).locktag_field4 = (offnum), \
-	 (locktag).locktag_field5 = 0)
-
-#define GET_PREDICATELOCKTARGETTAG_DB(locktag) \
-	((locktag).locktag_field1)
-#define GET_PREDICATELOCKTARGETTAG_RELATION(locktag) \
-	((locktag).locktag_field2)
-#define GET_PREDICATELOCKTARGETTAG_PAGE(locktag) \
-	((locktag).locktag_field3)
-#define GET_PREDICATELOCKTARGETTAG_OFFSET(locktag) \
-	((locktag).locktag_field4)
-#define GET_PREDICATELOCKTARGETTAG_TYPE(locktag)							 \
-	(((locktag).locktag_field4 != InvalidOffsetNumber) ? PREDLOCKTAG_TUPLE : \
-	 (((locktag).locktag_field3 != InvalidBlockNumber) ? PREDLOCKTAG_PAGE :   \
-	  PREDLOCKTAG_RELATION))
+extern int	max_predicate_locks_per_xact;
 
-typedef struct PredicateLockData
-{
-	int			nelements;
-	PREDICATELOCKTARGETTAG *locktags;
-	SERIALIZABLEXACT *xacts;
-} PredicateLockData;
 
 /*
  * function prototypes
@@ -155,7 +33,6 @@ extern void InitPredicateLocks(void);
 extern Size PredicateLockShmemSize(void);
 
 /* predicate lock reporting */
-extern PredicateLockData *GetPredicateLockStatusData(void);
 extern bool PageIsPredicateLocked(const Relation relation, const BlockNumber blkno);
 
 /* predicate lock maintenance */
patience-on.diffapplication/octet-stream; name=patience-on.diffDownload
diff --git a/src/include/storage/predicate.h b/src/include/storage/predicate.h
index d071c21..7dcc2af 100644
--- a/src/include/storage/predicate.h
+++ b/src/include/storage/predicate.h
@@ -1,7 +1,7 @@
 /*-------------------------------------------------------------------------
  *
  * predicate.h
- *	  POSTGRES predicate locking definitions.
+ *	  POSTGRES public predicate locking definitions.
  *
  *
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
@@ -14,137 +14,15 @@
 #ifndef PREDICATE_H
 #define PREDICATE_H
 
-#include "access/htup.h"
-#include "storage/lock.h"
 #include "utils/relcache.h"
 #include "utils/snapshot.h"
 
-/* GUC variables */
+
+/*
+ * GUC variables
+ */
 extern int	max_predicate_locks_per_xact;
 
-/*
- * The SERIALIZABLEXACTTAG struct identifies a serializable transaction.
- */
-typedef struct SERIALIZABLEXACTTAG
-{
-	VirtualTransactionId vxid;	/* We always have one of these. */
-} SERIALIZABLEXACTTAG;
-
-/*
- * Information needed for each serializable database transaction to support SSI techniques.
- * TODO SSI: Should inConflict and outConflict be lists?  That would allow us to reduce
- *			 false positives, *and* would allow us to guarantee that an immediate retry
- *			 of a transaction would never fail on the exact same conflicts.
- *			 The RAM doesn't look like it would be the limiting factor, but CPU time might
- *			 be -- we should have baseline benchmarks before attempting this.
- */
-typedef struct SERIALIZABLEXACT
-{
-	/* hash key */
-	SERIALIZABLEXACTTAG tag;
-
-	/* data */
-	struct SERIALIZABLEXACT *outConflict;		/* ptr to write transaction
-												 * whose data we couldn't
-												 * read. invalid means no
-												 * conflict; self-reference
-												 * means multiple or
-												 * committed. */
-	struct SERIALIZABLEXACT *inConflict;		/* ptr to read transaction
-												 * which couldn't see our
-												 * write. invalid means no
-												 * conflict; self-reference
-												 * means multiple or
-												 * committed. */
-	TransactionId topXid;		/* top level xid for the transaction, if one
-								 * exists */
-	TransactionId finishedBefore;		/* invalid means still running; else
-										 * the struct expires when no tags <
-										 * this. */
-	TransactionId xmin;			/* the transaction's snapshot xmin */
-	SHM_QUEUE	predicateLocks; /* list of associated PREDICATELOCK objects */
-	SHM_QUEUE	xids;			/* list of associated SERIALIZABLEXID objects */
-	SHM_QUEUE	finishedLink;	/* list link in
-								 * FinishedSerializableTransactions */
-	bool		rolledBack;		/* ignore conflicts when true; allows deferred
-								 * cleanup */
-} SERIALIZABLEXACT;
-
-
-typedef enum PredicateLockTargetType
-{
-	PREDLOCKTAG_RELATION,
-	PREDLOCKTAG_PAGE,
-	PREDLOCKTAG_TUPLE
-	/* TODO Other types may be needed for index locking */
-}	PredicateLockTargetType;
-
-/*
- * The PREDICATELOCKTARGETTAG struct is defined to fit into 16
- * bytes with no padding.  Note that this would need adjustment if we were
- * to widen Oid or BlockNumber to more than 32 bits.
- */
-typedef struct PREDICATELOCKTARGETTAG
-{
-	uint32		locktag_field1; /* a 32-bit ID field */
-	uint32		locktag_field2; /* a 32-bit ID field */
-	uint32		locktag_field3; /* a 32-bit ID field */
-	uint16		locktag_field4; /* a 16-bit ID field */
-	uint16		locktag_field5; /* a 16-bit ID field */
-} PREDICATELOCKTARGETTAG;
-
-/*
- * These macros define how we map logical IDs of lockable objects into
- * the physical fields of PREDICATELOCKTARGETTAG.	Use these to set up values,
- * rather than accessing the fields directly.  Note multiple eval of target!
- *
- * TODO SSI: If we always use the same fields for the same type of value,
- * we should rename these.	Holding off until it's clear there are no exceptions.
- * Since indexes are relations with blocks and tuples, it's looking likely that
- * the rename will be possible.  If not, we may need to divide the last field
- * and use part of it for a target type, so that we know how to interpret the
- * data..
- */
-#define SET_PREDICATELOCKTARGETTAG_RELATION(locktag,dboid,reloid) \
-	((locktag).locktag_field1 = (dboid), \
-	 (locktag).locktag_field2 = (reloid), \
-	 (locktag).locktag_field3 = InvalidBlockNumber, \
-	 (locktag).locktag_field4 = InvalidOffsetNumber, \
-	 (locktag).locktag_field5 = 0)
-
-#define SET_PREDICATELOCKTARGETTAG_PAGE(locktag,dboid,reloid,blocknum) \
-	((locktag).locktag_field1 = (dboid), \
-	 (locktag).locktag_field2 = (reloid), \
-	 (locktag).locktag_field3 = (blocknum), \
-	 (locktag).locktag_field4 = InvalidOffsetNumber, \
-	 (locktag).locktag_field5 = 0)
-
-#define SET_PREDICATELOCKTARGETTAG_TUPLE(locktag,dboid,reloid,blocknum,offnum) \
-	((locktag).locktag_field1 = (dboid), \
-	 (locktag).locktag_field2 = (reloid), \
-	 (locktag).locktag_field3 = (blocknum), \
-	 (locktag).locktag_field4 = (offnum), \
-	 (locktag).locktag_field5 = 0)
-
-#define GET_PREDICATELOCKTARGETTAG_DB(locktag) \
-	((locktag).locktag_field1)
-#define GET_PREDICATELOCKTARGETTAG_RELATION(locktag) \
-	((locktag).locktag_field2)
-#define GET_PREDICATELOCKTARGETTAG_PAGE(locktag) \
-	((locktag).locktag_field3)
-#define GET_PREDICATELOCKTARGETTAG_OFFSET(locktag) \
-	((locktag).locktag_field4)
-#define GET_PREDICATELOCKTARGETTAG_TYPE(locktag)							 \
-	(((locktag).locktag_field4 != InvalidOffsetNumber) ? PREDLOCKTAG_TUPLE : \
-	 (((locktag).locktag_field3 != InvalidBlockNumber) ? PREDLOCKTAG_PAGE :   \
-	  PREDLOCKTAG_RELATION))
-
-typedef struct PredicateLockData
-{
-	int			nelements;
-	PREDICATELOCKTARGETTAG *locktags;
-	SERIALIZABLEXACT *xacts;
-} PredicateLockData;
 
 /*
  * function prototypes
@@ -155,7 +33,6 @@ extern void InitPredicateLocks(void);
 extern Size PredicateLockShmemSize(void);
 
 /* predicate lock reporting */
-extern PredicateLockData *GetPredicateLockStatusData(void);
 extern bool PageIsPredicateLocked(const Relation relation, const BlockNumber blkno);
 
 /* predicate lock maintenance */
#5Kevin Grittner
Kevin.Grittner@wicourts.gov
In reply to: Peter Eisentraut (#3)
2 attachment(s)
Re: git diff --patience

Peter Eisentraut <peter_e@gmx.net> wrote:

Do you have an existing commit where you see a difference so I can
try it and see if there is some other problem that my local
configuration has?

Random poking around in the postgresql.git commits didn't turn up
any where it mattered, so here's before and after files for the
example diff files already posted. If you create branch, commit the
before copy, and copy in the after copy, you should be able to
replicate the results I posted.

-Kevin

Attachments:

predicate.h-beforeapplication/octet-stream; name=predicate.h-beforeDownload
predicate.h-afterapplication/octet-stream; name=predicate.h-afterDownload
#6Gurjeet Singh
singh.gurjeet@gmail.com
In reply to: Kevin Grittner (#5)
2 attachment(s)
Re: git diff --patience

Attached are two versions of the same patch, with and without --patience.

The with-patience version has only two hunks, removal of a big block of
comment and addition of a big block of code.

The without-patience patience is riddled with the mix of two hunks, spread
until line 120.

--patience is a clear winner here.

Regards,

On Wed, Sep 29, 2010 at 5:10 PM, Kevin Grittner <Kevin.Grittner@wicourts.gov

wrote:

Peter Eisentraut <peter_e@gmx.net> wrote:

Do you have an existing commit where you see a difference so I can
try it and see if there is some other problem that my local
configuration has?

Random poking around in the postgresql.git commits didn't turn up
any where it mattered, so here's before and after files for the
example diff files already posted. If you create branch, commit the
before copy, and copy in the after copy, you should be able to
replicate the results I posted.

-Kevin

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

--
gurjeet.singh
@ EnterpriseDB - The Enterprise Postgres Company
http://www.EnterpriseDB.com

singh.gurjeet@{ gmail | yahoo }.com
Twitter/Skype: singh_gurjeet

Mail sent from my BlackLaptop device

Attachments:

diff_without_patience.patchapplication/octet-stream; name=diff_without_patience.patchDownload
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index 788464e..432a4aa 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -1931,6 +1931,7 @@ transformAlterTableStmt(AlterTableStmt *stmt, const char *queryString)
 	List	   *newcmds = NIL;
 	bool		skipValidation = true;
 	AlterTableCmd *newcmd;
+	Oid	index_oid = InvalidOid;
 
 	/*
 	 * We must not scribble on the passed-in AlterTableStmt, so copy it. (This
@@ -2047,35 +2048,152 @@ transformAlterTableStmt(AlterTableStmt *stmt, const char *queryString)
 
 	transformFKConstraints(pstate, &cxt, skipValidation, true);
 
-	/* TODO: look at cxt->pkey->options and see if it has 'USING INDEX'; if yes
-			then cook-up an ALTER TABLE DROP CONSTRAINT for table's primary key,
-			and push into newcmds
+	/*
+	 * If the PRIMARY KEY clasue has WITH INDEX option set, then prepare to use
+	 * that index as the primary key.
+	 */
+	if (cxt.pkey)
+	foreach(l, cxt.pkey->options)
+	{
+		DefElem		*def = (DefElem*)lfirst(l);
+		Oid			pkey_oid;
+		char		*index_name;
+		char		*oid_string;
+		List		*index_name_list;
+		RangeVar	*index_rv;
+		Relation	index_rel;
+
+		if (def->defnamespace == NULL && 0 == strcmp(def->defname, "index"))
+		{
+			if (!(def->defaction == DEFELEM_UNSPEC || def->defaction == DEFELEM_SET))
+				elog(ERROR, "index option for a primary key has a syntax error." );
+		}
+		else
+			continue;
+
+		/*
+		 * If we don't do this, WITH INDEX will get to DefineIndex(), and it will
+		 * throw a fit.
+		 */
+		if (index_oid != InvalidOid)
+			elog(ERROR, "only one WITH INDEX option can be specified for a primary key.");
+
+		if (!IsA(def->arg, String))
+			elog(ERROR, "WITH INDEX option for primary key should be a string value");
+
+		index_name = strVal(def->arg);
 
-	Check if cxt->pkey->options has a 'USING INDEX' element
-		take an exclusive lock on that index
+		index_name_list = stringToQualifiedNameList(index_name);
 
-		Does this table have a primary key
-			check if index mentioned in cxt->pkey matches that PKEY definition,
-				Does column list match
-				Does index type metch (BTree for now)
-				Do they have the same owner
+		/* TODO: Should we assert that this is not a qualified name? */
+		index_rv = makeRangeVarFromNameList(index_name_list);
 
-		Append a new command to newcmds to drop the PKey constraint
-			use 'rel' variable to get primary key's OID ( modify and reuse relationHasPrimaryKey() )
-			use relation_open() to get pkey's relation
-			use the returned Relation->rd_rel->relname to build DROP CONSTRAINT command
-			set missingok member of the command so that this would work even if there was already a DROP CONSTRAINT for the PKey.
-			push this command to newcmds
+		index_rel = relation_openrv(index_rv, AccessExclusiveLock);
 
-		Chenge the 'USING INDEX' element, and replace index name in Value* to have decimal representation of index's OID.
-			This will be used by ATExecAddIndex().
-			string = DatumGetCString(DirectFunctionCall1(oidout,
-												ObjectIdGetDatum(tupleOid)));
+		index_oid = RelationGetRelid(index_rel);
+
+		oid_string = DatumGetCString(DirectFunctionCall1(oidout,
+												ObjectIdGetDatum(index_oid)));
+
+		/*
+		 * Replace index name with its Oid::cstring; ATAddIndex() will use this
+		 * OID for the primary key.
+		 */
+		def->arg = (Node*)makeString(oid_string);
+
+		/* set index name in the statement, to affect the constraint name */
+		cxt.pkey->idxname = pstrdup(strVal(llast(index_name_list)));
+
+		pkey_oid = relationHasPrimaryKey(rel);
+
+		if (pkey_oid != InvalidOid)
+		{
+			HeapTuple		pkey_tuple;
+			HeapTuple		index_tuple;
+			Form_pg_index	pkey_form;
+			Form_pg_index	index_form;
+			AlterTableCmd	*at_cmd;
+			int2			i;
+			Relation		pkey_rel;
+
+			pkey_rel = relation_open(pkey_oid, AccessExclusiveLock);
+
+			/*
+			 * Check pg_class->relam to see if the index type match. As of now, only
+			 * BTree indexes are used to implement primary keys, but it doesn't hurt
+			 * to be future proof.
+			 */
+			if (pkey_rel->rd_rel->relam != index_rel->rd_rel->relam)
+				elog(ERROR, "index type of WITH INDEX argument and that of the primary key are not the same.");
 
-			We need decimal representation of OID since int32 to Oid mapping may not be future proof.
-				TODO check with -hackers
+			if (pkey_rel->rd_rel->relowner != index_rel->rd_rel->relowner)
+				elog(ERROR, "owner of WITH INDEX argument and that of the primary key are not same.");
 
-  */
+			if (pkey_rel->rd_rel->relnamespace != index_rel->rd_rel->relnamespace)
+				elog(ERROR, "index in WITH INDEX argument is not in the correct namespace.");
+
+			pkey_tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(pkey_oid));
+			if (!HeapTupleIsValid(pkey_tuple))
+				elog(ERROR, "cache lookup failed for index %u", pkey_oid);
+			pkey_form = (Form_pg_index) GETSTRUCT(pkey_tuple);
+
+			index_tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(index_oid));
+			if (!HeapTupleIsValid(index_tuple))
+				elog(ERROR, "cache lookup failed for index %u", index_oid);
+			index_form = (Form_pg_index) GETSTRUCT(index_tuple);
+
+			if (!index_form->indisvalid)
+				elog(ERROR, "index mentioned in the WITH INDEX clause of primary key is not valid.");
+
+			if (!index_form->indisready)
+				elog(ERROR, "index mentioned in the WITH INDEX clause of primary key is not ready.");
+
+			if (!index_form->indisunique)
+				elog(ERROR, "index mentioned in the WITH INDEX clause of primary key is not a unique index.");
+
+			/* TODO: Should we check for indcheckxmin ?*/
+
+			if (index_form->indrelid != pkey_form->indrelid)
+				elog(ERROR, "index mentioned in the WITH INDEX clause of primary key is not on the same table.");
+
+			if (index_form->indnatts != pkey_form->indnatts)
+				elog(ERROR, "idefinition of index mentioned in the WITH INDEX clause does not match primary key.");
+
+			/*
+			 * Loop over each attribute in the primary key and see if it
+			 * matches the attributes of the index we are replacing it with.
+			 */
+			for (i = 0; i < pkey_form->indnatts; i++)
+			{
+				/* We do not expect primary keys on expressions */
+				Assert(pkey_form->indkey.values[i] != 0);
+
+				if (pkey_form->indkey.values[i] != index_form->indkey.values[i])
+					elog(ERROR, "idefinition of index mentioned in the WITH INDEX clause does not match primary key.");
+
+				if (pkey_form->indclass.values[i] != index_form->indclass.values[i])
+					elog(ERROR, "operator classes of index mentioned in the WITH INDEX clause does not match those of primary key.");
+			}
+
+			ReleaseSysCache(pkey_tuple);
+			ReleaseSysCache(index_tuple);
+
+			at_cmd = makeNode(AlterTableCmd);
+			at_cmd->subtype = AT_DropConstraint;
+			at_cmd->name = pstrdup(NameStr(pkey_rel->rd_rel->relname));
+			at_cmd->behavior = DROP_CASCADE;;
+			at_cmd->missing_ok = true;
+
+			newcmds = lappend(newcmds, at_cmd);
+
+			/* Release the lock so that it can be dropped from cache. */
+			relation_close(pkey_rel, AccessExclusiveLock);
+		}
+
+		relation_close(index_rel, NoLock);
+
+		/* do not break; at the end of the loop. Use this opprtunity to catch multiple 'WITH INDEX' clauses*/
+	}
 
 	/*
 	 * Push any index-creation commands into the ALTER, so that they can be
diff_with_patience.patchapplication/octet-stream; name=diff_with_patience.patchDownload
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index 788464e..432a4aa 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -1931,6 +1931,7 @@ transformAlterTableStmt(AlterTableStmt *stmt, const char *queryString)
 	List	   *newcmds = NIL;
 	bool		skipValidation = true;
 	AlterTableCmd *newcmd;
+	Oid	index_oid = InvalidOid;
 
 	/*
 	 * We must not scribble on the passed-in AlterTableStmt, so copy it. (This
@@ -2047,35 +2048,152 @@ transformAlterTableStmt(AlterTableStmt *stmt, const char *queryString)
 
 	transformFKConstraints(pstate, &cxt, skipValidation, true);
 
-	/* TODO: look at cxt->pkey->options and see if it has 'USING INDEX'; if yes
-			then cook-up an ALTER TABLE DROP CONSTRAINT for table's primary key,
-			and push into newcmds
-
-	Check if cxt->pkey->options has a 'USING INDEX' element
-		take an exclusive lock on that index
-
-		Does this table have a primary key
-			check if index mentioned in cxt->pkey matches that PKEY definition,
-				Does column list match
-				Does index type metch (BTree for now)
-				Do they have the same owner
-
-		Append a new command to newcmds to drop the PKey constraint
-			use 'rel' variable to get primary key's OID ( modify and reuse relationHasPrimaryKey() )
-			use relation_open() to get pkey's relation
-			use the returned Relation->rd_rel->relname to build DROP CONSTRAINT command
-			set missingok member of the command so that this would work even if there was already a DROP CONSTRAINT for the PKey.
-			push this command to newcmds
-
-		Chenge the 'USING INDEX' element, and replace index name in Value* to have decimal representation of index's OID.
-			This will be used by ATExecAddIndex().
-			string = DatumGetCString(DirectFunctionCall1(oidout,
-												ObjectIdGetDatum(tupleOid)));
-
-			We need decimal representation of OID since int32 to Oid mapping may not be future proof.
-				TODO check with -hackers
-
-  */
+	/*
+	 * If the PRIMARY KEY clasue has WITH INDEX option set, then prepare to use
+	 * that index as the primary key.
+	 */
+	if (cxt.pkey)
+	foreach(l, cxt.pkey->options)
+	{
+		DefElem		*def = (DefElem*)lfirst(l);
+		Oid			pkey_oid;
+		char		*index_name;
+		char		*oid_string;
+		List		*index_name_list;
+		RangeVar	*index_rv;
+		Relation	index_rel;
+
+		if (def->defnamespace == NULL && 0 == strcmp(def->defname, "index"))
+		{
+			if (!(def->defaction == DEFELEM_UNSPEC || def->defaction == DEFELEM_SET))
+				elog(ERROR, "index option for a primary key has a syntax error." );
+		}
+		else
+			continue;
+
+		/*
+		 * If we don't do this, WITH INDEX will get to DefineIndex(), and it will
+		 * throw a fit.
+		 */
+		if (index_oid != InvalidOid)
+			elog(ERROR, "only one WITH INDEX option can be specified for a primary key.");
+
+		if (!IsA(def->arg, String))
+			elog(ERROR, "WITH INDEX option for primary key should be a string value");
+
+		index_name = strVal(def->arg);
+
+		index_name_list = stringToQualifiedNameList(index_name);
+
+		/* TODO: Should we assert that this is not a qualified name? */
+		index_rv = makeRangeVarFromNameList(index_name_list);
+
+		index_rel = relation_openrv(index_rv, AccessExclusiveLock);
+
+		index_oid = RelationGetRelid(index_rel);
+
+		oid_string = DatumGetCString(DirectFunctionCall1(oidout,
+												ObjectIdGetDatum(index_oid)));
+
+		/*
+		 * Replace index name with its Oid::cstring; ATAddIndex() will use this
+		 * OID for the primary key.
+		 */
+		def->arg = (Node*)makeString(oid_string);
+
+		/* set index name in the statement, to affect the constraint name */
+		cxt.pkey->idxname = pstrdup(strVal(llast(index_name_list)));
+
+		pkey_oid = relationHasPrimaryKey(rel);
+
+		if (pkey_oid != InvalidOid)
+		{
+			HeapTuple		pkey_tuple;
+			HeapTuple		index_tuple;
+			Form_pg_index	pkey_form;
+			Form_pg_index	index_form;
+			AlterTableCmd	*at_cmd;
+			int2			i;
+			Relation		pkey_rel;
+
+			pkey_rel = relation_open(pkey_oid, AccessExclusiveLock);
+
+			/*
+			 * Check pg_class->relam to see if the index type match. As of now, only
+			 * BTree indexes are used to implement primary keys, but it doesn't hurt
+			 * to be future proof.
+			 */
+			if (pkey_rel->rd_rel->relam != index_rel->rd_rel->relam)
+				elog(ERROR, "index type of WITH INDEX argument and that of the primary key are not the same.");
+
+			if (pkey_rel->rd_rel->relowner != index_rel->rd_rel->relowner)
+				elog(ERROR, "owner of WITH INDEX argument and that of the primary key are not same.");
+
+			if (pkey_rel->rd_rel->relnamespace != index_rel->rd_rel->relnamespace)
+				elog(ERROR, "index in WITH INDEX argument is not in the correct namespace.");
+
+			pkey_tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(pkey_oid));
+			if (!HeapTupleIsValid(pkey_tuple))
+				elog(ERROR, "cache lookup failed for index %u", pkey_oid);
+			pkey_form = (Form_pg_index) GETSTRUCT(pkey_tuple);
+
+			index_tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(index_oid));
+			if (!HeapTupleIsValid(index_tuple))
+				elog(ERROR, "cache lookup failed for index %u", index_oid);
+			index_form = (Form_pg_index) GETSTRUCT(index_tuple);
+
+			if (!index_form->indisvalid)
+				elog(ERROR, "index mentioned in the WITH INDEX clause of primary key is not valid.");
+
+			if (!index_form->indisready)
+				elog(ERROR, "index mentioned in the WITH INDEX clause of primary key is not ready.");
+
+			if (!index_form->indisunique)
+				elog(ERROR, "index mentioned in the WITH INDEX clause of primary key is not a unique index.");
+
+			/* TODO: Should we check for indcheckxmin ?*/
+
+			if (index_form->indrelid != pkey_form->indrelid)
+				elog(ERROR, "index mentioned in the WITH INDEX clause of primary key is not on the same table.");
+
+			if (index_form->indnatts != pkey_form->indnatts)
+				elog(ERROR, "idefinition of index mentioned in the WITH INDEX clause does not match primary key.");
+
+			/*
+			 * Loop over each attribute in the primary key and see if it
+			 * matches the attributes of the index we are replacing it with.
+			 */
+			for (i = 0; i < pkey_form->indnatts; i++)
+			{
+				/* We do not expect primary keys on expressions */
+				Assert(pkey_form->indkey.values[i] != 0);
+
+				if (pkey_form->indkey.values[i] != index_form->indkey.values[i])
+					elog(ERROR, "idefinition of index mentioned in the WITH INDEX clause does not match primary key.");
+
+				if (pkey_form->indclass.values[i] != index_form->indclass.values[i])
+					elog(ERROR, "operator classes of index mentioned in the WITH INDEX clause does not match those of primary key.");
+			}
+
+			ReleaseSysCache(pkey_tuple);
+			ReleaseSysCache(index_tuple);
+
+			at_cmd = makeNode(AlterTableCmd);
+			at_cmd->subtype = AT_DropConstraint;
+			at_cmd->name = pstrdup(NameStr(pkey_rel->rd_rel->relname));
+			at_cmd->behavior = DROP_CASCADE;;
+			at_cmd->missing_ok = true;
+
+			newcmds = lappend(newcmds, at_cmd);
+
+			/* Release the lock so that it can be dropped from cache. */
+			relation_close(pkey_rel, AccessExclusiveLock);
+		}
+
+		relation_close(index_rel, NoLock);
+
+		/* do not break; at the end of the loop. Use this opprtunity to catch multiple 'WITH INDEX' clauses*/
+	}
 
 	/*
 	 * Push any index-creation commands into the ALTER, so that they can be
#7Kevin Grittner
Kevin.Grittner@wicourts.gov
In reply to: Gurjeet Singh (#6)
Re: git diff --patience

Gurjeet Singh <singh.gurjeet@gmail.com> wrote:

The with-patience version has only two hunks, removal of a big
block of comment and addition of a big block of code.

The without-patience patience is riddled with the mix of two
hunks, spread until line 120.

--patience is a clear winner here.

When I read the description of the algorithm, I can't imagine a
situation where --patience would make the diff *worse*. I was
somewhat afraid (based on the name) that it would be slow; but
if it is slower, it hasn't been by enough for me to notice it.

-Kevin

#8Alvaro Herrera
alvherre@commandprompt.com
In reply to: Kevin Grittner (#7)
Re: git diff --patience

Excerpts from Kevin Grittner's message of jue sep 30 16:38:11 -0400 2010:

When I read the description of the algorithm, I can't imagine a
situation where --patience would make the diff *worse*. I was
somewhat afraid (based on the name) that it would be slow; but
if it is slower, it hasn't been by enough for me to notice it.

There is a very simple example posted on some of the blog posts that
goes something like

aaaaaaaa
aaaaaaaa
aaaaaaaa
bbbbbbbb
bbbbbbbb
bbbbbbbb
xyz

and the "xyz" is moved to the front. In this corner case, the patience
diff is a lot worse.

--
Álvaro Herrera <alvherre@commandprompt.com>
The PostgreSQL Company - Command Prompt, Inc.
PostgreSQL Replication, Consulting, Custom Development, 24x7 support

#9Gurjeet Singh
singh.gurjeet@gmail.com
In reply to: Alvaro Herrera (#8)
Re: git diff --patience

On Fri, Oct 1, 2010 at 9:38 AM, Alvaro Herrera
<alvherre@commandprompt.com>wrote:

Excerpts from Kevin Grittner's message of jue sep 30 16:38:11 -0400 2010:

When I read the description of the algorithm, I can't imagine a
situation where --patience would make the diff *worse*. I was
somewhat afraid (based on the name) that it would be slow; but
if it is slower, it hasn't been by enough for me to notice it.

There is a very simple example posted on some of the blog posts that
goes something like

aaaaaaaa
aaaaaaaa
aaaaaaaa
bbbbbbbb
bbbbbbbb
bbbbbbbb
xyz

and the "xyz" is moved to the front. In this corner case, the patience
diff is a lot worse.

Sorry, but that example didn't make much sense to me. Can you please
elaborate, or maybe share those blog posts you are referring to.

Regards,
--
gurjeet.singh
@ EnterpriseDB - The Enterprise Postgres Company
http://www.EnterpriseDB.com

singh.gurjeet@{ gmail | yahoo }.com
Twitter/Skype: singh_gurjeet

Mail sent from my BlackLaptop device

#10Kevin Grittner
Kevin.Grittner@wicourts.gov
In reply to: Gurjeet Singh (#9)
Re: git diff --patience

Gurjeet Singh <singh.gurjeet@gmail.com> wrote:

Alvaro Herrera <alvherre@commandprompt.com>wrote:

There is a very simple example posted on some of the blog posts
that goes something like

aaaaaaaa
aaaaaaaa
aaaaaaaa
bbbbbbbb
bbbbbbbb
bbbbbbbb
xyz

and the "xyz" is moved to the front. In this corner case, the
patience diff is a lot worse.

Sorry, but that example didn't make much sense to me. Can you
please elaborate, or maybe share those blog posts you are referring

to.

I tried it out. Here are the results:

git diff --color
diff --git a/a1 b/a1
index bd0586b..32736d1 100644
--- a/a1
+++ b/a1
@@ -1,7 +1,7 @@
+xyz
 aaaaaaaa
 aaaaaaaa
 aaaaaaaa
 bbbbbbbb
 bbbbbbbb
 bbbbbbbb
-xyz
git diff --color --patience
diff --git a/a1 b/a1
index bd0586b..32736d1 100644
--- a/a1
+++ b/a1
@@ -1,7 +1,7 @@
-aaaaaaaa
-aaaaaaaa
-aaaaaaaa
-bbbbbbbb
-bbbbbbbb
-bbbbbbbb
 xyz
+aaaaaaaa
+aaaaaaaa
+aaaaaaaa
+bbbbbbbb
+bbbbbbbb
+bbbbbbbb

This is because lines which only occur once in a file are the
"anchors" around which lines which occur multiple times move --
after keeping intact any leading and trailing lines which match
between the files. An interesting exercise it so think about what
real-life lines you could have which would have multiple occurrences
in this pattern, and think about whether you would then prefer the
--patience output, especially if this were part of a larger file.
Even in this supposed "worst case" example, I'm not at all sure I
wouldn't prefer --patience, personally, even though more lines are
flagged.

-Kevin

#11Greg Stark
gsstark@mit.edu
In reply to: Kevin Grittner (#10)
Re: git diff --patience

On Fri, Oct 1, 2010 at 7:15 AM, Kevin Grittner
<Kevin.Grittner@wicourts.gov> wrote:

An interesting exercise it so think about what
real-life lines you could have which would have multiple occurrences
in this pattern, and think about whether you would then prefer the
--patience output, especially if this were part of a larger file.

The linux-kernel mailing list had examples of this occurring in real
life too. In real C programs function signatures usually end up being
the unique lines which is what you want but it can happen that
surprising lines are unique. Even braces can be unique if a given
indentation level is only used once.

The discussion basically convinced me that using uniqueness alone is a
bad idea but that the basic idea of trying to identify the important
lines is a fine idea. It's just that uniqueness turns out to be a
relatively weak signal for interesting lines. Linus suggested
line-length but it's pretty debatable which is better.

--
greg