Skip to content

Commit 2beedfc

Browse files
author
victor
committed
add: parse pivot for tsql and plsql
1 parent a0731d9 commit 2beedfc

File tree

12 files changed

+186
-87
lines changed

12 files changed

+186
-87
lines changed

DatabaseConverter/DatabaseConverter.Core/Converter/DbConverter.cs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -78,17 +78,20 @@ private async Task InternalConvert(SchemaInfo schemaInfo = null)
7878
{
7979
DbInterpreter sourceInterpreter = this.Source.DbInterpreter;
8080
sourceInterpreter.Option.BulkCopy = this.Option.BulkCopy;
81-
sourceInterpreter.Subscribe(this.observer);
82-
83-
if (sourceInterpreter.DatabaseType == DatabaseType.Oracle)
84-
{
85-
sourceInterpreter.Option.TreatBytesAsNullForExecuting = true;
86-
}
81+
sourceInterpreter.Subscribe(this.observer);
8782

8883
sourceInterpreter.Option.GetTableAllObjects = false;
8984
sourceInterpreter.Option.ThrowExceptionWhenErrorOccurs = false;
9085
this.Target.DbInterpreter.Option.ThrowExceptionWhenErrorOccurs = false;
9186

87+
if(string.IsNullOrEmpty(this.Target.DbOwner))
88+
{
89+
if(this.Target.DbInterpreter.DatabaseType == DatabaseType.Oracle)
90+
{
91+
this.Target.DbOwner = (this.Target.DbInterpreter as OracleInterpreter).GetDbOwner();
92+
}
93+
}
94+
9295
DatabaseObjectType databaseObjectType = (DatabaseObjectType)Enum.GetValues(typeof(DatabaseObjectType)).Cast<int>().Sum();
9396

9497
if (schemaInfo != null && !this.Source.DbInterpreter.Option.GetTableAllObjects

DatabaseConverter/DatabaseConverter.Core/ScriptToken/ScriptTokenProcessor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public class ScriptTokenProcessor
1313
{
1414
private ColumnTranslator columnTranslator;
1515
private Regex identifierRegex = new Regex($@"([`""\[][ _0-9a-zA-Z]+[`""\]])");
16-
private Regex nameRegex = new Regex(@"\b(^[_a-zA-Z][ _0-9a-zA-Z]+$)\b");
16+
private Regex nameRegex = new Regex(@"\b(^[_a-zA-Z][ _0-9a-zA-Z]*$)\b");
1717
private bool removeDbOwner => this.TargetInterpreter.DatabaseType != DatabaseType.SqlServer;
1818
private bool nameWithQuotation = SettingManager.Setting.DbObjectNameMode == DbObjectNameMode.WithQuotation;
1919
public CommonScript Script { get; set; }

DatabaseConverter/DatabaseConverter.Core/TranslateEngine.cs

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -118,20 +118,17 @@ private void ScriptTranslated(DatabaseType dbType, DatabaseObject dbObject, Tran
118118

119119
private void TranslateOwner()
120120
{
121-
if (!string.IsNullOrEmpty(this.targetDbOwner))
122-
{
123-
this.SetDatabaseObjectsOwner(this.targetSchemaInfo.UserDefinedTypes);
124-
this.SetDatabaseObjectsOwner(this.targetSchemaInfo.Functions);
125-
this.SetDatabaseObjectsOwner(this.targetSchemaInfo.Tables);
126-
this.SetDatabaseObjectsOwner(this.targetSchemaInfo.TableColumns);
127-
this.SetDatabaseObjectsOwner(this.targetSchemaInfo.TablePrimaryKeys);
128-
this.SetDatabaseObjectsOwner(this.targetSchemaInfo.TableForeignKeys);
129-
this.SetDatabaseObjectsOwner(this.targetSchemaInfo.TableIndexes);
130-
this.SetDatabaseObjectsOwner(this.targetSchemaInfo.TableTriggers);
131-
this.SetDatabaseObjectsOwner(this.targetSchemaInfo.TableConstraints);
132-
this.SetDatabaseObjectsOwner(this.targetSchemaInfo.Views);
133-
this.SetDatabaseObjectsOwner(this.targetSchemaInfo.Procedures);
134-
}
121+
this.SetDatabaseObjectsOwner(this.targetSchemaInfo.UserDefinedTypes);
122+
this.SetDatabaseObjectsOwner(this.targetSchemaInfo.Functions);
123+
this.SetDatabaseObjectsOwner(this.targetSchemaInfo.Tables);
124+
this.SetDatabaseObjectsOwner(this.targetSchemaInfo.TableColumns);
125+
this.SetDatabaseObjectsOwner(this.targetSchemaInfo.TablePrimaryKeys);
126+
this.SetDatabaseObjectsOwner(this.targetSchemaInfo.TableForeignKeys);
127+
this.SetDatabaseObjectsOwner(this.targetSchemaInfo.TableIndexes);
128+
this.SetDatabaseObjectsOwner(this.targetSchemaInfo.TableTriggers);
129+
this.SetDatabaseObjectsOwner(this.targetSchemaInfo.TableConstraints);
130+
this.SetDatabaseObjectsOwner(this.targetSchemaInfo.Views);
131+
this.SetDatabaseObjectsOwner(this.targetSchemaInfo.Procedures);
135132
}
136133

137134
private void SetDatabaseObjectsOwner<T>(List<T> dbObjects) where T : DatabaseObject

DatabaseConverter/SqlAnalyser.Core/Model/Statement/SelectStatement.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ public class JoinItem
4444
public JoinType Type { get; set; }
4545
public TableName TableName { get; set; }
4646
public TokenInfo Condition { get; set; }
47+
public TokenInfo Special { get; set; }
48+
public TokenInfo Alias { get; set; }
4749
}
4850

4951
public enum JoinType

DatabaseConverter/SqlAnalyser.Core/Model/Token/TokenInfo.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ public class TokenInfo
99
public virtual TokenType Type { get; set; }
1010
public string Symbol { get; set; }
1111
public int? StartIndex { get; set; }
12-
public int? StopIndex { get; set; }
12+
public int? StopIndex { get; set; }
1313

1414
public int Length => this.StartIndex.HasValue && this.StopIndex.HasValue ? (this.StopIndex - this.StartIndex + 1).Value : 0;
1515

16-
public List<TokenInfo> Tokens { get; set; } = new List<TokenInfo>();
16+
public List<TokenInfo> Tokens { get; set; } = new List<TokenInfo>();
1717

1818
public TokenInfo(string symbol)
1919
{
@@ -81,6 +81,8 @@ public enum TokenType
8181
Option = 10,
8282
JoinOn = 11,
8383
CursorName = 12,
84-
Alias = 13
84+
Alias = 13,
85+
Pivot = 14,
86+
UnPivot = 15
8587
}
8688
}

DatabaseConverter/SqlAnalyser.Core/RuleAnalyser/PlSqlRuleAnalyser.cs

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -935,6 +935,8 @@ public List<FromItem> ParseFormClause(From_clauseContext node)
935935
fromItem.TableName = this.ParseTableName(table);
936936

937937
Join_clauseContext[] joins = table.join_clause();
938+
Pivot_clauseContext pivot = table.pivot_clause();
939+
Unpivot_clauseContext unpivot = table.unpivot_clause();
938940

939941
if (joins != null && joins.Length > 0)
940942
{
@@ -966,6 +968,18 @@ public List<FromItem> ParseFormClause(From_clauseContext node)
966968
fromItem.JoinItems.Add(joinItem);
967969
}
968970
}
971+
else if (pivot != null)
972+
{
973+
JoinItem joinItem = new JoinItem() { Type = JoinType.PIVOT };
974+
joinItem.Special = this.ParseToken(pivot, TokenType.Pivot);
975+
fromItem.JoinItems.Add(joinItem);
976+
}
977+
else if (unpivot != null)
978+
{
979+
JoinItem joinItem = new JoinItem() { Type = JoinType.UNPIVOT };
980+
joinItem.Special = this.ParseToken(unpivot, TokenType.UnPivot);
981+
fromItem.JoinItems.Add(joinItem);
982+
}
969983

970984
fromItems.Add(fromItem);
971985
}
@@ -1251,7 +1265,7 @@ public override ColumnName ParseColumnName(ParserRuleContext node, bool strict =
12511265
if (ids != null && ids.Length > 0)
12521266
{
12531267
columnName = new ColumnName(ids[0]);
1254-
}
1268+
}
12551269
}
12561270
else if (node is Select_list_elementsContext ele)
12571271
{
@@ -1359,7 +1373,7 @@ public override List<TokenInfo> GetColumnNameTokens(IParseTree node)
13591373
}
13601374

13611375
return tokens;
1362-
}
1376+
}
13631377

13641378
private bool IsChildOfType<T>(RuleContext node)
13651379
{
@@ -1387,14 +1401,14 @@ public override List<TokenInfo> GetRoutineNameTokens(IParseTree node)
13871401
if (node is General_element_partContext gep && (node as General_element_partContext).children.Any(item => item is Function_argumentContext))
13881402
{
13891403
routineName = gep.id_expression().LastOrDefault();
1390-
}
1404+
}
13911405

13921406
if (routineName != null)
13931407
{
13941408
tokens.Add(new TokenInfo(routineName) { Type = TokenType.RoutineName });
13951409
}
13961410

13971411
return tokens;
1398-
}
1412+
}
13991413
}
14001414
}

DatabaseConverter/SqlAnalyser.Core/RuleAnalyser/TSqlRuleAnalyser.cs

Lines changed: 48 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -468,39 +468,39 @@ public List<FromItem> ParseTableScources(Table_sourcesContext node)
468468
else
469469
{
470470
fromItem.TableName = this.ParseTableName(fromTable);
471+
}
471472

472-
Join_partContext[] joins = tsi.join_part();
473+
Join_partContext[] joins = tsi.join_part();
473474

474-
if (joins != null && joins.Length > 0)
475+
if (joins != null && joins.Length > 0)
476+
{
477+
foreach (Join_partContext join in joins)
475478
{
476-
foreach (Join_partContext join in joins)
477-
{
478-
List<JoinItem> joinItems = this.ParseJoin(join);
479+
List<JoinItem> joinItems = this.ParseJoin(join);
479480

480-
if (joinItems.Count > 1)
481+
if (joinItems.Count > 1)
482+
{
483+
for (int i = joinItems.Count - 1; i > 0; i--)
481484
{
482-
for (int i = joinItems.Count - 1; i > 0; i--)
483-
{
484-
JoinItem currentJoinItem = joinItems[i];
485+
JoinItem currentJoinItem = joinItems[i];
485486

486-
if (i - 1 > 0)
487-
{
488-
JoinItem previousJoinItem = joinItems[i - 1];
487+
if (i - 1 > 0)
488+
{
489+
JoinItem previousJoinItem = joinItems[i - 1];
489490

490-
TableName previousJoinTableName = new TableName(previousJoinItem.TableName.Symbol);
491-
ObjectHelper.CopyProperties(previousJoinItem.TableName, previousJoinTableName);
491+
TableName previousJoinTableName = new TableName(previousJoinItem.TableName.Symbol);
492+
ObjectHelper.CopyProperties(previousJoinItem.TableName, previousJoinTableName);
492493

493-
TableName currentJoinTableName = new TableName(currentJoinItem.TableName.Symbol);
494-
ObjectHelper.CopyProperties(currentJoinItem.TableName, currentJoinTableName);
494+
TableName currentJoinTableName = new TableName(currentJoinItem.TableName.Symbol);
495+
ObjectHelper.CopyProperties(currentJoinItem.TableName, currentJoinTableName);
495496

496-
joinItems[i - 1].TableName = currentJoinTableName;
497-
joinItems[i].TableName = previousJoinTableName;
498-
}
497+
joinItems[i - 1].TableName = currentJoinTableName;
498+
joinItems[i].TableName = previousJoinTableName;
499499
}
500500
}
501-
502-
fromItem.JoinItems.AddRange(joinItems);
503501
}
502+
503+
fromItem.JoinItems.AddRange(joinItems);
504504
}
505505
}
506506

@@ -540,19 +540,34 @@ public List<JoinItem> ParseJoin(Join_partContext node)
540540
case TSqlParser.CROSS:
541541
joinItem.Type = JoinType.CROSS;
542542
break;
543+
case TSqlParser.PIVOT:
544+
joinItem.Type = JoinType.PIVOT;
545+
break;
546+
case TSqlParser.UNPIVOT:
547+
joinItem.Type = JoinType.UNPIVOT;
548+
break;
543549
}
544550
}
545551
}
546552

547553
Table_sourceContext tableSoure = node.table_source();
554+
Pivot_clauseContext pivot = node.pivot_clause();
555+
Unpivot_clauseContext unpivot = node.unpivot_clause();
548556

549-
joinItem.TableName = this.ParseTableName(tableSoure);
550-
joinItem.Condition = this.ParseCondition(node.search_condition());
557+
As_table_aliasContext alias = node.as_table_alias();
558+
559+
if (alias != null)
560+
{
561+
joinItem.Alias = new TokenInfo(alias.table_alias());
562+
}
551563

552564
joinItems.Add(joinItem);
553565

554566
if (tableSoure != null)
555567
{
568+
joinItem.TableName = this.ParseTableName(tableSoure);
569+
joinItem.Condition = this.ParseCondition(node.search_condition());
570+
556571
Table_source_item_joinedContext join = tableSoure.table_source_item_joined();
557572

558573
if (join != null)
@@ -564,6 +579,14 @@ public List<JoinItem> ParseJoin(Join_partContext node)
564579
joinItems.AddRange(childJoinItems);
565580
}
566581
}
582+
else if (pivot != null)
583+
{
584+
joinItem.Special = this.ParseToken(pivot, TokenType.Pivot);
585+
}
586+
else if (unpivot != null)
587+
{
588+
joinItem.Special = this.ParseToken(unpivot, TokenType.UnPivot);
589+
}
567590

568591
return joinItems;
569592
}
@@ -1315,12 +1338,12 @@ public override TableName ParseTableName(ParserRuleContext node, bool strict = f
13151338
{
13161339
tableName = new TableName(tn);
13171340
}
1318-
else if(node is Full_table_nameContext fullName)
1341+
else if (node is Full_table_nameContext fullName)
13191342
{
13201343
tableName = new TableName(fullName);
13211344

13221345
tableName.Name = new TokenInfo(fullName.table);
1323-
1346+
13241347
}
13251348
else if (node is Table_source_itemContext tsi)
13261349
{

DatabaseConverter/SqlAnalyser.Core/StatementScriptBuilder/StatementScriptBuilder.cs

Lines changed: 61 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -106,17 +106,12 @@ protected void BuildSelectStatementFromItems(SelectStatement selectStatement)
106106

107107
this.Append($"{fromItem.TableName}{(hasJoins ? Environment.NewLine : "")}", false);
108108

109-
if (fromItem.JoinItems.Count > 0)
110-
{
111-
foreach (JoinItem joinItem in fromItem.JoinItems)
112-
{
113-
string condition = joinItem.Condition == null ? "" : $" ON {joinItem.Condition}";
109+
bool hasSubSelect = false;
114110

115-
this.AppendLine($"{joinItem.Type} JOIN {joinItem.TableName}{condition}");
116-
}
117-
}
118-
else if (fromItem.SubSelectStatement != null)
111+
if (fromItem.SubSelectStatement != null)
119112
{
113+
hasSubSelect = true;
114+
120115
this.AppendLine("");
121116
this.AppendLine("(");
122117
this.BuildSelectStatement(fromItem.SubSelectStatement, false);
@@ -126,7 +121,63 @@ protected void BuildSelectStatementFromItems(SelectStatement selectStatement)
126121
{
127122
this.Append($"{fromItem.Alias}", false);
128123
}
129-
}
124+
}
125+
126+
if (fromItem.JoinItems.Count > 0)
127+
{
128+
if (hasSubSelect)
129+
{
130+
this.AppendLine("");
131+
}
132+
133+
foreach (JoinItem joinItem in fromItem.JoinItems)
134+
{
135+
if (joinItem.Special != null)
136+
{
137+
if (joinItem.Type == JoinType.PIVOT || joinItem.Type == JoinType.UNPIVOT)
138+
{
139+
string symbol = joinItem.Special.Symbol;
140+
141+
if (symbol.Contains(joinItem.Type.ToString()))
142+
{
143+
this.AppendLine(symbol);
144+
}
145+
else
146+
{
147+
bool hasBracket = joinItem.Special.Symbol.StartsWith("(") && joinItem.Special.Symbol.EndsWith(")");
148+
this.AppendLine($"{joinItem.Type}");
149+
150+
if (!hasBracket)
151+
{
152+
this.AppendLine("(");
153+
}
154+
155+
this.AppendLine(symbol);
156+
157+
if (!hasBracket)
158+
{
159+
this.AppendLine(")");
160+
}
161+
}
162+
163+
if (joinItem.Alias != null)
164+
{
165+
this.AppendLine(joinItem.Alias.Symbol);
166+
}
167+
else
168+
{
169+
this.AppendLine(joinItem.Type.ToString() + "_");
170+
}
171+
}
172+
}
173+
else
174+
{
175+
string condition = joinItem.Condition == null ? "" : $" ON {joinItem.Condition}";
176+
177+
this.AppendLine($"{joinItem.Type} JOIN {joinItem.TableName}{condition}");
178+
}
179+
}
180+
}
130181

131182
i++;
132183
}

0 commit comments

Comments
 (0)