Skip to content

Commit 91eb884

Browse files
authored
Merge 62f13ad into a88d157
2 parents a88d157 + 62f13ad commit 91eb884

35 files changed

Lines changed: 1202 additions & 356 deletions
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
---------------
2+
Partial indices
3+
---------------
4+
5+
Function:
6+
Allow to index only a subset of table rows defined by the search condition specified during index creation.
7+
8+
Author:
9+
Dmitry Yemanov <[email protected]>
10+
11+
Syntax rules:
12+
CREATE [UNIQUE] [{ASC[ENDING] | DESC[ENDING]}] INDEX <index_name> ON <table_name>
13+
{ (<column_list>) | COMPUTED [BY] ( <value_expression> ) }
14+
WHERE <search_condition>
15+
16+
Scope:
17+
DSQL (DDL)
18+
19+
Example(s):
20+
1. CREATE INDEX IT1_COL ON T1 (COL) WHERE COL < 100;
21+
SELECT * FROM T1 WHERE COL < 100;
22+
-- PLAN (T1 INDEX (IT1_COL))
23+
2. CREATE INDEX IT1_COL2 ON T1 (COL) WHERE COL IS NOT NULL;
24+
SELECT * FROM T1 WHERE COL > 100;
25+
-- PLAN (T1 INDEX IT1_COL2)
26+
3. CREATE INDEX IT1_COL3 ON T1 (COL) WHERE COL = 1 OR COL = 2;
27+
SELECT * FROM T1 WHERE COL = 2;
28+
-- PLAN (T1 INDEX IT1_COL3)
29+
30+
Note(s):
31+
1. A partial index definition may include the UNIQUE specification. In this case,
32+
every key in the index is required to be unique. This allows to enforce uniqueness
33+
across some subset of table rows.
34+
2. Partial index is usable only in the following cases:
35+
a) WHERE condition includes exactly the same boolean expression as the one
36+
defined for the index;
37+
b) Search condition defined for the index contains ORed boolean expressions
38+
and one of them is explicitly included in the WHERE condition;
39+
c) Search condition defined for the index specifies IS NOT NULL and the
40+
WHERE condition includes an expression on the same field that is known to
41+
ignore NULLs.
42+

src/burp/OdsDetection.epp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ namespace
5454
{"RDB$ROLES", "RDB$DESCRIPTION", DB_VERSION_DDL11}, // FB2
5555
{"RDB$RELATIONS", "RDB$RELATION_TYPE", DB_VERSION_DDL11_1}, // FB2.1
5656
{"RDB$PROCEDURE_PARAMETERS", "RDB$FIELD_NAME", DB_VERSION_DDL11_2}, // FB2.5
57+
{"RDB$INDICES", "RDB$CONDITION_BLR", DB_VERSION_DDL13_1}, // FB5
5758
{0, 0, 0}
5859
};
5960

src/burp/OdsDetection.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,12 @@ DDL12_0 = 120 // rdb$engine_name and rdb$entrypoint in rdb$triggers
5454
// Type of rdb$triggers.rdb$trigger_type changed from SMALLINT to BIGINT
5555
DDL13_0 = 130 // Table rdb$publications
5656
// Table rdb$publication_tables
57+
DDL13_1 = 131 // rdb$condition_blr / rdb$condition_source in rdb$indices
5758
5859
ASF: Engine that works with ODS11.1 and newer supports access to non-existent system fields.
5960
Reads return NULL and writes do nothing.
6061
*/
6162

62-
//const int DB_VERSION_DDL4 = 40; // ods4 db
63-
//const int DB_VERSION_DDL5 = 50; // ods5 db
6463
const int DB_VERSION_DDL8 = 80; // ods8 db, IB4
6564
const int DB_VERSION_DDL9 = 90; // ods9 db, IB5
6665
const int DB_VERSION_DDL10 = 100; // ods10 db, IB6, FB1, FB1.5
@@ -69,6 +68,7 @@ const int DB_VERSION_DDL11_1 = 111; // ods11.1 db, FB2.1
6968
const int DB_VERSION_DDL11_2 = 112; // ods11.2 db, FB2.5
7069
const int DB_VERSION_DDL12 = 120; // ods12.0 db, FB3.0
7170
const int DB_VERSION_DDL13 = 130; // ods13.0 db, FB4.0
71+
const int DB_VERSION_DDL13_1 = 131; // ods13.1 db, FB5.0
7272

7373
const int DB_VERSION_OLDEST_SUPPORTED = DB_VERSION_DDL8; // IB4.0 is ods8
7474

src/burp/backup.epp

Lines changed: 130 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1617,68 +1617,152 @@ void put_index( burp_rel* relation)
16171617
// requests--this requires more code but it is well worth it
16181618
// for the performance benefits, especially remotely--deej
16191619

1620-
FOR (REQUEST_HANDLE tdgbl->handles_put_index_req_handle1)
1621-
X IN RDB$INDICES WITH
1622-
X.RDB$RELATION_NAME EQ relation->rel_name
1620+
if (tdgbl->runtimeODS >= DB_VERSION_DDL13_1)
1621+
{
1622+
FOR (REQUEST_HANDLE tdgbl->handles_put_index_req_handle1)
1623+
X IN RDB$INDICES WITH
1624+
X.RDB$RELATION_NAME EQ relation->rel_name
1625+
1626+
count = 0;
1627+
FOR (REQUEST_HANDLE tdgbl->handles_put_index_req_handle2)
1628+
I_S IN RDB$INDEX_SEGMENTS CROSS
1629+
RFR IN RDB$RELATION_FIELDS WITH
1630+
I_S.RDB$FIELD_NAME = RFR.RDB$FIELD_NAME AND
1631+
I_S.RDB$INDEX_NAME = X.RDB$INDEX_NAME AND
1632+
RFR.RDB$RELATION_NAME = relation->rel_name
1633+
1634+
count++;
1635+
1636+
END_FOR;
1637+
ON_ERROR
1638+
general_on_error();
1639+
END_ERROR;
16231640

1624-
count = 0;
1625-
FOR (REQUEST_HANDLE tdgbl->handles_put_index_req_handle2)
1626-
I_S IN RDB$INDEX_SEGMENTS CROSS
1627-
RFR IN RDB$RELATION_FIELDS WITH
1628-
I_S.RDB$FIELD_NAME = RFR.RDB$FIELD_NAME AND
1629-
I_S.RDB$INDEX_NAME = X.RDB$INDEX_NAME AND
1630-
RFR.RDB$RELATION_NAME = relation->rel_name
1641+
if (count != (ULONG) X.RDB$SEGMENT_COUNT)
1642+
{
1643+
BURP_print(true, 180, SafeArg() << X.RDB$INDEX_NAME << count << X.RDB$SEGMENT_COUNT);
1644+
continue;
1645+
}
1646+
1647+
put(tdgbl, rec_index);
1648+
const ULONG l = PUT_TEXT (att_index_name, X.RDB$INDEX_NAME);
1649+
MISC_terminate (X.RDB$INDEX_NAME, temp, l, sizeof(temp));
1650+
BURP_verbose (151, temp);
1651+
// msg 151 writing index %s
1652+
put_int32 (att_segment_count, X.RDB$SEGMENT_COUNT);
1653+
put_int32 (att_index_inactive, X.RDB$INDEX_INACTIVE);
1654+
put_int32 (att_index_unique_flag, X.RDB$UNIQUE_FLAG);
1655+
1656+
FOR (REQUEST_HANDLE tdgbl->handles_put_index_req_handle5)
1657+
Y IN RDB$INDEX_SEGMENTS WITH
1658+
Y.RDB$INDEX_NAME EQ X.RDB$INDEX_NAME
1659+
SORTED BY Y.RDB$FIELD_POSITION
16311660

1632-
count++;
1661+
PUT_TEXT (att_index_field_name, Y.RDB$FIELD_NAME);
1662+
1663+
END_FOR;
1664+
ON_ERROR
1665+
general_on_error();
1666+
END_ERROR;
1667+
1668+
put_source_blob (att_index_description2, att_index_description, X.RDB$DESCRIPTION);
1669+
put_int32 (att_index_type, X.RDB$INDEX_TYPE);
1670+
1671+
if (!X.RDB$EXPRESSION_SOURCE.NULL)
1672+
{
1673+
put_source_blob(att_index_expression_source, att_index_expression_source,
1674+
X.RDB$EXPRESSION_SOURCE);
1675+
}
1676+
if (!X.RDB$EXPRESSION_BLR.NULL)
1677+
put_blr_blob(att_index_expression_blr, X.RDB$EXPRESSION_BLR);
1678+
1679+
if (!X.RDB$FOREIGN_KEY.NULL)
1680+
PUT_TEXT (att_index_foreign_key, X.RDB$FOREIGN_KEY);
1681+
1682+
if (!X.RDB$CONDITION_SOURCE.NULL)
1683+
{
1684+
put_source_blob(att_index_condition_source, att_index_condition_source,
1685+
X.RDB$CONDITION_SOURCE);
1686+
}
1687+
if (!X.RDB$CONDITION_BLR.NULL)
1688+
put_blr_blob(att_index_condition_blr, X.RDB$CONDITION_BLR);
1689+
1690+
put(tdgbl, att_end);
16331691

16341692
END_FOR;
16351693
ON_ERROR
16361694
general_on_error();
16371695
END_ERROR;
1696+
}
1697+
else
1698+
{
1699+
FOR (REQUEST_HANDLE tdgbl->handles_put_index_req_handle1)
1700+
X IN RDB$INDICES WITH
1701+
X.RDB$RELATION_NAME EQ relation->rel_name
16381702

1639-
if (count != (ULONG) X.RDB$SEGMENT_COUNT)
1640-
{
1641-
BURP_print(true, 180, SafeArg() << X.RDB$INDEX_NAME << count << X.RDB$SEGMENT_COUNT);
1642-
continue;
1643-
}
1703+
count = 0;
1704+
FOR (REQUEST_HANDLE tdgbl->handles_put_index_req_handle2)
1705+
I_S IN RDB$INDEX_SEGMENTS CROSS
1706+
RFR IN RDB$RELATION_FIELDS WITH
1707+
I_S.RDB$FIELD_NAME = RFR.RDB$FIELD_NAME AND
1708+
I_S.RDB$INDEX_NAME = X.RDB$INDEX_NAME AND
1709+
RFR.RDB$RELATION_NAME = relation->rel_name
1710+
1711+
count++;
1712+
1713+
END_FOR;
1714+
ON_ERROR
1715+
general_on_error();
1716+
END_ERROR;
1717+
1718+
if (count != (ULONG) X.RDB$SEGMENT_COUNT)
1719+
{
1720+
BURP_print(true, 180, SafeArg() << X.RDB$INDEX_NAME << count << X.RDB$SEGMENT_COUNT);
1721+
continue;
1722+
}
1723+
1724+
put(tdgbl, rec_index);
1725+
const ULONG l = PUT_TEXT (att_index_name, X.RDB$INDEX_NAME);
1726+
MISC_terminate (X.RDB$INDEX_NAME, temp, l, sizeof(temp));
1727+
BURP_verbose (151, temp);
1728+
// msg 151 writing index %s
1729+
put_int32 (att_segment_count, X.RDB$SEGMENT_COUNT);
1730+
put_int32 (att_index_inactive, X.RDB$INDEX_INACTIVE);
1731+
put_int32 (att_index_unique_flag, X.RDB$UNIQUE_FLAG);
1732+
1733+
FOR (REQUEST_HANDLE tdgbl->handles_put_index_req_handle5)
1734+
Y IN RDB$INDEX_SEGMENTS WITH
1735+
Y.RDB$INDEX_NAME EQ X.RDB$INDEX_NAME
1736+
SORTED BY Y.RDB$FIELD_POSITION
1737+
1738+
PUT_TEXT (att_index_field_name, Y.RDB$FIELD_NAME);
1739+
1740+
END_FOR;
1741+
ON_ERROR
1742+
general_on_error();
1743+
END_ERROR;
16441744

1645-
put(tdgbl, rec_index);
1646-
const ULONG l = PUT_TEXT (att_index_name, X.RDB$INDEX_NAME);
1647-
MISC_terminate (X.RDB$INDEX_NAME, temp, l, sizeof(temp));
1648-
BURP_verbose (151, temp);
1649-
// msg 151 writing index %s
1650-
put_int32 (att_segment_count, X.RDB$SEGMENT_COUNT);
1651-
put_int32 (att_index_inactive, X.RDB$INDEX_INACTIVE);
1652-
put_int32 (att_index_unique_flag, X.RDB$UNIQUE_FLAG);
1745+
put_source_blob (att_index_description2, att_index_description, X.RDB$DESCRIPTION);
1746+
put_int32 (att_index_type, X.RDB$INDEX_TYPE);
1747+
1748+
if (!X.RDB$EXPRESSION_SOURCE.NULL)
1749+
{
1750+
put_source_blob(att_index_expression_source, att_index_expression_source,
1751+
X.RDB$EXPRESSION_SOURCE);
1752+
}
1753+
if (!X.RDB$EXPRESSION_BLR.NULL)
1754+
put_blr_blob(att_index_expression_blr, X.RDB$EXPRESSION_BLR);
16531755

1654-
FOR (REQUEST_HANDLE tdgbl->handles_put_index_req_handle5)
1655-
Y IN RDB$INDEX_SEGMENTS WITH
1656-
Y.RDB$INDEX_NAME EQ X.RDB$INDEX_NAME
1657-
SORTED BY Y.RDB$FIELD_POSITION
1756+
if (!X.RDB$FOREIGN_KEY.NULL)
1757+
PUT_TEXT (att_index_foreign_key, X.RDB$FOREIGN_KEY);
16581758

1659-
PUT_TEXT (att_index_field_name, Y.RDB$FIELD_NAME);
1759+
put(tdgbl, att_end);
16601760

16611761
END_FOR;
16621762
ON_ERROR
16631763
general_on_error();
16641764
END_ERROR;
1665-
1666-
put_source_blob (att_index_description2, att_index_description, X.RDB$DESCRIPTION);
1667-
put_int32 (att_index_type, X.RDB$INDEX_TYPE);
1668-
1669-
if (!X.RDB$EXPRESSION_SOURCE.NULL)
1670-
put_source_blob (att_index_expression_source, att_index_expression_source,
1671-
X.RDB$EXPRESSION_SOURCE);
1672-
if (!X.RDB$EXPRESSION_BLR.NULL)
1673-
put_blr_blob (att_index_expression_blr, X.RDB$EXPRESSION_BLR);
1674-
if (!X.RDB$FOREIGN_KEY.NULL)
1675-
PUT_TEXT (att_index_foreign_key, X.RDB$FOREIGN_KEY);
1676-
put(tdgbl, att_end);
1677-
1678-
END_FOR;
1679-
ON_ERROR
1680-
general_on_error();
1681-
END_ERROR;
1765+
}
16821766
}
16831767

16841768

src/burp/burp.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,8 @@ enum att_type {
351351
att_index_description2,
352352
att_index_expression_source,
353353
att_index_expression_blr,
354+
att_index_condition_source,
355+
att_index_condition_blr,
354356

355357
// Data record
356358

src/burp/restore.epp

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6472,6 +6472,9 @@ bool get_index(BurpGlobals* tdgbl, const burp_rel* relation)
64726472

64736473
SSHORT count = 0, segments = 0;
64746474

6475+
ISC_QUAD conditionSrc, conditionBlr;
6476+
bool hasConditionSrc = false, hasConditionBlr = false;
6477+
64756478
STORE (REQUEST_HANDLE tdgbl->handles_get_index_req_handle1)
64766479
X IN RDB$INDICES
64776480
strcpy (X.RDB$RELATION_NAME, relation->rel_name);
@@ -6568,6 +6571,36 @@ bool get_index(BurpGlobals* tdgbl, const burp_rel* relation)
65686571
get_blr_blob (tdgbl, X.RDB$EXPRESSION_BLR, false);
65696572
break;
65706573

6574+
case att_index_condition_source:
6575+
if (tdgbl->RESTORE_format >= 11)
6576+
{
6577+
if (tdgbl->runtimeODS >= DB_VERSION_DDL13_1)
6578+
{
6579+
get_source_blob(tdgbl, conditionSrc, false);
6580+
hasConditionSrc = true;
6581+
}
6582+
else
6583+
eat_blob(tdgbl);
6584+
}
6585+
else
6586+
bad_attribute(scan_next_attr, attribute, 93);
6587+
break;
6588+
6589+
case att_index_condition_blr:
6590+
if (tdgbl->RESTORE_format >= 11)
6591+
{
6592+
if (tdgbl->runtimeODS >= DB_VERSION_DDL13_1)
6593+
{
6594+
get_blr_blob(tdgbl, conditionBlr, false);
6595+
hasConditionBlr = true;
6596+
}
6597+
else
6598+
eat_blob(tdgbl);
6599+
}
6600+
else
6601+
bad_attribute(scan_next_attr, attribute, 93);
6602+
break;
6603+
65716604
case att_index_foreign_key:
65726605
foreign_index = true;
65736606
// Defer foreign key index activation
@@ -6616,6 +6649,40 @@ bool get_index(BurpGlobals* tdgbl, const burp_rel* relation)
66166649
general_on_error ();
66176650
END_ERROR;
66186651

6652+
if (hasConditionSrc || hasConditionBlr)
6653+
{
6654+
fb_assert(tdgbl->runtimeODS >= DB_VERSION_DDL13_1);
6655+
6656+
Firebird::IRequest* req_handle = nullptr;
6657+
6658+
FOR (REQUEST_HANDLE req_handle)
6659+
IDX IN RDB$INDICES WITH IDX.RDB$INDEX_NAME = index_name
6660+
{
6661+
MODIFY IDX USING
6662+
if (hasConditionSrc)
6663+
{
6664+
IDX.RDB$CONDITION_SOURCE.NULL = FALSE;
6665+
IDX.RDB$CONDITION_SOURCE = conditionSrc;
6666+
}
6667+
6668+
if (hasConditionBlr)
6669+
{
6670+
IDX.RDB$CONDITION_BLR.NULL = FALSE;
6671+
IDX.RDB$CONDITION_BLR = conditionBlr;
6672+
}
6673+
END_MODIFY;
6674+
ON_ERROR
6675+
general_on_error();
6676+
END_ERROR;
6677+
}
6678+
END_FOR;
6679+
ON_ERROR
6680+
general_on_error();
6681+
END_ERROR;
6682+
6683+
MISC_release_request_silent(req_handle);
6684+
}
6685+
66196686
return true;
66206687
}
66216688

0 commit comments

Comments
 (0)