Esempio n. 1
0
        public static string RecreateProcedure(PLSQLSpecParsedProcedure procedure)
        {
            string procString = string.Empty;

            procString += procedure.IsFunction ? "function " : "procedure ";

            procString += procedure.Name;

            if (procedure.Parameters.Count > 0)
            {
                // The current length of the procString is how many spaces
                // that should be added for each new parameter.
                int tabLength = procString.Length;

                procString += "(";

                // First check length in total
                int paraNameLen = 0;
                for (int i = 0; i < procedure.Parameters.Count; i++)
                {
                    int len;

                    PLSQLSpecParsedProcedureParameter param = procedure.Parameters[i];

                    len = param.Name.Length + 1;

                    if (param.IsMandatory)
                    {
                        len += 15 + 1; // "/* Mandatory */ "
                    }

                    if (param.Direction == ParseParameterDirection.InOut)
                    {
                        len += 6 + 1; // "in out "
                    }
                    else if (param.Direction == ParseParameterDirection.Out)
                    {
                        len += 3 + 1; // "out "
                    }

                    paraNameLen = Math.Max(paraNameLen, len);
                }

                for (int i = 0; i < procedure.Parameters.Count; i++)
                {
                    PLSQLSpecParsedProcedureParameter param = procedure.Parameters[i];

                    // Pad to the right the amount of spaces as the tabLength and add a comma.
                    if (i != 0)
                    {
                        procString += "".PadLeft(tabLength, ' ') + ",";
                    }

                    string tmpString = string.Empty;

                    tmpString += param.IsMandatory ? "/* Mandatory */ " : string.Empty;

                    switch (param.Direction)
                    {
                    case ParseParameterDirection.InOut:
                        tmpString += "in out ";
                        break;

                    case ParseParameterDirection.Out:
                        tmpString += "out ";
                        break;
                    }

                    tmpString = param.Name + "".PadLeft(paraNameLen - tmpString.Length - param.Name.Length, ' ') + tmpString;

                    procString += tmpString;

                    switch (param.ParameterType)
                    {
                    case ParseParameterType.DataType:
                        procString += PLSQLSpecParser.GetParameterDataTypeAsString(param.ParameterTypeData.DataType);
                        break;

                    case ParseParameterType.TableColumn:
                        procString += param.ParameterTypeData.Param1 + "." + param.ParameterTypeData.Param2 + "%type";
                        break;

                    case ParseParameterType.TableRow:
                        procString += param.ParameterTypeData.Param1 + "%rowtype";
                        break;

                    case ParseParameterType.PackageDataType:
                        procString += param.ParameterTypeData.Param1 + "." + param.ParameterTypeData.Param2;
                        break;
                    }

                    if (param.DefaultValue != string.Empty)
                    {
                        procString += " := " + param.DefaultValue;
                    }

                    if (i != (procedure.Parameters.Count - 1))
                    {
                        procString += Environment.NewLine;
                    }
                }

                procString += ")";
            }

            if (procedure.IsFunction)
            {
                procString += Environment.NewLine + "    return ";

                switch (procedure.FunctionReturnType)
                {
                case ParseFunctionReturnType.DataType:
                    procString += PLSQLSpecParser.GetFunctionReturnDataTypeAsString(procedure.FunctionReturnTypeData.DataType);
                    break;

                case ParseFunctionReturnType.TableColumn:
                    procString += procedure.FunctionReturnTypeData.Param1 + "." + procedure.FunctionReturnTypeData.Param2 + "%type";
                    break;

                default:
                    procString += "<Unknown Datatype>";
                    break;
                }

                procString += ";";
            }
            else
            {
                procString += ";";
            }

            return(procString);
        }
        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);
        }