Skip to content

Commit ca4687c

Browse files
authored
feat: allow left table column prefix in JOIN
1 parent 179b690 commit ca4687c

22 files changed

Lines changed: 142 additions & 50 deletions

File tree

.translation-cache/Searching/Joining.md.json

Lines changed: 15 additions & 3 deletions
Large diffs are not rendered by default.

manual/chinese/Searching/Joining.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -996,9 +996,11 @@ POST /search
996996

997997
在 Manticore Search 中使用 JOIN 时,请记住以下几点:
998998

999-
1. **字段选择**:在 JOIN 中选择两个表的字段时,不要为左表的字段添加前缀,但需要为右表的字段添加前缀。例如:
999+
1. **字段选择**:在 JOIN 中从两个表选择字段时,右表的字段需以表名作为前缀。左表的字段可以使用或不使用表名前缀。例如:
10001000
```sql
10011001
SELECT field_name, right_table.field_name FROM ...
1002+
-- or with left table prefix:
1003+
SELECT left_table.field_name, right_table.field_name FROM ...
10021004
```
10031005

10041006
2. **JOIN 条件**:始终在 JOIN 条件中明确指定表名:

manual/english/Searching/Joining.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -996,9 +996,11 @@ Distributed tables consisting only of local tables are supported on both the lef
996996

997997
When using JOINs in Manticore Search, keep the following points in mind:
998998

999-
1. **Field selection**: When selecting fields from two tables in a JOIN, do not prefix fields from the left table, but do prefix fields from the right table. For example:
999+
1. **Field selection**: When selecting fields from two tables in a JOIN, prefix fields from the right table with the table name. Left table fields can be used with or without the table prefix. For example:
10001000
```sql
10011001
SELECT field_name, right_table.field_name FROM ...
1002+
-- or with left table prefix:
1003+
SELECT left_table.field_name, right_table.field_name FROM ...
10021004
```
10031005

10041006
2. **JOIN conditions**: Always explicitly specify the table names in your JOIN conditions:

manual/russian/Searching/Joining.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -996,9 +996,11 @@ POST /search
996996

997997
При использовании JOIN в Manticore Search учитывайте следующие моменты:
998998

999-
1. **Выбор полей**: При выборе полей из двух таблиц в JOIN не используйте префикс для полей из левой таблицы, но используйте префикс для полей из правой таблицы. Например:
999+
1. **Выбор полей**: При выборе полей из двух таблиц в JOIN добавляйте префикс имени таблицы к полям из правой таблицы. Поля левой таблицы можно использовать как с префиксом таблицы, так и без него. Например:
10001000
```sql
10011001
SELECT field_name, right_table.field_name FROM ...
1002+
-- or with left table prefix:
1003+
SELECT left_table.field_name, right_table.field_name FROM ...
10021004
```
10031005

10041006
2. **Условия JOIN**: Всегда явно указывайте имена таблиц в ваших условиях JOIN:

src/gtests/gtests_functions.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2115,7 +2115,7 @@ TEST ( functions, histogram_expression )
21152115

21162116
CSphString sError;
21172117
ExprParseArgs_t tExprArgs;
2118-
ISphExprRefPtr_c pExpr ( sphExprParse ( "histogram(price*100, {hist_interval=1})", tSchema, nullptr, sError, tExprArgs ) );
2118+
ISphExprRefPtr_c pExpr ( sphExprParse ( "histogram(price*100, {hist_interval=1})", tSchema, sError, tExprArgs ) );
21192119
ASSERT_TRUE ( pExpr.Ptr () ) << sError.cstr();
21202120

21212121
sphSetRowAttr ( pRow, tSchema.GetAttr(0).m_tLocator, sphF2DW ( 0.5f ) );

src/gtests/gtests_text.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,7 @@ TEST ( Text, expression_parser )
419419
{
420420
CSphString sError;
421421
ExprParseArgs_t tExprArgs;
422-
ISphExprRefPtr_c pExpr ( sphExprParse ( dTest.m_sExpr, tSchema, nullptr, sError, tExprArgs ) );
422+
ISphExprRefPtr_c pExpr ( sphExprParse ( dTest.m_sExpr, tSchema, sError, tExprArgs ) );
423423
ASSERT_TRUE ( pExpr.Ptr () ) << "parsing " << dTest.m_sExpr << ":" << sError.cstr ();
424424
ASSERT_FLOAT_EQ ( dTest.m_fValue, pExpr->Eval ( tMatch ) );
425425
}
@@ -511,7 +511,7 @@ TEST ( Text, expression_parser_many )
511511
{
512512
CSphString sError;
513513
ExprParseArgs_t tExprArgs;
514-
ISphExprRefPtr_c pExpr ( sphExprParse ( sTest.cstr (), tSchema, nullptr, sError, tExprArgs ) );
514+
ISphExprRefPtr_c pExpr ( sphExprParse ( sTest.cstr (), tSchema, sError, tExprArgs ) );
515515
ASSERT_TRUE ( pExpr.Ptr () ) << sError.cstr () << ": " << sTest.cstr();
516516
}
517517

src/joinsorter.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1686,12 +1686,11 @@ bool JoinSorter_c::ValidateLeftTableNotPrefixedInFilters ( CSphString & sError )
16861686
sLeftPrefix.SetSprintf ( "%s.", sLeftTableName.cstr() );
16871687
ARRAY_FOREACH ( i, m_tQuery.m_dFilters )
16881688
{
1689-
const auto & tFilter = m_tQuery.m_dFilters[i];
1689+
auto & tFilter = m_tQuery.m_dFilters[i];
16901690
if ( tFilter.m_sAttrName.Begins ( sLeftPrefix.cstr() ) )
16911691
{
1692-
CSphString sAttrName = tFilter.m_sAttrName.SubString ( sLeftPrefix.Length(), tFilter.m_sAttrName.Length() - sLeftPrefix.Length() );
1693-
sError.SetSprintf ( "table %s: unknown column: %s (do not prefix left table attributes in JOIN queries, use '%s' instead of '%s')", sLeftTableName.cstr(), sAttrName.cstr(), sAttrName.cstr(), tFilter.m_sAttrName.cstr() );
1694-
return false;
1692+
// Allow left table prefix: strip it so the rest of the pipeline sees bare attribute names
1693+
tFilter.m_sAttrName = tFilter.m_sAttrName.SubString ( sLeftPrefix.Length(), tFilter.m_sAttrName.Length() - sLeftPrefix.Length() );
16951694
}
16961695
}
16971696

@@ -1716,6 +1715,7 @@ bool JoinSorter_c::SetupRightFilters ( CSphString & sError )
17161715
tCtx.m_pIndexSchema = &m_pIndex->GetMatchSchema();
17171716
tCtx.m_bScan = m_tQuery.m_sQuery.IsEmpty();
17181717
tCtx.m_sJoinIdx = GetJoinedIndexName();
1718+
tCtx.m_sJoinIdxLeft = m_pIndex->GetName();
17191719
tCtx.m_eJoinType = m_tQuery.m_eJoinType;
17201720
if ( !sphCreateFilters ( tCtx, sError, sError ) )
17211721
{

src/queuecreator.cpp

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -403,8 +403,13 @@ void QueueCreator_c::CreateGrouperByAttr ( ESphAttr eType, const CSphColumnInfo
403403
{
404404
ExprParseArgs_t tExprArgs;
405405
tExprArgs.m_eCollation = m_tQuery.m_eCollation;
406+
if ( m_tSettings.m_pJoinArgs )
407+
{
408+
tExprArgs.m_pJoinIdx = &m_tSettings.m_pJoinArgs->m_sIndex2;
409+
tExprArgs.m_pJoinIdxLeft = &m_tSettings.m_pJoinArgs->m_sIndex1;
410+
}
406411

407-
ISphExprRefPtr_c pExpr { sphExprParse ( m_tQuery.m_sGroupBy.cstr(), tSchema, m_tSettings.m_pJoinArgs ? &(m_tSettings.m_pJoinArgs->m_sIndex2) : nullptr, m_sError, tExprArgs ) };
412+
ISphExprRefPtr_c pExpr { sphExprParse ( m_tQuery.m_sGroupBy.cstr(), tSchema, m_sError, tExprArgs ) };
408413
m_tGroupSorterSettings.m_pGrouper = CreateGrouperJsonField ( tLoc, pExpr );
409414
m_tGroupSorterSettings.m_bJson = true;
410415
}
@@ -586,7 +591,12 @@ bool QueueCreator_c::SetupGroupbySettings ( bool bHasImplicitGrouping )
586591
if ( !sJsonExpr.IsEmpty() )
587592
{
588593
ExprParseArgs_t tExprArgs;
589-
dJsonKeys.Add ( sphExprParse ( sJsonExpr.cstr(), tSchema, m_tSettings.m_pJoinArgs ? &(m_tSettings.m_pJoinArgs->m_sIndex2) : nullptr, m_sError, tExprArgs ) );
594+
if ( m_tSettings.m_pJoinArgs )
595+
{
596+
tExprArgs.m_pJoinIdx = &m_tSettings.m_pJoinArgs->m_sIndex2;
597+
tExprArgs.m_pJoinIdxLeft = &m_tSettings.m_pJoinArgs->m_sIndex1;
598+
}
599+
dJsonKeys.Add ( sphExprParse ( sJsonExpr.cstr(), tSchema, m_sError, tExprArgs ) );
590600
}
591601
else if ( tAttr.m_eAttrType==SPH_ATTR_JSON_FIELD )
592602
{
@@ -623,8 +633,13 @@ bool QueueCreator_c::SetupGroupbySettings ( bool bHasImplicitGrouping )
623633

624634
ExprParseArgs_t tExprArgs;
625635
tExprArgs.m_eCollation = m_tQuery.m_eCollation;
636+
if ( m_tSettings.m_pJoinArgs )
637+
{
638+
tExprArgs.m_pJoinIdx = &m_tSettings.m_pJoinArgs->m_sIndex2;
639+
tExprArgs.m_pJoinIdxLeft = &m_tSettings.m_pJoinArgs->m_sIndex1;
640+
}
626641

627-
ISphExprRefPtr_c pExpr { sphExprParse ( m_tQuery.m_sGroupBy.cstr(), tSchema, m_tSettings.m_pJoinArgs ? &(m_tSettings.m_pJoinArgs->m_sIndex2) : nullptr, m_sError, tExprArgs ) };
642+
ISphExprRefPtr_c pExpr { sphExprParse ( m_tQuery.m_sGroupBy.cstr(), tSchema, m_sError, tExprArgs ) };
628643
m_tGroupSorterSettings.m_pGrouper = CreateGrouperJsonField ( tSchema.GetAttr(iAttr).m_tLocator, pExpr );
629644
m_tGroupSorterSettings.m_bJson = true;
630645
m_bJoinedGroupSort |= IsJoinAttr(sJsonColumn);
@@ -1124,10 +1139,22 @@ bool QueueCreator_c::ParseQueryItem ( const CSphQueryItem & tItem )
11241139
{
11251140
CSphString sExpr2;
11261141
sExpr2.SetSprintf ( "TO_STRING(%s)", sExpr.cstr() );
1127-
tExprCol.m_pExpr = sphExprParse ( sExpr2.cstr(), *m_pSorterSchema, m_tSettings.m_pJoinArgs ? &(m_tSettings.m_pJoinArgs->m_sIndex2) : nullptr, m_sError, tExprParseArgs );
1142+
if ( m_tSettings.m_pJoinArgs )
1143+
{
1144+
tExprParseArgs.m_pJoinIdx = &m_tSettings.m_pJoinArgs->m_sIndex2;
1145+
tExprParseArgs.m_pJoinIdxLeft = &m_tSettings.m_pJoinArgs->m_sIndex1;
1146+
}
1147+
tExprCol.m_pExpr = sphExprParse ( sExpr2.cstr(), *m_pSorterSchema, m_sError, tExprParseArgs );
11281148
}
11291149
else
1130-
tExprCol.m_pExpr = sphExprParse ( sExpr.cstr(), *m_pSorterSchema, m_tSettings.m_pJoinArgs ? &(m_tSettings.m_pJoinArgs->m_sIndex2) : nullptr, m_sError, tExprParseArgs );
1150+
{
1151+
if ( m_tSettings.m_pJoinArgs )
1152+
{
1153+
tExprParseArgs.m_pJoinIdx = &m_tSettings.m_pJoinArgs->m_sIndex2;
1154+
tExprParseArgs.m_pJoinIdxLeft = &m_tSettings.m_pJoinArgs->m_sIndex1;
1155+
}
1156+
tExprCol.m_pExpr = sphExprParse ( sExpr.cstr(), *m_pSorterSchema, m_sError, tExprParseArgs );
1157+
}
11311158

11321159
m_uPackedFactorFlags |= uQueryPackedFactorFlags;
11331160
m_bZonespanlist |= bHasZonespanlist;
@@ -1264,8 +1291,13 @@ bool QueueCreator_c::MaybeAddExprColumn ()
12641291
tExprArgs.m_pProfiler = m_tSettings.m_pProfiler;
12651292
tExprArgs.m_eCollation = m_tQuery.m_eCollation;
12661293
tExprArgs.m_pZonespanlist = &bHasZonespanlist;
1294+
if ( m_tSettings.m_pJoinArgs )
1295+
{
1296+
tExprArgs.m_pJoinIdx = &m_tSettings.m_pJoinArgs->m_sIndex2;
1297+
tExprArgs.m_pJoinIdxLeft = &m_tSettings.m_pJoinArgs->m_sIndex1;
1298+
}
12671299

1268-
tCol.m_pExpr = sphExprParse ( m_tQuery.m_sSortBy.cstr (), *m_pSorterSchema, m_tSettings.m_pJoinArgs ? &(m_tSettings.m_pJoinArgs->m_sIndex2) : nullptr, m_sError, tExprArgs );
1300+
tCol.m_pExpr = sphExprParse ( m_tQuery.m_sSortBy.cstr (), *m_pSorterSchema, m_sError, tExprArgs );
12691301
if ( !tCol.m_pExpr )
12701302
return false;
12711303

@@ -1460,7 +1492,12 @@ void QueueCreator_c::ReplaceJsonGroupbyWithStrings ( CSphString & sJsonGroupBy )
14601492
if ( !sJsonExpr.IsEmpty() )
14611493
{
14621494
ExprParseArgs_t tExprArgs;
1463-
dJsonKeys.Add ( sphExprParse ( sJsonExpr.cstr(), *m_pSorterSchema, m_tSettings.m_pJoinArgs ? &(m_tSettings.m_pJoinArgs->m_sIndex2) : nullptr, m_sError, tExprArgs ) );
1495+
if ( m_tSettings.m_pJoinArgs )
1496+
{
1497+
tExprArgs.m_pJoinIdx = &m_tSettings.m_pJoinArgs->m_sIndex2;
1498+
tExprArgs.m_pJoinIdxLeft = &m_tSettings.m_pJoinArgs->m_sIndex1;
1499+
}
1500+
dJsonKeys.Add ( sphExprParse ( sJsonExpr.cstr(), *m_pSorterSchema, m_sError, tExprArgs ) );
14641501
}
14651502
else
14661503
dJsonKeys.Add(nullptr);
@@ -1655,8 +1692,13 @@ bool QueueCreator_c::ParseJoinExpr ( CSphColumnInfo & tExprCol, const CSphString
16551692
tExprParseArgs.m_pAttrType = &tExprCol.m_eAttrType;
16561693
tExprParseArgs.m_pProfiler = m_tSettings.m_pProfiler;
16571694
tExprParseArgs.m_eCollation = m_tQuery.m_eCollation;
1695+
if ( m_tSettings.m_pJoinArgs )
1696+
{
1697+
tExprParseArgs.m_pJoinIdx = &m_tSettings.m_pJoinArgs->m_sIndex2;
1698+
tExprParseArgs.m_pJoinIdxLeft = &m_tSettings.m_pJoinArgs->m_sIndex1;
1699+
}
16581700
tExprCol.m_eStage = SPH_EVAL_PRESORT;
1659-
tExprCol.m_pExpr = sphExprParse ( sExpr.cstr(), *m_pSorterSchema, m_tSettings.m_pJoinArgs ? &(m_tSettings.m_pJoinArgs->m_sIndex2) : nullptr, m_sError, tExprParseArgs );
1701+
tExprCol.m_pExpr = sphExprParse ( sExpr.cstr(), *m_pSorterSchema, m_sError, tExprParseArgs );
16601702
tExprCol.m_uAttrFlags |= CSphColumnInfo::ATTR_JOINED;
16611703
return !!tExprCol.m_pExpr;
16621704
}

src/schematransform.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ void TransformedSchemaBuilder_c::ReplaceColumnarAttrWithExpression ( CSphColumnI
173173
// parse expression as if it is not columnar
174174
CSphString sError;
175175
ExprParseArgs_t tExprArgs;
176-
tAttr.m_pExpr = sphExprParse ( tAttr.m_sName.cstr(), m_tNewSchema, nullptr, sError, tExprArgs );
176+
tAttr.m_pExpr = sphExprParse ( tAttr.m_sName.cstr(), m_tNewSchema, sError, tExprArgs );
177177
assert ( tAttr.m_pExpr );
178178

179179
// now remove it from schema (it will be added later with the supplied expression)
@@ -310,7 +310,7 @@ void MatchesToNewSchema_c::SetupAction ( const CSphColumnInfo & tOld, const CSph
310310
{
311311
CSphString sError;
312312
ExprParseArgs_t tExprArgs;
313-
tAction.m_pExpr = sphExprParse ( tOld.m_sName.cstr(), *pOldSchema, nullptr, sError, tExprArgs );
313+
tAction.m_pExpr = sphExprParse ( tOld.m_sName.cstr(), *pOldSchema, sError, tExprArgs );
314314
assert ( tAction.m_pExpr );
315315

316316
switch ( tNew.m_eAttrType )

src/searchd.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7712,7 +7712,7 @@ static void ReturnZeroCount ( const CSphSchema & tSchema, const CSphBitvec & tAt
77127712
CSphString sError;
77137713
ExprParseArgs_t tExprArgs;
77147714
tExprArgs.m_pAttrType = &eAttrType;
7715-
ISphExprRefPtr_c pExpr { sphExprParse ( tCol.m_sName.cstr(), tSchema, nullptr, sError, tExprArgs )};
7715+
ISphExprRefPtr_c pExpr { sphExprParse ( tCol.m_sName.cstr(), tSchema, sError, tExprArgs )};
77167716

77177717
if ( !pExpr || !pExpr->IsConst() )
77187718
eAttrType = SPH_ATTR_NONE;
@@ -9503,7 +9503,7 @@ void HandleMysqlSelectColumns ( RowBuffer_i & tOut, const SqlStmt_t & tStmt, Cli
95039503
ESphAttr eAttrType;
95049504
ExprParseArgs_t tExprArgs;
95059505
tExprArgs.m_pAttrType = &eAttrType;
9506-
ISphExprRefPtr_c pExpr { sphExprParse ( sVar.cstr(), tSchema, nullptr, sError, tExprArgs ) };
9506+
ISphExprRefPtr_c pExpr { sphExprParse ( sVar.cstr(), tSchema, sError, tExprArgs ) };
95079507
if ( pExpr )
95089508
{
95099509
dColumns.Add ( { eAttrType, ESphAttr2MysqlColumn ( eAttrType ), pExpr, -1, tItem.m_sAlias.cstr() } );

0 commit comments

Comments
 (0)