Skip to content

Commit de44d58

Browse files
committed
Implement non-key columns extraction
1 parent a2e9c4f commit de44d58

File tree

1 file changed

+128
-1
lines changed
  • Orm/Xtensive.Orm.PostgreSql/Sql.Drivers.PostgreSql/v12_0

1 file changed

+128
-1
lines changed

Orm/Xtensive.Orm.PostgreSql/Sql.Drivers.PostgreSql/v12_0/Extractor.cs

Lines changed: 128 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
// This code is distributed under MIT license terms.
33
// See the License.txt file in the project root for more information.
44

5+
using System;
6+
using System.Data.Common;
7+
using System.Linq;
8+
using System.Text.RegularExpressions;
59
using Xtensive.Sql.Model;
610

711
namespace Xtensive.Sql.Drivers.PostgreSql.v12_0
@@ -13,7 +17,10 @@ protected override void BuildPgCatalogSchema(Schema schema)
1317
{
1418
base.BuildPgCatalogSchema(schema);
1519
var defaultValuesTable = schema.Tables["pg_attrdef"];
16-
defaultValuesTable.CreateColumn("adbin", new SqlValueType(SqlType.Binary));
20+
_ = defaultValuesTable.CreateColumn("adbin", new SqlValueType(SqlType.Binary));
21+
22+
var indexesTable = schema.Tables["pg_index"];
23+
CreateInt2Column(indexesTable, "indnkeyatts");
1724
}
1825

1926
/// <inheritdoc/>
@@ -77,6 +84,126 @@ protected override ISqlCompileUnit BuildExtractTableAndDomainConstraintsQuery(Ex
7784
return select;
7885
}
7986

87+
/// <inheritdoc />
88+
protected override ISqlCompileUnit BuildExtractTableIndexesQuery(ExtractionContext context)
89+
{
90+
var tableMap = context.TableMap;
91+
var tableSpacesTable = PgTablespace;
92+
var relationsTable = PgClass;
93+
var indexTable = PgIndex;
94+
var dependencyTable = PgDepend;
95+
96+
//subselect that index was not created automatically
97+
var subSelect = SqlDml.Select(dependencyTable);
98+
subSelect.Where = dependencyTable["classid"] == PgClassOid &&
99+
dependencyTable["objid"] == indexTable["indexrelid"] &&
100+
dependencyTable["deptype"] == 'i';
101+
subSelect.Columns.Add(dependencyTable[0]);
102+
103+
//not automatically created indexes of our tables
104+
var select = SqlDml.Select(indexTable
105+
.InnerJoin(relationsTable, relationsTable["oid"] == indexTable["indexrelid"])
106+
.LeftOuterJoin(tableSpacesTable, tableSpacesTable["oid"] == relationsTable["reltablespace"]));
107+
select.Where = SqlDml.In(indexTable["indrelid"], CreateOidRow(tableMap.Keys)) && !SqlDml.Exists(subSelect);
108+
select.Columns.Add(indexTable["indrelid"]);
109+
select.Columns.Add(indexTable["indexrelid"]);
110+
select.Columns.Add(relationsTable["relname"]);
111+
select.Columns.Add(indexTable["indisunique"]);
112+
select.Columns.Add(indexTable["indisclustered"]);
113+
select.Columns.Add(indexTable["indkey"]);
114+
select.Columns.Add(tableSpacesTable["spcname"]);
115+
select.Columns.Add(indexTable["indnatts"]);
116+
select.Columns.Add(indexTable["indnkeyatts"]);
117+
select.Columns.Add(SqlDml.FunctionCall("pg_get_expr", indexTable["indexprs"], indexTable["indrelid"], true),
118+
"indexprstext");
119+
select.Columns.Add(SqlDml.FunctionCall("pg_get_expr", indexTable["indpred"], indexTable["indrelid"], true),
120+
"indpredtext");
121+
select.Columns.Add(SqlDml.FunctionCall("pg_get_indexdef", indexTable["indexrelid"]), "inddef");
122+
AddSpecialIndexQueryColumns(select, tableSpacesTable, relationsTable, indexTable, dependencyTable);
123+
return select;
124+
}
125+
126+
/// <inheritdoc />
127+
protected override int ReadTableIndexData(DbDataReader dataReader, ExtractionContext context)
128+
{
129+
var tableMap = context.TableMap;
130+
var tableColumns = context.TableColumnMap;
131+
132+
var maxColumnNumber = 0;
133+
var tableIdentifier = Convert.ToInt64(dataReader["indrelid"]);
134+
var indexIdentifier = Convert.ToInt64(dataReader["indexrelid"]);
135+
var indexName = dataReader["relname"].ToString();
136+
var isUnique = dataReader.GetBoolean(dataReader.GetOrdinal("indisunique"));
137+
var indexKey = (short[]) dataReader["indkey"];
138+
139+
var tablespaceName = (dataReader["spcname"] != DBNull.Value) ? dataReader["spcname"].ToString() : null;
140+
var filterExpression = (dataReader["indpredtext"] != DBNull.Value)
141+
? dataReader["indpredtext"].ToString()
142+
: string.Empty;
143+
144+
var table = tableMap[tableIdentifier];
145+
146+
var fullTextRegex =
147+
@"(?<=CREATE INDEX \S+ ON \S+ USING (?:gist|gin)(?:\s|\S)*)to_tsvector\('(\w+)'::regconfig, \(*(?:(?:\s|\)|\(|\|)*(?:\(""(\S+)""\)|'\s')::text)+\)";
148+
var indexScript = dataReader["inddef"].ToString();
149+
var matches = Regex.Matches(indexScript, fullTextRegex, RegexOptions.Compiled);
150+
if (matches.Count > 0) {
151+
// Fulltext index
152+
var fullTextIndex = table.CreateFullTextIndex(indexName);
153+
foreach (Match match in matches) {
154+
var columnConfigurationName = match.Groups[1].Value;
155+
foreach (Capture capture in match.Groups[2].Captures) {
156+
var columnName = capture.Value;
157+
var fullTextColumn = fullTextIndex.Columns[columnName]
158+
?? fullTextIndex.CreateIndexColumn(table.Columns.Single(column => column.Name == columnName));
159+
if (fullTextColumn.Languages[columnConfigurationName] == null)
160+
fullTextColumn.Languages.Add(new Language(columnConfigurationName));
161+
}
162+
}
163+
}
164+
else {
165+
//Regular index
166+
var index = table.CreateIndex(indexName);
167+
index.IsBitmap = false;
168+
index.IsUnique = isUnique;
169+
index.Filegroup = tablespaceName;
170+
if (!string.IsNullOrEmpty(filterExpression))
171+
index.Where = SqlDml.Native(filterExpression);
172+
173+
// Expression-based index
174+
var some = dataReader["indexprstext"];
175+
if (some != DBNull.Value) {
176+
context.ExpressionIndexMap[indexIdentifier] = new ExpressionIndexInfo(index, indexKey);
177+
maxColumnNumber = dataReader.GetInt16(dataReader.GetOrdinal("indnatts"));
178+
}
179+
else {
180+
var keyColumnNumber = dataReader.GetInt16(dataReader.GetOrdinal("indnkeyatts"));
181+
for (int j = 0; j < indexKey.Length; j++) {
182+
if (j < keyColumnNumber) {
183+
int colIndex = indexKey[j];
184+
if (colIndex > 0) {
185+
_ = index.CreateIndexColumn(tableColumns[tableIdentifier][colIndex], true);
186+
}
187+
else {
188+
//column index is 0
189+
//this means that this index column is an expression
190+
//which is not possible with SqlDom tables
191+
}
192+
}
193+
else {
194+
int colIndex = indexKey[j];
195+
index.NonkeyColumns.Add(tableColumns[tableIdentifier][colIndex]);
196+
}
197+
}
198+
}
199+
200+
ReadSpecialIndexProperties(dataReader, index);
201+
}
202+
203+
return maxColumnNumber;
204+
}
205+
206+
80207
// Constructors
81208

82209
public Extractor(SqlDriver driver)

0 commit comments

Comments
 (0)