/// <summary> /// Constructor. /// </summary> public PLSQLSpecParsedProcedureCollection(PLSQLSpecParsed spec) { HasParseError = false; ParseErrorText = string.Empty; specParsed = spec; }
public static PLSQLSpecParsed ParseString(string stringToParse, string pathAndFileName) { PLSQLSpecParsed specFile = null; if (!string.IsNullOrEmpty(stringToParse)) { // Create the regular expression objects needed Regex reSpec = new Regex(PLSQLSpecParserRegEx.SPEC_PACKAGE_FETCH); Regex reProcCount = new Regex(PLSQLSpecParserRegEx.PROCEDURE_COUNT); Regex reProcFetch = new Regex(PLSQLSpecParserRegEx.PROCEDURE_FETCH); Regex reParamCount = new Regex(PLSQLSpecParserRegEx.PARAMETER_COUNT); Regex reParamFetch = new Regex(PLSQLSpecParserRegEx.PARAMETER_FETCH); // Fetch the spec file MatchCollection specFetchMatches = reSpec.Matches(stringToParse); // Check that we got one match if (specFetchMatches.Count == 1) { // Create spec object specFile = new PLSQLSpecParsed(); // Get the length of the read string. specFile.PackageLength = stringToParse.Length; // Get the hash of the read string. specFile.PackageHash = Hashing.Get(Hash.HashTypes.SHA1, stringToParse); // Get the filename that was read to parse specFile.FileNameParsed = pathAndFileName; // Get the only match Match specMatch = specFetchMatches[0]; // Fetch the packagename if (!string.IsNullOrEmpty(specMatch.Groups[PLSQLSpecParserRegEx.SPEC_PACKAGE_PACKAGENAME].Value)) { specFile.PackageName = specMatch.Groups[PLSQLSpecParserRegEx.SPEC_PACKAGE_PACKAGENAME].Value; string procedures = specMatch.Groups[PLSQLSpecParserRegEx.SPEC_PACKAGE_PROCEDURES].Value; if (!string.IsNullOrEmpty(procedures)) { // Do the fetch of the procedures and functions. MatchCollection procFetchMatches = reProcFetch.Matches(procedures); // Loop through the fetched procedures. foreach (Match procMatch in procFetchMatches) { PLSQLSpecParsedProcedure procedure = new PLSQLSpecParsedProcedure(); // Fetch the name of the procedure/function if (procMatch.Groups[PLSQLSpecParserRegEx.PROCEDURE_FETCH_NAME].Value != string.Empty) { procedure.Name = procMatch.Groups[PLSQLSpecParserRegEx.PROCEDURE_FETCH_NAME].Value; } else { // Name is empty! specFile.Procedures.HasParseError = true; specFile.Procedures.SetParseErrorText(PLSQLSpecParserErrorTexts.ProcedureNameError, procMatch.Groups[PLSQLSpecParserRegEx.PROCEDURE_FETCH_NAME].Value); continue; } // Fetch if this is a function or procedure if (!procedure.HasParseError) { bool?isFunction = GetIsFunction(procMatch.Groups[PLSQLSpecParserRegEx.PROCEDURE_FETCH_TYPE].Value); if (isFunction == true) { procedure.IsFunction = true; } else if (isFunction == false) { procedure.IsFunction = false; } else { // Invalid type! procedure.HasParseError = true; procedure.SetParseErrorText(PLSQLSpecParserErrorTexts.ProcedureTypeError, procMatch.Groups[PLSQLSpecParserRegEx.PROCEDURE_FETCH_TYPE].Value); } } // Fetch the function return type if it's a function. if (!procedure.HasParseError) { if (procedure.IsFunction) { // What type of return data type is it. if (procMatch.Groups[PLSQLSpecParserRegEx.PROCEDURE_FETCH_RETURNTYPE_TABLE].Value != string.Empty && procMatch.Groups[PLSQLSpecParserRegEx.PROCEDURE_FETCH_RETURNTYPE_COLUMN].Value != string.Empty) { procedure.FunctionReturnType = ParseFunctionReturnType.TableColumn; procedure.FunctionReturnTypeData.Param1 = procMatch.Groups[PLSQLSpecParserRegEx.PROCEDURE_FETCH_RETURNTYPE_TABLE].Value; procedure.FunctionReturnTypeData.Param2 = procMatch.Groups[PLSQLSpecParserRegEx.PROCEDURE_FETCH_RETURNTYPE_COLUMN].Value; } else if (procMatch.Groups[PLSQLSpecParserRegEx.PROCEDURE_FETCH_RETURNTYPE_DBTYPE].Value != string.Empty) { procedure.FunctionReturnType = ParseFunctionReturnType.DataType; procedure.FunctionReturnTypeData.DataType = GetFunctionReturnDataType(procMatch.Groups[PLSQLSpecParserRegEx.PROCEDURE_FETCH_RETURNTYPE_DBTYPE].Value); if (procedure.FunctionReturnTypeData.DataType == ParseFunctionReturnDBDataType.Invalid) { procedure.HasParseError = true; procedure.SetParseErrorText(PLSQLSpecParserErrorTexts.ProcedureFunctionReturnDataTypeError, procMatch.Groups[PLSQLSpecParserRegEx.PROCEDURE_FETCH_RETURNTYPE_DBTYPE].Value); } } else { // Parse error. Function return type unknown. procedure.HasParseError = true; procedure.SetParseErrorText(PLSQLSpecParserErrorTexts.ProcedureFunctionReturnTypeUnknown, string.Empty); } } } // Fetch all parameters into the string. // It IS possible for the parameters to be empty since it could be a parameterless // procedure or function. if (!procedure.HasParseError) { procedure.ParameterString = procMatch.Groups[PLSQLSpecParserRegEx.PROCEDURE_FETCH_PARAMETERS].Value.Trim(); if (procedure.ParameterString != string.Empty) { // First check how many parameters that exists. MatchCollection paramCountMatches = reParamCount.Matches(procedure.ParameterString); // Do the real fetch of the procedures and functions. MatchCollection paramFetchMatches = reParamFetch.Matches(procedure.ParameterString); // Check that the two different regular expressions generates the same count // of parameters. if (paramCountMatches.Count == paramFetchMatches.Count) { // Loop through all the parameters found foreach (Match paramMatch in paramFetchMatches) { PLSQLSpecParsedProcedureParameter param = new PLSQLSpecParsedProcedureParameter(); // First check what type of parameter this is so we know what kind of // object we should instantiate. if (paramMatch.Groups[PLSQLSpecParserRegEx.PARAMETER_FETCH_TABLE].Value != string.Empty && paramMatch.Groups[PLSQLSpecParserRegEx.PARAMETER_FETCH_COLUMN].Value != string.Empty) { // This is a parameter of type TABLE.COLUMN%type parameter. param.ParameterType = ParseParameterType.TableColumn; param.ParseParameterTypeTableColumn_Table = paramMatch.Groups[PLSQLSpecParserRegEx.PARAMETER_FETCH_TABLE].Value; param.ParseParameterTypeTableColumn_Column = paramMatch.Groups[PLSQLSpecParserRegEx.PARAMETER_FETCH_COLUMN].Value; } else if (paramMatch.Groups[PLSQLSpecParserRegEx.PARAMETER_FETCH_TABLEROW].Value != string.Empty) { // This is a parameter of type TABLE%rowtype parameter. param.ParameterType = ParseParameterType.TableRow; param.ParseParameterTypeTableRow_Table = paramMatch.Groups[PLSQLSpecParserRegEx.PARAMETER_FETCH_TABLEROW].Value; } else if (paramMatch.Groups[PLSQLSpecParserRegEx.PARAMETER_FETCH_PACKAGE].Value != string.Empty && paramMatch.Groups[PLSQLSpecParserRegEx.PARAMETER_FETCH_PACKAGEDATATYPE].Value != string.Empty) { // This is a parameter of type PACKAGE.PACKAGEDATATYPE parameter. param.ParameterType = ParseParameterType.PackageDataType; param.ParseParameterTypePackageDataType_Package = paramMatch.Groups[PLSQLSpecParserRegEx.PARAMETER_FETCH_PACKAGE].Value; param.ParseParameterTypePackageDataType_CustomDataType = paramMatch.Groups[PLSQLSpecParserRegEx.PARAMETER_FETCH_PACKAGEDATATYPE].Value; } else if (paramMatch.Groups[PLSQLSpecParserRegEx.PARAMETER_FETCH_DBTYPE].Value != string.Empty) { // This is a parameter of type varchar2, boolean etc. parameter. param.ParameterType = ParseParameterType.DataType; param.ParseParameterTypeDataType_DataType = GetParameterDataType(paramMatch.Groups[PLSQLSpecParserRegEx.PARAMETER_FETCH_DBTYPE].Value); // Check the datatype if it's supported or not if (param.ParseParameterTypeDataType_DataType == ParseParameterDBDataType.Invalid) { procedure.HasParseError = true; procedure.SetParseErrorText(PLSQLSpecParserErrorTexts.ProcedureParameterDataTypeNotParsable, paramMatch.Groups[PLSQLSpecParserRegEx.PARAMETER_FETCH_NAME].Value); break; } } else { // Unknown parametertype! procedure.HasParseError = true; procedure.SetParseErrorText(PLSQLSpecParserErrorTexts.ProcedureParameterUnknownType, paramMatch.Groups[PLSQLSpecParserRegEx.PARAMETER_FETCH_NAME].Value); break; } // Fetch the name of the parameter if (paramMatch.Groups[PLSQLSpecParserRegEx.PARAMETER_FETCH_NAME].Value != string.Empty) { param.Name = paramMatch.Groups[PLSQLSpecParserRegEx.PARAMETER_FETCH_NAME].Value; } else { // Name is empty. Some error with parsing. procedure.HasParseError = true; procedure.SetParseErrorText(PLSQLSpecParserErrorTexts.ProcedureParameterNameEmpty, string.Empty); break; } // Check if mandatory // Pattern is created so that if there is text in the group // then it's mandatory. If empty it's not. if (paramMatch.Groups[PLSQLSpecParserRegEx.PARAMETER_FETCH_ISMANDATORY].Value != string.Empty) { param.IsMandatory = true; } else { param.IsMandatory = false; } // Check direction of parameter if (paramMatch.Groups[PLSQLSpecParserRegEx.PARAMETER_FETCH_ISINANDOUT].Value != string.Empty) { param.Direction = ParseParameterDirection.InOut; } else if (paramMatch.Groups[PLSQLSpecParserRegEx.PARAMETER_FETCH_ISOUT].Value != string.Empty) { param.Direction = ParseParameterDirection.Out; } else { param.Direction = ParseParameterDirection.In; } // Fetch the defaultvalue (can be empty) param.DefaultValue = paramMatch.Groups[PLSQLSpecParserRegEx.PARAMETER_FETCH_DEFAULTVALUE].Value; // Add the parameter to the procedures parameters. procedure.Parameters.Add(param); } } else /* if (paramCountMatches.Count == paramFetchMatches.Count) */ { if (paramCountMatches.Count > paramFetchMatches.Count) { // Check what parameter is missing. string checkName = string.Empty; foreach (Match countMatch in paramCountMatches) { checkName = countMatch.Groups[PLSQLSpecParserRegEx.PARAMETER_COUNT_NAME].Value; foreach (Match fetchMatch in paramFetchMatches) { if (checkName == fetchMatch.Groups[PLSQLSpecParserRegEx.PARAMETER_FETCH_NAME].Value) { checkName = string.Empty; break; } } if (checkName != string.Empty) { // Name of first parameter found that is missing. procedure.HasParseError = true; procedure.SetParseErrorText(PLSQLSpecParserErrorTexts.ProcedureParameterTooFewFetchedError, checkName); break; } } // Check if it's not set to error yet. There should be an error // even if we can't find any specific parameters that we miss. if (!procedure.HasParseError) { procedure.HasParseError = true; procedure.SetParseErrorText(PLSQLSpecParserErrorTexts.ProcedureParameterTooFewFetchedGenericError, string.Empty); } } else { // Too many fetched parameters compared to counted ones. Very strange! procedure.HasParseError = true; procedure.SetParseErrorText(PLSQLSpecParserErrorTexts.ProcedureParameterTooManyFetchedGenericError, string.Empty); } } } } // Add the procedure to the collection. if (procedure != null) { specFile.Procedures.Add(procedure); } } // Check how many procedures and functions that exists in file. MatchCollection procCountMatches = reProcCount.Matches(procedures); // Check if we got the same count of procedures. if (procCountMatches.Count > procFetchMatches.Count) { // There are more procedures that has been counted than really got fetched. // Find out what procedures and functions that we miss so that we can add // "ghost" versions of them to set as errors. string checkName = string.Empty; int namesFound = 0; foreach (Match countMatch in procCountMatches) { checkName = countMatch.Groups[PLSQLSpecParserRegEx.PROCEDURE_COUNT_NAME].Value; foreach (Match fetchMatch in procFetchMatches) { if (checkName == fetchMatch.Groups[PLSQLSpecParserRegEx.PROCEDURE_FETCH_NAME].Value) { checkName = string.Empty; break; } } if (checkName != string.Empty) { namesFound++; PLSQLSpecParsedProcedure procedure = new PLSQLSpecParsedProcedure(); procedure.Name = checkName; procedure.HasParseError = true; procedure.SetParseErrorText(PLSQLSpecParserErrorTexts.ProcedureNotParsedError, string.Empty); // Add the "ghost" procedure so that it's possible to see the error. specFile.Procedures.Add(procedure); } } // Check if all names was found. if (procCountMatches.Count + namesFound < procFetchMatches.Count) { specFile.Procedures.HasParseError = true; specFile.Procedures.SetParseErrorText(PLSQLSpecParserErrorTexts.ProcedureCollectionMissingProcedures, string.Empty); } } else if (procCountMatches.Count < procFetchMatches.Count) { specFile.Procedures.HasParseError = true; specFile.Procedures.SetParseErrorText(PLSQLSpecParserErrorTexts.ProcedureCollectionTooManyProcedures, string.Empty); } } } } } return(specFile); }