Skip to content

Commit ca5c2a8

Browse files
author
Ole John Aske
committed
WL#5940: Handler extension and optimizer addaption required for pushed joins.
1 parent 4e85e96 commit ca5c2a8

12 files changed

Lines changed: 272 additions & 104 deletions

sql/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ IF(HAVE_VISIBILITY_HIDDEN)
4949
ENDIF()
5050

5151
SET(SQL_SHARED_SOURCES
52+
abstract_query_plan.cc
5253
datadict.cc
5354
debug_sync.cc
5455
derror.cc

sql/ha_ndbcluster.cc

Lines changed: 8 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -12345,6 +12345,14 @@ ulonglong ha_ndbcluster::table_flags(void) const
1234512345
*/
1234612346
if (thd->variables.binlog_format == BINLOG_FORMAT_STMT)
1234712347
f= (f | HA_BINLOG_STMT_CAPABLE) & ~HA_HAS_OWN_BINLOGGING;
12348+
12349+
/**
12350+
* To maximize join pushability we want const-table
12351+
* optimization blocked if 'ndb_join_pushdown= on'
12352+
*/
12353+
if (THDVAR(thd, join_pushdown))
12354+
f= f | HA_BLOCK_CONST_TABLE;
12355+
1234812356
return f;
1234912357
}
1235012358

@@ -14504,97 +14512,6 @@ ha_ndbcluster::parent_of_pushed_join() const
1450414512
return NULL;
1450514513
}
1450614514

14507-
bool
14508-
ha_ndbcluster::test_push_flag(enum ha_push_flag flag) const
14509-
{
14510-
DBUG_ENTER("test_push_flag");
14511-
switch (flag) {
14512-
case HA_PUSH_BLOCK_CONST_TABLE:
14513-
{
14514-
/**
14515-
* We don't support join push down if...
14516-
* - not LM_CommittedRead
14517-
* - uses blobs
14518-
*/
14519-
THD *thd= current_thd;
14520-
if (unlikely(!THDVAR(thd, join_pushdown)))
14521-
DBUG_RETURN(false);
14522-
14523-
if (table->read_set != NULL && uses_blob_value(table->read_set))
14524-
{
14525-
DBUG_RETURN(false);
14526-
}
14527-
14528-
NdbOperation::LockMode lm= get_ndb_lock_mode(m_lock.type);
14529-
14530-
if (lm != NdbOperation::LM_CommittedRead)
14531-
{
14532-
DBUG_RETURN(false);
14533-
}
14534-
14535-
DBUG_RETURN(true);
14536-
}
14537-
case HA_PUSH_MULTIPLE_DEPENDENCY:
14538-
/**
14539-
* If any child operation within this pushed join refer
14540-
* column values (paramValues), the pushed join has dependencies
14541-
* in addition to the root operation itself.
14542-
*/
14543-
if (m_pushed_join_operation==PUSHED_ROOT &&
14544-
m_pushed_join_member->get_field_referrences_count() > 0) // Childs has field refs
14545-
{
14546-
DBUG_RETURN(true);
14547-
}
14548-
DBUG_RETURN(false);
14549-
14550-
case HA_PUSH_NO_ORDERED_INDEX:
14551-
{
14552-
if (m_pushed_join_operation != PUSHED_ROOT)
14553-
{
14554-
DBUG_RETURN(true);
14555-
}
14556-
const NdbQueryDef& query_def = m_pushed_join_member->get_query_def();
14557-
const NdbQueryOperationDef::Type root_type=
14558-
query_def.getQueryOperation((uint)PUSHED_ROOT)->getType();
14559-
14560-
/**
14561-
* Primary key/ unique key lookup is always 'ordered' wrt. itself.
14562-
*/
14563-
if (root_type == NdbQueryOperationDef::PrimaryKeyAccess ||
14564-
root_type == NdbQueryOperationDef::UniqueIndexAccess)
14565-
{
14566-
DBUG_RETURN(false);
14567-
}
14568-
14569-
/**
14570-
* Ordered index scan can be provided as an ordered resultset iff
14571-
* it has no child scans.
14572-
*/
14573-
if (root_type == NdbQueryOperationDef::OrderedIndexScan)
14574-
{
14575-
for (uint i= 1; i < query_def.getNoOfOperations(); i++)
14576-
{
14577-
const NdbQueryOperationDef::Type child_type=
14578-
query_def.getQueryOperation(i)->getType();
14579-
if (child_type == NdbQueryOperationDef::TableScan ||
14580-
child_type == NdbQueryOperationDef::OrderedIndexScan)
14581-
{
14582-
DBUG_RETURN(true);
14583-
}
14584-
}
14585-
DBUG_RETURN(false);
14586-
}
14587-
DBUG_RETURN(true);
14588-
}
14589-
14590-
default:
14591-
DBUG_ASSERT(0);
14592-
DBUG_RETURN(false);
14593-
}
14594-
DBUG_RETURN(false);
14595-
}
14596-
14597-
1459814515
/**
1459914516
@param[in] comment table comment defined by user
1460014517

sql/ha_ndbcluster.h

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -414,15 +414,6 @@ static void set_tabname(const char *pathname, char *tabname);
414414
bool maybe_pushable_join(const char*& reason) const;
415415
int assign_pushed_join(const ndb_pushed_join* pushed_join);
416416

417-
#ifdef NDB_WITHOUT_JOIN_PUSHDOWN
418-
enum ha_push_flag {
419-
HA_PUSH_BLOCK_CONST_TABLE,
420-
HA_PUSH_MULTIPLE_DEPENDENCY,
421-
HA_PUSH_NO_ORDERED_INDEX
422-
};
423-
#endif
424-
bool test_push_flag(enum ha_push_flag flag) const;
425-
426417
uint number_of_pushed_joins() const;
427418
const TABLE* root_of_pushed_join() const;
428419
const TABLE* parent_of_pushed_join() const;

sql/handler.cc

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5069,6 +5069,44 @@ int ha_table_exists_in_engine(THD* thd, const char* db, const char* name)
50695069
DBUG_RETURN(args.err);
50705070
}
50715071

5072+
/**
5073+
Prepare (sub-) sequences of joins in this statement
5074+
which may be pushed to each storage engine for execution.
5075+
*/
5076+
struct st_make_pushed_join_args
5077+
{
5078+
const AQP::Join_plan* plan; // Query plan provided by optimizer
5079+
int err; // Error code to return.
5080+
};
5081+
5082+
static my_bool make_pushed_join_handlerton(THD *thd, plugin_ref plugin,
5083+
void *arg)
5084+
{
5085+
st_make_pushed_join_args *vargs= (st_make_pushed_join_args *)arg;
5086+
handlerton *hton= plugin_data(plugin, handlerton *);
5087+
5088+
if (hton && hton->make_pushed_join)
5089+
{
5090+
const int error= hton->make_pushed_join(hton, thd, vargs->plan);
5091+
if (unlikely(error))
5092+
{
5093+
vargs->err = error;
5094+
return TRUE;
5095+
}
5096+
}
5097+
return FALSE;
5098+
}
5099+
5100+
int ha_make_pushed_joins(THD *thd, const AQP::Join_plan* plan)
5101+
{
5102+
DBUG_ENTER("ha_make_pushed_joins");
5103+
st_make_pushed_join_args args= {plan, 0};
5104+
plugin_foreach(thd, make_pushed_join_handlerton,
5105+
MYSQL_STORAGE_ENGINE_PLUGIN, &args);
5106+
DBUG_PRINT("exit", ("error: %d", args.err));
5107+
DBUG_RETURN(args.err);
5108+
}
5109+
50725110
#ifdef HAVE_NDB_BINLOG
50735111
/*
50745112
TODO: change this into a dynamic struct

sql/handler.h

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,12 @@ enum enum_alter_inplace_result {
231231
*/
232232
#define HA_READ_OUT_OF_SYNC (LL(1) << 40)
233233

234+
/*
235+
The handler don't want accesses to this table to
236+
be const-table optimized
237+
*/
238+
#define HA_BLOCK_CONST_TABLE (LL(1) << 41)
239+
234240
/* bits in index_flags(index_number) for what you can do with index */
235241
#define HA_READ_NEXT 1 /* TODO really use this flag */
236242
#define HA_READ_PREV 2 /* supports ::index_prev */
@@ -480,6 +486,10 @@ typedef ulonglong my_xid; // this line is the same as in log_event.h
480486
#define COMPATIBLE_DATA_YES 0
481487
#define COMPATIBLE_DATA_NO 1
482488

489+
namespace AQP {
490+
class Join_plan;
491+
};
492+
483493
/**
484494
struct xid_t is binary compatible with the XID structure as
485495
in the X/Open CAE Specification, Distributed Transaction Processing:
@@ -886,6 +896,8 @@ struct handlerton
886896
const char *wild, bool dir, List<LEX_STRING> *files);
887897
int (*table_exists_in_engine)(handlerton *hton, THD* thd, const char *db,
888898
const char *name);
899+
int (*make_pushed_join)(handlerton *hton, THD* thd,
900+
const AQP::Join_plan* plan);
889901

890902
/**
891903
List of all system tables specific to the SE.
@@ -2525,6 +2537,34 @@ class handler :public Sql_alloc
25252537
in_range_check_pushed_down= false;
25262538
}
25272539

2540+
/**
2541+
Reports #tables included in pushed join which this
2542+
handler instance is part of. ==0 -> Not pushed
2543+
*/
2544+
virtual uint number_of_pushed_joins() const
2545+
{ return 0; }
2546+
2547+
/**
2548+
If this handler instance is part of a pushed join sequence
2549+
returned TABLE instance being root of the pushed query?
2550+
*/
2551+
virtual const TABLE* root_of_pushed_join() const
2552+
{ return NULL; }
2553+
2554+
/**
2555+
If this handler instance is a child in a pushed join sequence
2556+
returned TABLE instance being my parent?
2557+
*/
2558+
virtual const TABLE* parent_of_pushed_join() const
2559+
{ return NULL; }
2560+
2561+
virtual int index_read_pushed(uchar * buf, const uchar * key,
2562+
key_part_map keypart_map)
2563+
{ return HA_ERR_WRONG_COMMAND; }
2564+
2565+
virtual int index_next_pushed(uchar * buf)
2566+
{ return HA_ERR_WRONG_COMMAND; }
2567+
25282568
/**
25292569
Part of old, deprecated in-place ALTER API.
25302570
*/
@@ -3195,6 +3235,9 @@ int ha_rollback_to_savepoint(THD *thd, SAVEPOINT *sv);
31953235
int ha_savepoint(THD *thd, SAVEPOINT *sv);
31963236
int ha_release_savepoint(THD *thd, SAVEPOINT *sv);
31973237

3238+
/* Build pushed joins in handlers implementing this feature */
3239+
int ha_make_pushed_joins(THD *thd, const AQP::Join_plan* plan);
3240+
31983241
/* these are called by storage engines */
31993242
void trans_register_ha(THD *thd, bool all, handlerton *ht);
32003243

sql/opt_explain.cc

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -904,6 +904,46 @@ bool Explain_table_base::explain_extra_common(const SQL_SELECT *select,
904904
return true;
905905
}
906906

907+
const TABLE* pushed_root= table->file->root_of_pushed_join();
908+
if (pushed_root)
909+
{
910+
char buf[128];
911+
int len;
912+
int pushed_id= 0;
913+
914+
for (JOIN_TAB* prev= join->join_tab; prev <= tab; prev++)
915+
{
916+
const TABLE* prev_root= prev->table->file->root_of_pushed_join();
917+
if (prev_root == prev->table)
918+
{
919+
pushed_id++;
920+
if (prev_root == pushed_root)
921+
break;
922+
}
923+
}
924+
if (pushed_root == table)
925+
{
926+
uint pushed_count= tab->table->file->number_of_pushed_joins();
927+
len= my_snprintf(buf, sizeof(buf)-1,
928+
"Parent of %d pushed join@%d",
929+
pushed_count, pushed_id);
930+
}
931+
else
932+
{
933+
len= my_snprintf(buf, sizeof(buf)-1,
934+
"Child of '%s' in pushed join@%d",
935+
tab->table->file->parent_of_pushed_join()->alias,
936+
pushed_id);
937+
}
938+
939+
{
940+
StringBuffer<128> buff(cs);
941+
buff.append(buf,len);
942+
if (push_extra(ET_PUSHED_JOIN, buff))
943+
return true;
944+
}
945+
}
946+
907947
switch (quick_type) {
908948
case QUICK_SELECT_I::QS_TYPE_ROR_UNION:
909949
case QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT:

sql/opt_explain_format.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ enum Extra_tag
9898
ET_CONST_ROW_NOT_FOUND,
9999
ET_UNIQUE_ROW_NOT_FOUND,
100100
ET_IMPOSSIBLE_ON_CONDITION,
101+
ET_PUSHED_JOIN,
101102
//------------------------------------
102103
ET_total
103104
};

sql/opt_explain_json.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ static const char *json_extra_tags[ET_total]=
5353
"const_row_not_found", // ET_CONST_ROW_NOT_FOUND
5454
"unique_row_not_found", // ET_UNIQUE_ROW_NOT_FOUND
5555
"impossible_on_condition", // ET_IMPOSSIBLE_ON_CONDITION
56+
"pushed_join" // ET_PUSHED_JOIN
5657
};
5758

5859

sql/opt_explain_traditional.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ static const char *traditional_extra_tags[ET_total]=
5252
"const row not found", // ET_CONST_ROW_NOT_FOUND
5353
"unique row not found", // ET_UNIQUE_ROW_NOT_FOUND
5454
"Impossible ON condition" // ET_IMPOSSIBLE_ON_CONDITION
55+
"" // ET_PUSHED_JOIN
5556
};
5657

5758

@@ -202,6 +203,7 @@ bool Explain_format_traditional::flush_entry()
202203
break;
203204
}
204205
if (e->tag != ET_FIRST_MATCH && // for backward compatibility
206+
e->tag != ET_PUSHED_JOIN &&
205207
buff.append(" "))
206208
return true;
207209
if (brackets && buff.append("("))

0 commit comments

Comments
 (0)