mirror of
				https://github.com/postgres/postgres.git
				synced 2025-10-31 10:30:33 +03:00 
			
		
		
		
	Generalize hash and ordering support in amapi
Stop comparing access method OID values against HASH_AM_OID and BTREE_AM_OID, and instead check the IndexAmRoutine for an index to see if it advertises its ability to perform the necessary ordering, hashing, or cross-type comparing functionality. A field amcanorder already existed, this uses it more widely. Fields amcanhash and amcancrosscompare are added for the other purposes. Author: Mark Dilger <mark.dilger@enterprisedb.com> Discussion: https://www.postgresql.org/message-id/flat/E72EAA49-354D-4C2E-8EB9-255197F55330@enterprisedb.com
This commit is contained in:
		| @@ -109,6 +109,8 @@ blhandler(PG_FUNCTION_ARGS) | ||||
| 	amroutine->amoptsprocnum = BLOOM_OPTIONS_PROC; | ||||
| 	amroutine->amcanorder = false; | ||||
| 	amroutine->amcanorderbyop = false; | ||||
| 	amroutine->amcanhash = false; | ||||
| 	amroutine->amcancrosscompare = false; | ||||
| 	amroutine->amcanbackward = false; | ||||
| 	amroutine->amcanunique = false; | ||||
| 	amroutine->amcanmulticol = true; | ||||
|   | ||||
| @@ -103,6 +103,10 @@ typedef struct IndexAmRoutine | ||||
|     bool        amcanorder; | ||||
|     /* does AM support ORDER BY result of an operator on indexed column? */ | ||||
|     bool        amcanorderbyop; | ||||
|     /* does AM support hashing using API consistent with the hash AM? */ | ||||
|     bool        amcanhash; | ||||
|     /* does AM support cross-type comparisons? */ | ||||
|     bool        amcancrosscompare; | ||||
|     /* does AM support backward scanning? */ | ||||
|     bool        amcanbackward; | ||||
|     /* does AM support UNIQUE indexes? */ | ||||
|   | ||||
| @@ -256,6 +256,8 @@ brinhandler(PG_FUNCTION_ARGS) | ||||
| 	amroutine->amoptsprocnum = BRIN_PROCNUM_OPTIONS; | ||||
| 	amroutine->amcanorder = false; | ||||
| 	amroutine->amcanorderbyop = false; | ||||
| 	amroutine->amcanhash = false; | ||||
| 	amroutine->amcancrosscompare = false; | ||||
| 	amroutine->amcanbackward = false; | ||||
| 	amroutine->amcanunique = false; | ||||
| 	amroutine->amcanmulticol = true; | ||||
|   | ||||
| @@ -43,6 +43,8 @@ ginhandler(PG_FUNCTION_ARGS) | ||||
| 	amroutine->amoptsprocnum = GIN_OPTIONS_PROC; | ||||
| 	amroutine->amcanorder = false; | ||||
| 	amroutine->amcanorderbyop = false; | ||||
| 	amroutine->amcanhash = false; | ||||
| 	amroutine->amcancrosscompare = false; | ||||
| 	amroutine->amcanbackward = false; | ||||
| 	amroutine->amcanunique = false; | ||||
| 	amroutine->amcanmulticol = true; | ||||
|   | ||||
| @@ -65,6 +65,8 @@ gisthandler(PG_FUNCTION_ARGS) | ||||
| 	amroutine->amoptsprocnum = GIST_OPTIONS_PROC; | ||||
| 	amroutine->amcanorder = false; | ||||
| 	amroutine->amcanorderbyop = true; | ||||
| 	amroutine->amcanhash = false; | ||||
| 	amroutine->amcancrosscompare = false; | ||||
| 	amroutine->amcanbackward = false; | ||||
| 	amroutine->amcanunique = false; | ||||
| 	amroutine->amcanmulticol = true; | ||||
|   | ||||
| @@ -64,6 +64,8 @@ hashhandler(PG_FUNCTION_ARGS) | ||||
| 	amroutine->amoptsprocnum = HASHOPTIONS_PROC; | ||||
| 	amroutine->amcanorder = false; | ||||
| 	amroutine->amcanorderbyop = false; | ||||
| 	amroutine->amcanhash = true; | ||||
| 	amroutine->amcancrosscompare = false; | ||||
| 	amroutine->amcanbackward = true; | ||||
| 	amroutine->amcanunique = false; | ||||
| 	amroutine->amcanmulticol = false; | ||||
|   | ||||
| @@ -107,6 +107,8 @@ bthandler(PG_FUNCTION_ARGS) | ||||
| 	amroutine->amoptsprocnum = BTOPTIONS_PROC; | ||||
| 	amroutine->amcanorder = true; | ||||
| 	amroutine->amcanorderbyop = false; | ||||
| 	amroutine->amcanhash = false; | ||||
| 	amroutine->amcancrosscompare = true; | ||||
| 	amroutine->amcanbackward = true; | ||||
| 	amroutine->amcanunique = true; | ||||
| 	amroutine->amcanmulticol = true; | ||||
|   | ||||
| @@ -50,6 +50,8 @@ spghandler(PG_FUNCTION_ARGS) | ||||
| 	amroutine->amoptsprocnum = SPGIST_OPTIONS_PROC; | ||||
| 	amroutine->amcanorder = false; | ||||
| 	amroutine->amcanorderbyop = true; | ||||
| 	amroutine->amcanhash = false; | ||||
| 	amroutine->amcancrosscompare = false; | ||||
| 	amroutine->amcanbackward = false; | ||||
| 	amroutine->amcanunique = false; | ||||
| 	amroutine->amcanmulticol = false; | ||||
|   | ||||
| @@ -1242,25 +1242,25 @@ assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid, | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * btree comparison procs must be 2-arg procs returning int4.  btree | ||||
| 	 * sortsupport procs must take internal and return void.  btree in_range | ||||
| 	 * procs must be 5-arg procs returning bool.  btree equalimage procs must | ||||
| 	 * take 1 arg and return bool.  hash support proc 1 must be a 1-arg proc | ||||
| 	 * returning int4, while proc 2 must be a 2-arg proc returning int8. | ||||
| 	 * Otherwise we don't know. | ||||
| 	 * Ordering comparison procs must be 2-arg procs returning int4.  Ordering | ||||
| 	 * sortsupport procs must take internal and return void.  Ordering | ||||
| 	 * in_range procs must be 5-arg procs returning bool.  Ordering equalimage | ||||
| 	 * procs must take 1 arg and return bool.  Hashing support proc 1 must be | ||||
| 	 * a 1-arg proc returning int4, while proc 2 must be a 2-arg proc | ||||
| 	 * returning int8. Otherwise we don't know. | ||||
| 	 */ | ||||
| 	else if (amoid == BTREE_AM_OID) | ||||
| 	else if (GetIndexAmRoutineByAmId(amoid, false)->amcanorder) | ||||
| 	{ | ||||
| 		if (member->number == BTORDER_PROC) | ||||
| 		{ | ||||
| 			if (procform->pronargs != 2) | ||||
| 				ereport(ERROR, | ||||
| 						(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), | ||||
| 						 errmsg("btree comparison functions must have two arguments"))); | ||||
| 						 errmsg("ordering comparison functions must have two arguments"))); | ||||
| 			if (procform->prorettype != INT4OID) | ||||
| 				ereport(ERROR, | ||||
| 						(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), | ||||
| 						 errmsg("btree comparison functions must return integer"))); | ||||
| 						 errmsg("ordering comparison functions must return integer"))); | ||||
|  | ||||
| 			/* | ||||
| 			 * If lefttype/righttype isn't specified, use the proc's input | ||||
| @@ -1277,11 +1277,11 @@ assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid, | ||||
| 				procform->proargtypes.values[0] != INTERNALOID) | ||||
| 				ereport(ERROR, | ||||
| 						(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), | ||||
| 						 errmsg("btree sort support functions must accept type \"internal\""))); | ||||
| 						 errmsg("ordering sort support functions must accept type \"internal\""))); | ||||
| 			if (procform->prorettype != VOIDOID) | ||||
| 				ereport(ERROR, | ||||
| 						(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), | ||||
| 						 errmsg("btree sort support functions must return void"))); | ||||
| 						 errmsg("ordering sort support functions must return void"))); | ||||
|  | ||||
| 			/* | ||||
| 			 * Can't infer lefttype/righttype from proc, so use default rule | ||||
| @@ -1292,11 +1292,11 @@ assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid, | ||||
| 			if (procform->pronargs != 5) | ||||
| 				ereport(ERROR, | ||||
| 						(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), | ||||
| 						 errmsg("btree in_range functions must have five arguments"))); | ||||
| 						 errmsg("ordering in_range functions must have five arguments"))); | ||||
| 			if (procform->prorettype != BOOLOID) | ||||
| 				ereport(ERROR, | ||||
| 						(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), | ||||
| 						 errmsg("btree in_range functions must return boolean"))); | ||||
| 						 errmsg("ordering in_range functions must return boolean"))); | ||||
|  | ||||
| 			/* | ||||
| 			 * If lefttype/righttype isn't specified, use the proc's input | ||||
| @@ -1312,11 +1312,11 @@ assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid, | ||||
| 			if (procform->pronargs != 1) | ||||
| 				ereport(ERROR, | ||||
| 						(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), | ||||
| 						 errmsg("btree equal image functions must have one argument"))); | ||||
| 						 errmsg("ordering equal image functions must have one argument"))); | ||||
| 			if (procform->prorettype != BOOLOID) | ||||
| 				ereport(ERROR, | ||||
| 						(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), | ||||
| 						 errmsg("btree equal image functions must return boolean"))); | ||||
| 						 errmsg("ordering equal image functions must return boolean"))); | ||||
|  | ||||
| 			/* | ||||
| 			 * pg_amproc functions are indexed by (lefttype, righttype), but | ||||
| @@ -1329,10 +1329,10 @@ assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid, | ||||
| 			if (member->lefttype != member->righttype) | ||||
| 				ereport(ERROR, | ||||
| 						(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), | ||||
| 						 errmsg("btree equal image functions must not be cross-type"))); | ||||
| 						 errmsg("ordering equal image functions must not be cross-type"))); | ||||
| 		} | ||||
| 	} | ||||
| 	else if (amoid == HASH_AM_OID) | ||||
| 	else if (GetIndexAmRoutineByAmId(amoid, false)->amcanhash) | ||||
| 	{ | ||||
| 		if (member->number == HASHSTANDARD_PROC) | ||||
| 		{ | ||||
|   | ||||
| @@ -1331,10 +1331,10 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index, | ||||
| 				varattno = ((Var *) leftop)->varattno; | ||||
|  | ||||
| 				/* | ||||
| 				 * We have to look up the operator's associated btree support | ||||
| 				 * We have to look up the operator's associated support | ||||
| 				 * function | ||||
| 				 */ | ||||
| 				if (index->rd_rel->relam != BTREE_AM_OID || | ||||
| 				if (!index->rd_indam->amcanorder || | ||||
| 					varattno < 1 || varattno > indnkeyatts) | ||||
| 					elog(ERROR, "bogus RowCompare index qualification"); | ||||
| 				opfamily = index->rd_opfamily[varattno - 1]; | ||||
|   | ||||
							
								
								
									
										8
									
								
								src/backend/utils/cache/lsyscache.c
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								src/backend/utils/cache/lsyscache.c
									
									
									
									
										vendored
									
									
								
							| @@ -716,10 +716,9 @@ equality_ops_are_compatible(Oid opno1, Oid opno2) | ||||
| 	{ | ||||
| 		HeapTuple	op_tuple = &catlist->members[i]->tuple; | ||||
| 		Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple); | ||||
| 		IndexAmRoutine *amroutine = GetIndexAmRoutineByAmId(op_form->amopmethod, false); | ||||
|  | ||||
| 		/* must be btree or hash */ | ||||
| 		if (op_form->amopmethod == BTREE_AM_OID || | ||||
| 			op_form->amopmethod == HASH_AM_OID) | ||||
| 		if (amroutine->amcancrosscompare) | ||||
| 		{ | ||||
| 			if (op_in_opfamily(opno2, op_form->amopfamily)) | ||||
| 			{ | ||||
| @@ -767,8 +766,9 @@ comparison_ops_are_compatible(Oid opno1, Oid opno2) | ||||
| 	{ | ||||
| 		HeapTuple	op_tuple = &catlist->members[i]->tuple; | ||||
| 		Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple); | ||||
| 		IndexAmRoutine *amroutine = GetIndexAmRoutineByAmId(op_form->amopmethod, false); | ||||
|  | ||||
| 		if (op_form->amopmethod == BTREE_AM_OID) | ||||
| 		if (amroutine->amcanorder && amroutine->amcancrosscompare) | ||||
| 		{ | ||||
| 			if (op_in_opfamily(opno2, op_form->amopfamily)) | ||||
| 			{ | ||||
|   | ||||
| @@ -243,6 +243,10 @@ typedef struct IndexAmRoutine | ||||
| 	bool		amcanorder; | ||||
| 	/* does AM support ORDER BY result of an operator on indexed column? */ | ||||
| 	bool		amcanorderbyop; | ||||
| 	/* does AM support hashing using API consistent with the hash AM? */ | ||||
| 	bool		amcanhash; | ||||
| 	/* does AM support cross-type comparisons? */ | ||||
| 	bool		amcancrosscompare; | ||||
| 	/* does AM support backward scanning? */ | ||||
| 	bool		amcanbackward; | ||||
| 	/* does AM support UNIQUE indexes? */ | ||||
|   | ||||
| @@ -282,6 +282,8 @@ dihandler(PG_FUNCTION_ARGS) | ||||
| 	amroutine->amsupport = 1; | ||||
| 	amroutine->amcanorder = false; | ||||
| 	amroutine->amcanorderbyop = false; | ||||
| 	amroutine->amcanhash = false; | ||||
| 	amroutine->amcancrosscompare = false; | ||||
| 	amroutine->amcanbackward = false; | ||||
| 	amroutine->amcanunique = false; | ||||
| 	amroutine->amcanmulticol = false; | ||||
|   | ||||
| @@ -420,7 +420,7 @@ BEGIN TRANSACTION; | ||||
| CREATE OPERATOR FAMILY alt_opf12 USING btree; | ||||
| CREATE FUNCTION fn_opf12  (int4, int2) RETURNS BIGINT AS 'SELECT NULL::BIGINT;' LANGUAGE SQL; | ||||
| ALTER OPERATOR FAMILY alt_opf12 USING btree ADD FUNCTION 1 fn_opf12(int4, int2); | ||||
| ERROR:  btree comparison functions must return integer | ||||
| ERROR:  ordering comparison functions must return integer | ||||
| DROP OPERATOR FAMILY alt_opf12 USING btree; | ||||
| ERROR:  current transaction is aborted, commands ignored until end of transaction block | ||||
| ROLLBACK; | ||||
| @@ -438,7 +438,7 @@ BEGIN TRANSACTION; | ||||
| CREATE OPERATOR FAMILY alt_opf14 USING btree; | ||||
| CREATE FUNCTION fn_opf14 (int4) RETURNS BIGINT AS 'SELECT NULL::BIGINT;' LANGUAGE SQL; | ||||
| ALTER OPERATOR FAMILY alt_opf14 USING btree ADD FUNCTION 1 fn_opf14(int4); | ||||
| ERROR:  btree comparison functions must have two arguments | ||||
| ERROR:  ordering comparison functions must have two arguments | ||||
| DROP OPERATOR FAMILY alt_opf14 USING btree; | ||||
| ERROR:  current transaction is aborted, commands ignored until end of transaction block | ||||
| ROLLBACK; | ||||
| @@ -504,7 +504,7 @@ ALTER OPERATOR FAMILY alt_opf18 USING btree ADD | ||||
| -- Should fail. Not allowed to have cross-type equalimage function. | ||||
| ALTER OPERATOR FAMILY alt_opf18 USING btree | ||||
|   ADD FUNCTION 4 (int4, int2) btequalimage(oid); | ||||
| ERROR:  btree equal image functions must not be cross-type | ||||
| ERROR:  ordering equal image functions must not be cross-type | ||||
| ALTER OPERATOR FAMILY alt_opf18 USING btree DROP FUNCTION 2 (int4, int4); | ||||
| ERROR:  function 2(integer,integer) does not exist in operator family "alt_opf18" | ||||
| DROP OPERATOR FAMILY alt_opf18 USING btree; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user