I downloaded Oracle Developer Tools for Visual studio and explored the libraries (.dll). I need to parse the PLSQL scripts to get the SQL Statements in that and using the visitors to visit the nodes. I found Oracle.VsDevTools.SqlAndPlsqlParser library and explored further and tried to parse the PLSQL scripts. Please refer the below code.
string plSQLScript="CREATE TABLE Student(Age int);";
List<LexerToken> tokens= LexerToken.Parse(plSQLScript, false, true);
But the above code gives tokens only, I need PLSQL parser.
Is there any possible way to parser the PLSQL scripts and get the sql statements. Also I need to explicit visit the sql statements like CreateTableVisitor, CreateProcedureVisitor, etc.
I already created the parser for TSQL files by exploring Microsoft SQL library called Microsoft.SqlServer.TransactSql.ScriptDom and using the below mentioned code for parsing.
TSql100Parser parser = new TSql100Parser(true);
IList<ParseError> error;
using (TextReader tr = new StreamReader(filePath))
{
TSqlFragment fragment = parser.Parse(tr, out error);
tr.Close();
}
And using TSqlFragmentVisitor to visit the sql statements. Please refer the below mentioned code.
public override void ExplicitVisit(CreateTableStatement node)
{
//----Coding----
}
I want the same for PLSQL by using Oracle.VsDevTools.SqlAndPlsqlParser library.
Please let me know if there any possibility for this.
Thanks,Sivaprakash.
With some reflection used it's possible. The parser, nodes and grammar classes are internal. I made small example for you:
private static Assembly odacDevAssembly = Assembly.Load("Oracle.VsDevTools.14.0");
private static Type parseNodeType = odacDevAssembly.GetType("Oracle.VsDevTools.SqlAndPlsqlParser.ParseNode");
void Main()
{
var parserType = odacDevAssembly.GetType("Oracle.VsDevTools.SqlAndPlsqlParser.OracleSqlEarley");
var parser = Activator.CreateInstance(parserType);
const string sqlScriptText = "DECLARE x NUMBER; BEGIN SELECT DUMMY INTO :DUMMY FROM DUAL T1; x := 1; SELECT DUMMY INTO :DUMMY FROM DUAL T2; x := 2; INSERT INTO T3 (C) VALUES (1); x := 3; END;";
var tokens = LexerToken.Parse(sqlScriptText);
var parserGrammar = parserType.GetProperty("EarleyGrammar").GetValue(parser);
var allSymbols = (string[])parserGrammar.GetType().GetField("m_vAllSymbols", BindingFlags.Public | BindingFlags.Instance).GetValue(parserGrammar);
var sqlStatementIndex = -1;
for (var i = 0; i < allSymbols.Length; i++)
{
if (allSymbols[i] == "unlabeled_nonblock_stmt")
{
sqlStatementIndex = i;
break;
}
}
var parseTree = parserType.GetMethod("Parse").Invoke(parser, new object[] { sqlScriptText, tokens });
//parseTree.GetType().GetMethod("PrintTree", new Type[] { parserGrammar.GetType() }).Invoke(parseTree, new object[] { parserGrammar });
var commandNodes = GetDescendants(parseTree).Where(d => GetPayloadIn(d) == sqlStatementIndex);
foreach (var commandNode in commandNodes)
{
var commandText = GetCommandText(commandNode, sqlScriptText, tokens);
Console.WriteLine(commandText);
}
}
private static string GetCommandText(object parseNode, string sqlScriptText, List<LexerToken> tokens)
{
var from = (int)parseNodeType.GetProperty("From").GetValue(parseNode);
var to = (int)parseNodeType.GetProperty("To").GetValue(parseNode) - 1;
var begin = tokens[from].m_vBegin;
return sqlScriptText.Substring(begin, tokens[to].m_vEnd - begin);
}
private static IEnumerable<object> GetDescendants(object parseNode)
{
yield return parseNode;
foreach (var child in GetChildren(parseNode))
foreach (var descendant in GetDescendants(child))
yield return descendant;
}
private static int GetPayloadIn(object parseNode)
{
return (int)parseNodeType.GetProperty("PayloadIn").GetValue(parseNode);
}
private static IEnumerable<object> GetChildren(object parseNode)
{
return (IEnumerable<object>)parseNodeType.GetMethod("Children").Invoke(parseNode, null);
}
UPDATE:
I'm not exactly sure what do you want to achieve but I hope it will be at least somehow helpful:
private static Assembly odacDevAssembly = Assembly.Load("Oracle.VsDevTools.14.0");
private static Type parseNodeType = odacDevAssembly.GetType("Oracle.VsDevTools.SqlAndPlsqlParser.ParseNode");
void Main()
{
var parserType = odacDevAssembly.GetType("Oracle.VsDevTools.SqlAndPlsqlParser.OracleSqlEarley");
var parser = Activator.CreateInstance(parserType);
const string sqlScriptText = "DECLARE x NUMBER; BEGIN SELECT DUMMY INTO :DUMMY FROM DUAL T1; x := 1; SELECT DUMMY INTO :DUMMY FROM DUAL T2; x := 2; INSERT INTO T3 (C) VALUES (1); x := 3; END;";
var tokens = LexerToken.Parse(sqlScriptText);
var parserGrammar = parserType.GetProperty("EarleyGrammar").GetValue(parser);
var allSymbols = (string[])parserGrammar.GetType().GetField("m_vAllSymbols", BindingFlags.Public | BindingFlags.Instance).GetValue(parserGrammar);
const int sqlStatementIndex = 4453; // unlabeled_nonblock_stmt
var parseTree = parserType.GetMethod("Parse").Invoke(parser, new object[] { sqlScriptText, tokens });
//parseTree.GetType().GetMethod("PrintTree", new Type[] { parserGrammar.GetType() }).Invoke(parseTree, new object[] { parserGrammar });
var commandNodes = GetDescendants(parseTree)
.Select(n => ParseNodeFactory.CreateNode(n, sqlScriptText, tokens))
.Where(n => n != null);
var visitor = new GrammarNodeVisitor();
foreach (var commandNode in commandNodes)
{
commandNode.Accept(visitor);
}
}
public static class ParseNodeFactory
{
private const int queryBlockIndex = 3849; // query_block
private const int insertIndex = 3136; // insert
public static IParseNode CreateNode(object parseNode, string sqlScriptText, List<LexerToken> tokens)
{
var symbolIndex = GetPayloadIn(parseNode);
var parseData = new ParseData { ParseNode = parseNode, SqlScriptText = sqlScriptText, Tokens = tokens };
switch (symbolIndex)
{
case queryBlockIndex:
return new QueryBlock { ParseData = parseData };
case insertIndex:
return new Insert { ParseData = parseData };
default:
return null;
}
}
}
public class GrammarNodeVisitor : IParseNodeVisitor
{
public void VisitQueryBlock(QueryBlock queryBlock)
{
Console.WriteLine($"Visited query block: {GetCommandText(queryBlock.ParseData.ParseNode, queryBlock.ParseData.SqlScriptText, queryBlock.ParseData.Tokens)}");
}
public void VisitInsert(Insert insert)
{
Console.WriteLine($"Visited insert command: {GetCommandText(insert.ParseData.ParseNode, insert.ParseData.SqlScriptText, insert.ParseData.Tokens)}");
}
}
public interface IParseNodeVisitor
{
void VisitQueryBlock(QueryBlock queryBlock);
void VisitInsert(Insert insert);
}
public interface IParseNode
{
ParseData ParseData { get; }
void Accept(IParseNodeVisitor visitor);
}
public class ParseData
{
public object ParseNode { get; set; }
public string SqlScriptText { get; set; }
public List<LexerToken> Tokens { get; set; }
}
public class QueryBlock : IParseNode
{
public ParseData ParseData { get; set; }
public void Accept(IParseNodeVisitor visitor)
{
visitor.VisitQueryBlock(this);
}
}
public class Insert : IParseNode
{
public ParseData ParseData { get; set; }
public void Accept(IParseNodeVisitor visitor)
{
visitor.VisitInsert(this);
}
}
private static string GetCommandText(object parseNode, string sqlScriptText, List<LexerToken> tokens)
{
var from = (int)parseNodeType.GetProperty("From").GetValue(parseNode);
var to = (int)parseNodeType.GetProperty("To").GetValue(parseNode) - 1;
var begin = tokens[from].m_vBegin;
return sqlScriptText.Substring(begin, tokens[to].m_vEnd - begin);
}
private static IEnumerable<object> GetDescendants(object parseNode)
{
yield return parseNode;
foreach (var child in GetChildren(parseNode))
foreach (var descendant in GetDescendants(child))
yield return descendant;
}
private static int GetPayloadIn(object parseNode)
{
return (int)parseNodeType.GetProperty("PayloadIn").GetValue(parseNode);
}
private static IEnumerable<object> GetChildren(object parseNode)
{
return (IEnumerable<object>)parseNodeType.GetMethod("Children").Invoke(parseNode, null);
}
Related
I'm not able to override GetChildrenCore correctly. I use this for a Canvas to get information about it's children (Line, Rectangle).
The output correctly indicates the first child but misses the second. Even though the Canvas already contains both.
Custom Canvas
Custom Line Childs of Canvas parent: 2
Instead it should be like this:
Custom Canvas
Custom Line Childs of Canvas parent: 2
Custom Rectangle Childs of Canvas parent: 2
App side side:
public class ElementAP : FrameworkElementAutomationPeer
{
private FrameworkElement Owner = null;
private Int32 Count = 0;
public ElementAP(FrameworkElement owner, Int32 count) : base (owner)
{
Owner = owner;
Count = count;
}
protected override AutomationControlType GetAutomationControlTypeCore()
{
return AutomationControlType.Custom;
}
protected override string GetClassNameCore()
{
return $"{Owner.GetType().Name} Childs of Canvas parent: {Count}";
}
}
public class CanvasAP : FrameworkElementAutomationPeer
{
public CanvasAP(Windows.UI.Xaml.Controls.Canvas owner) : base(owner)
{
}
protected override AutomationControlType GetAutomationControlTypeCore()
{
return AutomationControlType.Custom;
}
protected override string GetClassNameCore()
{
return "Canvas";
}
protected override IList<AutomationPeer> GetChildrenCore()
{
var owner = (Windows.UI.Xaml.Controls.Canvas)Owner;
var list = new List<AutomationPeer> ();
foreach (var child in owner.Children)
{
var peer = new ElementAP(child as FrameworkElement, owner.Children.Count);
list.Add(peer);
}
return list;
}
}
UI Testing side:
private static string WalkTree(UITestControl element, Int32 level = 0)
{
var children = element.GetChildren();
var str = "";
foreach (var c in children)
{
str += GetElementString(c, level);
str += WalkTree(c, level + 1);
}
return str;
}
private static string GetElementString(UITestControl element, Int32 level = 0)
{
var xaml = element as XamlControl;
var str = "";
for (var i = 0; i < level; i++)
str += " ";
str += $"{element.ControlType} {element.ClassName} {element.Name} {xaml?.AutomationId ?? ""}\n";
return str;
}
I finally found an answer. When using a cache for the children`s AutomationPeers it works perfectly.
public class ElementAP : FrameworkElementAutomationPeer
{
public UIElement Element { get { return Owner; } }
public ElementAP(FrameworkElement owner) : base(owner)
{
}
protected override AutomationControlType GetAutomationControlTypeCore()
{
return AutomationControlType.Custom;
}
protected override string GetClassNameCore()
{
return Owner.GetType().Name;
}
}
public class CanvasAP : FrameworkElementAutomationPeer
{
private List<ElementAP> _cachedAutomationPeers = new List<ElementAP>();
public CanvasAP(Windows.UI.Xaml.Controls.Canvas owner) : base(owner)
{
}
protected override AutomationControlType GetAutomationControlTypeCore()
{
return AutomationControlType.Custom;
}
protected override string GetClassNameCore()
{
return "Canvas";
}
protected override IList<AutomationPeer> GetChildrenCore()
{
var owner = (Windows.UI.Xaml.Controls.Canvas)Owner;
if (owner.Children.All(c => c is CanvasA))
return base.GetChildrenCore();
var list = new List<ElementAP>();
foreach (var child in owner.Children)
{
var peer = _cachedAutomationPeers.FirstOrDefault(p => p.Element == child) ?? new ElementAP(child as FrameworkElement);
list.Add(peer);
}
_cachedAutomationPeers = list;
return list.Cast<AutomationPeer>().ToList();
}
}
Problem is faced, when we come across huge data items, where while scrolling the cells become black and glitches are seen throughout....any suggestion are appreciated.
Why not try IncrementalLoading to load your data in gridview.
Tutorial
Incase the link stops working
Code Snippet
public interface IIncrementalSource<T>
{
Task<IEnumerable<T>> GetPagedItems(int pageIndex, int pageSize);
}
public class IncrementalLoadingCollection<T, I> : ObservableCollection<I>,
ISupportIncrementalLoading
where T : IIncrementalSource<I>, new()
{
private T source;
private int itemsPerPage;
private bool hasMoreItems;
private int currentPage;
public IncrementalLoadingCollection(int itemsPerPage = 20)
{
this.source = new T();
this.itemsPerPage = itemsPerPage;
this.hasMoreItems = true;
}
public bool HasMoreItems
{
get { return hasMoreItems; }
}
public IAsyncOperation<LoadMoreItemsResult> LoadMoreItemsAsync(uint count)
{
var dispatcher = Window.Current.Dispatcher;
return Task.Run<LoadMoreItemsResult>(
async () =>
{
uint resultCount = 0;
var result = await source.GetPagedItems(currentPage++, itemsPerPage);
if (result == null || result.Count() == 0)
{
hasMoreItems = false;
}
else
{
resultCount = (uint)result.Count();
await dispatcher.RunAsync(
CoreDispatcherPriority.Normal,
() =>
{
foreach (I item in result)
this.Add(item);
});
}
return new LoadMoreItemsResult() { Count = resultCount };
}).AsAsyncOperation<LoadMoreItemsResult>();
}
}
I have the following code, I can figure why its invalid argument:
AuditDAL ad = new AuditDAL();
var agencies = ad.SearchAgencies("Ak001", "");
string col = param.sColumns.Split(',')[param.iSortCol_0];
string orderby = col + " " + param.sSortDir_0;
// The best overloaded method match for 'AMS.Helper.PaginatedList.PaginatedList(System.Linq.IQueryable, int, int)' has some invalid arguments C:\NexGen\AMS\DEV\Source\AMS\Controllers\AuditController.cs
var qry = new PaginatedList<AuditAgency>(agencies, param.iDisplayStart, param.iDisplayLength);
PaginatedList Code:
namespace AMS.Helper
{
public class PaginatedList<T> : List<T> {
public int PageIndex { get; private set; }
public int PageSize { get; private set; }
public int TotalCount { get; private set; }
public int TotalPages { get; private set; }
public PaginatedList(IQueryable<T> source, int pageIndex, int pageSize) {
PageIndex = pageIndex;
PageSize = pageSize;
TotalCount = source.Count();
TotalPages = (int) Math.Ceiling(TotalCount / (double)PageSize);
this.AddRange(source.Skip(PageIndex * PageSize).Take(PageSize));
}
public bool HasPreviousPage {
get {
return (PageIndex > 0);
}
}
public bool HasNextPage {
get {
return (PageIndex+1 < TotalPages);
}
}
}
}
Search Agencies Code:
public IEnumerable<AuditAgency> SearchAgencies(string ori, string name)
{
List<AuditAgency> agencies = new List<AuditAgency>();
using (var conn = new SqlConnection(_connectionString))
{
var com = new SqlCommand();
com.Connection = conn;
com.CommandType = CommandType.StoredProcedure;
string term = "Ori";
if (!String.IsNullOrEmpty(ori))
{
term = "Ori";
com.Parameters.Add(new SqlParameter
{
ParameterName = "#ORI",
Value = ori
});
}
if (!String.IsNullOrEmpty(name))
{
term = "legal_name";
com.Parameters.Add(new SqlParameter
{
ParameterName = "#Name",
Value = name
});
}
com.CommandText = "Audit_Get_Agency_List";
var adapt = new SqlDataAdapter();
adapt.SelectCommand = com;
var dataset = new DataSet();
adapt.Fill(dataset);
agencies = (from c in dataset.Tables[0].AsEnumerable()
select new AuditAgency()
{
Agency_ID = Convert.ToInt32(c["Agency_Id"]),
Agency_Name = c["Agency_Name"].ToString(),
Agency_Ori = c["ORI"].ToString(),
COPSAuditNumber = c["COPSAuditNumber"].ToString(),
OIGAuditNumber = c["OIGAuditNumber"].ToString()
}).ToList<AuditAgency>();
return agencies;
}
}
The error should tell you where to start.
If you fire up the debugger, I think you'll find agencies is an IEnumberable, but not an IQueryable
correct it by changing the return type of SearchAgencies from IQueryable to IEnumerable
or alternatively, you can change the type of the PaginatedList to accept IEnumberables instead of IQueryables. this may be safer as IQueryable inherits from IEnumerable
(see
http://msdn.microsoft.com/en-us/library/system.linq.iqueryable.aspx or
Differences between IQueryable, List, IEnumerator?
for the difference between the two)
It's the first time that I use EmitMapper.
I have a list of object ex: Customer and I would like to map this list in a ienumerable of CustomerDTO how can I do that?
Tnx
It's straightforward if you have a list and want to convert it to list of DTOs:
var mapper = ObjectMapperManager.DefaultInstance.GetMapper<Customer, CustomerDTO>();
IEnumerable<CustomerDTO> dtos = listOfCustomer.Select(mapper.map);
The preblem is when the list is in another object, for example User and UserDTO:
class User {
public List<Customer> Customers { get; set; }
}
class UserDTO {
public IEnumerable<CustomerDTO> Customers { get; set; }
}
It seems that EmitMapper does not support conversion from List to Enumerable. A way to support it would be:
var customerMapper = ObjectMapperManager
.DefaultInstance.GetMapper<Customer, CustomerDTO>();
var mapper = ObjectMapperManager.DefaultInstance
.GetMapper<User, UserDTO>(
new DefaultMapConfig()
.ConvertUsing<List<Customer>, IEnumerable<CustomerDTO>>(
a => a.Select(customerMapper.Map))
);
This can be done creating a custom class, implementing the interface "ICustomConverterProvider" and adding a ConvertGeneric to the "DefaultMapConfig".
Looking on the source code of EmitMapper, i found a class named "ArraysConverterProvider", which is the default generic converter from ICollections to Arrays.
Adapting the code from this class to work with IEnumerable collections:
class GenericIEnumerableConverterProvider : ICustomConverterProvider
{
public CustomConverterDescriptor GetCustomConverterDescr(
Type from,
Type to,
MapConfigBaseImpl mappingConfig)
{
var tFromTypeArgs = DefaultCustomConverterProvider.GetGenericArguments(from);
var tToTypeArgs = DefaultCustomConverterProvider.GetGenericArguments(to);
if (tFromTypeArgs == null || tToTypeArgs == null || tFromTypeArgs.Length != 1 || tToTypeArgs.Length != 1)
{
return null;
}
var tFrom = tFromTypeArgs[0];
var tTo = tToTypeArgs[0];
if (tFrom == tTo && (tFrom.IsValueType || mappingConfig.GetRootMappingOperation(tFrom, tTo).ShallowCopy))
{
return new CustomConverterDescriptor
{
ConversionMethodName = "Convert",
ConverterImplementation = typeof(GenericIEnumerableConverter_OneTypes<>),
ConverterClassTypeArguments = new[] { tFrom }
};
}
return new CustomConverterDescriptor
{
ConversionMethodName = "Convert",
ConverterImplementation = typeof(GenericIEnumerableConverter_DifferentTypes<,>),
ConverterClassTypeArguments = new[] { tFrom, tTo }
};
}
}
class GenericIEnumerableConverter_DifferentTypes<TFrom, TTo> : ICustomConverter
{
private Func<TFrom, TTo> _converter;
public IEnumerable<TTo> Convert(IEnumerable<TFrom> from, object state)
{
if (from == null)
{
return null;
}
TTo[] result = new TTo[from.Count()];
int idx = 0;
foreach (var f in from)
{
result[idx++] = _converter(f);
}
return result;
}
public void Initialize(Type from, Type to, MapConfigBaseImpl mappingConfig)
{
var staticConverters = mappingConfig.GetStaticConvertersManager() ?? StaticConvertersManager.DefaultInstance;
var staticConverterMethod = staticConverters.GetStaticConverter(typeof(TFrom), typeof(TTo));
if (staticConverterMethod != null)
{
_converter = (Func<TFrom, TTo>)Delegate.CreateDelegate(
typeof(Func<TFrom, TTo>),
null,
staticConverterMethod
);
}
else
{
_subMapper = ObjectMapperManager.DefaultInstance.GetMapperImpl(typeof(TFrom), typeof(TTo), mappingConfig);
_converter = ConverterBySubmapper;
}
}
ObjectsMapperBaseImpl _subMapper;
private TTo ConverterBySubmapper(TFrom from)
{
return (TTo)_subMapper.Map(from);
}
}
class GenericIEnumerableConverter_OneTypes<T>
{
public IEnumerable<T> Convert(IEnumerable<T> from, object state)
{
if (from == null)
{
return null;
}
return from;
}
}
This code is just a copy with a minimum of adaptation as possible and can be applyed to objects with many levels of hierarchy.
You can use the above code with the following command:
new DefaultMapConfig().ConvertGeneric(
typeof(IEnumerable<>),
typeof(IEnumerable<>),
new GenericIEnumerableConverterProvider());
This saved my day and I hope to save yours too! hehehe
Is it possible to use SQL Server table-value functions by using the BLToolkit library?
I would like to use it within the Linq query, but I couldn't find anything regarding this on the library wiki.
Define your function in your data context class as the following:
[TableFunction(Name="GetParentByID")]
public Table<Parent> GetParentByID(int? id)
{
return GetTable<Parent>(this, (MethodInfo)MethodBase.GetCurrentMethod(), id);
}
Usage:
[Test]
public void Func2()
{
using (var db = new TestDbManager())
{
var q =
from c in db.Child
from p in db.GetParentByID(2)
select p;
q.ToList();
}
}
SQL:
SELECT
[t2].[ParentID],
[t2].[Value1]
FROM
[Child] [t1], [GetParentByID](2) [t2]
Also you can define it outside of the data context:
public class Functions
{
private readonly IDataContext _ctx;
public Functions(IDataContext ctx)
{
_ctx = ctx;
}
[TableFunction]
public Table<Parent> GetParentByID(int? id)
{
return _ctx.GetTable<Parent>(this, (MethodInfo)(MethodBase.GetCurrentMethod()), id);
}
[TableExpression("{0} {1} WITH (TABLOCK)")]
public Table<T> WithTabLock<T>()
where T : class
{
return _ctx.GetTable<T>(this, ((MethodInfo)(MethodBase.GetCurrentMethod())).MakeGenericMethod(typeof(T)));
}
}
[Test]
public void Func1()
{
using (var db = new TestDbManager())
{
var q =
from p in new Functions(db).GetParentByID(1)
select p;
q.ToList();
}
}
[Test]
public void WithTabLock()
{
using (var db = new TestDbManager())
{
var q =
from p in new Functions(db).WithTabLock<Parent>()
select p;
q.ToList();
}
}
SQL:
SELECT
[p].[ParentID],
[p].[Value1]
FROM
[GetParentByID](1) [p]
SELECT
[p].[ParentID],
[p].[Value1]
FROM
[Parent] [p] WITH (TABLOCK)