In SSIS (MS Visual Studio 2010) I have created a SQL Task with Single Row output (int32) that is passed to User::Variable. Then I have a "For Loop" that I want to run as many times as the integer from the SQL Task query equals to. I have setup the For Loop with the following:
InitExpression: #Start = 1
EvalExpression: #Variable >= #Start
AssignExpression: #Start = #Start+1
In my test example, the #Variable is set to 4 by SQL Task query, and the loop runs fine for the first loop, but then immediately finishes reporting package successfully executed (after just 1 loop when it should have looped 4 times).
It is like the #Variable resets to default value (0) after the first loop is done instead of keeping the original value (4).
How can I fix this?
What's more likely: using the name Variable, which SSIS defaults to for a new variable, is incompatible with anything in an SSIS package or that you've done something that you haven't shown?
I have created a package with two Variables, Variable and Start. I have populated Variable from a SQL Query with the value of 4 and then used a For Loop as described and I did not experience early termination.
My package, variables with design time values set to zero.
My For Loop Container
Last iteration of the loop
Reproducible results
Biml, the Business Intelligence Markup Language, describes the platform for business intelligence. Here, we're going to use it to describe the ETL. BIDS Helper, is a free add on for Visual Studio/BIDS/SSDT that addresses a host of shortcomings with it.
You will need to edit line 3 to be a valid OLE DB Connection Manager for your machine (point to a SQL Server installation and possibly update the Provider)
<Biml xmlns="http://schemas.varigence.com/biml.xsd">
<Connections>
<OleDbConnection Name="CM_OLE" ConnectionString="Data Source=localhost\dev2012;Initial Catalog=tempdb;Provider=SQLNCLI11;Integrated Security=SSPI;" />
</Connections>
<Packages>
<Package Name="so_25878932" ConstraintMode="Linear">
<Variables>
<Variable Name="Variable" DataType="Int32">0</Variable>
<Variable Name="Start" DataType="Int32">0</Variable>
</Variables>
<Tasks>
<ExecuteSQL ConnectionName="CM_OLE" Name="SQL Variable" ResultSet="SingleRow">
<DirectInput>SELECT 4 AS Variable;</DirectInput>
<Results>
<Result Name="0" VariableName="User.Variable"/>
</Results>
</ExecuteSQL>
<ForLoop ConstraintMode="Linear" Name="FLC Go">
<InitializerExpression>#Start = 1</InitializerExpression>
<LoopTestExpression>#Variable >= #Start</LoopTestExpression>
<CountingExpression>#Start = #Start + 1</CountingExpression>
<Tasks>
<!--
Pilfered from http://bimlscript.com/Snippet/Details/74
-->
<Script
ProjectCoreName="ST_232fecafb70a4e8a904cc21f8870eed0"
Name="SCR Emit Variable and Start">
<ReadOnlyVariables>
<ReadOnlyVariable VariableName="User.Variable" />
<ReadOnlyVariable VariableName="User.Start" />
</ReadOnlyVariables>
<ScriptTaskProject>
<ScriptTaskProject ProjectCoreName="ST_c41ad4bf47544c49ad46f4440163feae" Name="TaskScriptProject1">
<AssemblyReferences>
<AssemblyReference AssemblyPath="Microsoft.SqlServer.ManagedDTS.dll" />
<AssemblyReference AssemblyPath="Microsoft.SqlServer.ScriptTask.dll" />
<AssemblyReference AssemblyPath="System.dll" />
<AssemblyReference AssemblyPath="System.AddIn.dll" />
<AssemblyReference AssemblyPath="System.Data.dll" />
<AssemblyReference AssemblyPath="System.Windows.Forms.dll" />
<AssemblyReference AssemblyPath="System.Xml.dll" />
</AssemblyReferences>
<Files>
<File Path="AssemblyInfo.cs">
using System.Reflection;
using System.Runtime.CompilerServices;
//
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
//
[assembly: AssemblyTitle("ST_c41ad4bf47544c49ad46f4440163feae.csproj")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Varigence")]
[assembly: AssemblyProduct("ST_c41ad4bf47544c49ad46f4440163feae.csproj")]
[assembly: AssemblyCopyright("Copyright # Varigence 2013")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: AssemblyVersion("1.0.*")]
</File>
<File Path="ScriptMain.cs">
using System;
using System.Data;
using Microsoft.SqlServer.Dts.Runtime;
using System.Windows.Forms;
// if SSIS2012, use the following line:
[Microsoft.SqlServer.Dts.Tasks.ScriptTask.SSISScriptTaskEntryPointAttribute]
// if earlier version, use the next line instead of the above line:
// [System.AddIn.AddIn("ScriptMain", Version = "1.0", Publisher = "", Description = "")]
public partial class ScriptMain : Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase
{
enum ScriptResults
{
Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success,
Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure
};
public void Main()
{
int i = 0;
MessageBox.Show(string.Format("{0}:{1}", Dts.Variables[i].Name, Dts.Variables[i].Value));
i++;
MessageBox.Show(string.Format("{0}:{1}", Dts.Variables[i].Name, Dts.Variables[i].Value));
Dts.TaskResult = (int)ScriptResults.Success;
}
}
</File>
</Files>
</ScriptTaskProject>
</ScriptTaskProject>
</Script>
<ExecuteProcess Executable="cmd.exe" Name="EP Do nothing" Arguments="/C">
</ExecuteProcess>
</Tasks>
</ForLoop>
</Tasks>
</Package>
</Packages>
</Biml>
Root cause guess
Variables can be created at different scopes within a package. I would presume that since a variable is created with the default name of Variable two, or more, such variables exist with the same name but at different application scopes. Thus, if I had defined a second SSIS variable named Variable on my ForLoop Container, it would start with a value of 0, unless defined otherwise. My package execution would begin, assign the value of 4 to my package level Variable. Control switches to my ForLoop Container. The Variable defined there wins from a scoping perspective so my value there is 0, not 4 because nothing has initialized it. In that case, the ForLoop would never fire as the terminal condition has already been met. For your case, I further presume that someone initialized that variable to 1.
Notice the Scope here, this is what I believe to be your root cause.
Solution:
DO NOT name SSIS variables #Variable. Doing so will unintentionally cause the variable value to pick up exit codes of other processes in the package as they run.
In my case the #Variable value would automatically change to 0 after a successfully run Execute Process Task with exit code 0; or change to -1073741510 when that process run failed.
Related
As most of you know, Windbg can be used for debugging programs, but now I'd like to do just the opposite: I'd like to debug what I'm doing in Windbg, let me show you why:
I've found an interesting native visualiser, containing following entries:
<Type Name='CMap<*,*,*,*>'>
<AlternativeType Name="CMapStringToString"/>
<AlternativeType Name="CMapStringToPtr"/>
<DisplayString>{{size = {m_nCount} }}</DisplayString>
<Expand>
<CustomListItems>
<Variable Name='pHashtable' InitialValue='m_pHashTable'/>
<Variable Name='hashtable_index' InitialValue='0'/>
<Variable Name='pList' InitialValue='*m_pHashTable'/>
<Variable Name='i' InitialValue='0'/>
<Loop Condition='hashtable_index < m_nHashTableSize'>
<Exec>pList = pHashtable[hashtable_index]</Exec>
<Loop Condition='pList '>
<Item Name='{i}: [{pList->key}]'>pList->value</Item>
<Exec>pList = pList->pNext</Exec>
<Exec>++i</Exec>
</Loop>
<Exec>++hashtable_index</Exec>
</Loop>
</CustomListItems>
</Expand>
</Type>
<Type Name='CMap<*,*,*,*>' IncludeView='keys'>
<AlternativeType Name="CMapStringToString::CAssoc"/>
<AlternativeType Name="CMapStringToPtr::CAssoc"/>
<DisplayString>{{size = {m_nCount} }}</DisplayString>
<Expand>
<CustomListItems>
<Variable Name='pHashtable' InitialValue='m_pHashTable'/>
<Variable Name='hashtable_index' InitialValue='0'/>
<Variable Name='pList' InitialValue='*m_pHashTable'/>
<Variable Name='i' InitialValue='0'/>
<Loop Condition='hashtable_index < m_nHashTableSize'>
<Exec>pList = pHashtable[hashtable_index]</Exec>
<Loop Condition='pList '>
<Item Name='[{i}].key:'>pList->key</Item>
<Item Name=' [{i}].value:'>pList->value</Item>
<Exec>pList = pList->pNext</Exec>
<Exec>++i</Exec>
</Loop>
<Exec>++hashtable_index</Exec>
</Loop>
</CustomListItems>
</Expand>
</Type>
These entries make sure that CMap objects get shown in a nice way, one under the other. Together with another internal entry, this gives following result in a Visual Studio watch-window:
0x000000005b9c95d0 Element L"Element1" (ID1/SubID1.1, L"interesting_information.1"/L"1.0.0.0")
0x0000000059484d20 Element L"Element2" (ID1/SubID1.2, L"interesting_information.2"/L"2.0.0.0")
0x000000004caa6110 Element L"Element3" (ID2/SubID2.1, L"interesting_information.3"/L"3.0.0.0")
...
(this goes until the end of the CMap)
When I try to do the same in Windbg (using the dx commands), this gives similar information, but it ends at entry number 49:
Windbg Prompt>dx -r1 (*((<application>!CMap<unsigned __int64,unsigned __int64,CElement *,CElement *> *)0x13fbd2ae0))
[" [0].value:"] : 0x6dce7fd0 [Type: CElement *]
["[1].key:"] : 0x7984000007a3 [Type: unsigned __int64]
[" [1].value:"] : 0x5b9c95d0 [Type: CElement *]
["[2].key:"] : 0x79840000053f [Type: unsigned __int64]
...
[" [49].value:"] : 0x1bab05b0 [Type: CElement *]
[...] [Type: CMap<unsigned __int64,unsigned __int64,CElement *,CElement *>]
(By clicking on the entries, I get more information, which is correctly rendered by the mentioned other native visualiser entry)
I'd like to know the reason why the display of the CMap entries stops at 49. I already know I can get more entries by clicking on ... (which adds -c 100, -c 200, ... to the dx command) but if I could get more information (like the output window of Visual Studio with the option "Debugging, Output Window, General Output Settings, Natvis diagnostics messages" set to "Verbose"), I'd be able to diagnose and solve my problems.
Does anybody know how to do this?
Thanks in advance
At the moment, there are not 'extended diagnostics' available for NatVis in WinDbg similar to what you can get with Visual Studio.
That said -- the 'dx' command will, by default, display the first 100 entries of any container and display a DML link for continuation (the [...]). If you want more than 100 entries, you can use a format specifier to indicate how many entries to display (these are the same as with Visual Studio).
For example:
dx <container expression>,1000
would display 1000 entries of whatever evaluated to before a continuation link instead of the default 100.
windbg can debug windbg the child windbg debugging your actual binary
iirc it is callef daisy wheeling
open a command prompt
type windbg windbg app and hit enter
if you dont mind using the console version windbg has an inbuilt command
.dbgdbg
this will spawn a parent debugger to an existing instance
How do i find a text() node in XmlConfig and use it to remove the parent nodeset. All the examples I have seen just find and remove the 'found' node not the parent nodes.
My understanding is that this Xpath finds the matching node via verify path and ElementPath is the path of the nodes to remove. However Its not working at all.
Is text() supported?, I have tried [[*='ATrigger'[]], [[].='ATrigger'[]] but still no luck.
<util:XmlConfig Id="RemoveATriggerCompletely" File="[#QuartzXmlJob]" Sequence="104" Action="delete" On ="install" Node="element"
ElementPath="//job-scheduling-data/schedule/"
VerifyPath="//job-scheduling-data/schedule/trigger/cron/name[\[]text()='ATrigger'[\]]"/>
Given the following XML
<job-scheduling-data xmlns="http://quartznet.sourceforge.net/JobSchedulingData" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0">
<schedule>
<trigger>
<cron>
<name>ATrigger</name>
<group>default</group>
<description>Every 2 minutes</description>
<job-name>ATriggerJob</job-name>
<job-group>defaultGroup</job-group>
<misfire-instruction>SmartPolicy</misfire-instruction>
<!-- every 5mins -->
<cron-expression>2 * * * * ?</cron-expression>
</cron>
</trigger>
<trigger>
<cron>
<name>BTrigger</name>
<group>default</group>
<description>Every 2 minutes</description>
<job-name>BTriggerJob</job-name>
<job-group>defaultGroup</job-group>
<misfire-instruction>SmartPolicy</misfire-instruction>
<!-- every 5mins -->
<cron-expression>2 * * * * ?</cron-expression>
</cron>
</trigger>
The output i require is
<job-scheduling-data xmlns="http://quartznet.sourceforge.net/JobSchedulingData" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0">
<schedule>
<trigger>
<cron>
<name>BTrigger</name>
<group>default</group>
<description>Every 2 minutes</description>
<job-name>BTriggerJob</job-name>
<job-group>defaultGroup</job-group>
<misfire-instruction>SmartPolicy</misfire-instruction>
<!-- every 5mins -->
<cron-expression>2 * * * * ?</cron-expression>
</cron>
</trigger>
I have been banging my head against a wall for hours now so any help whatsoever is very much appreciated.
I'm not familiar with that "XmlConfig" task.
But I see two issues.
You need to alias the namespace and use that alias for the xpath "select".
I show the XmlPeek version below. Note I use "peanut", you can use any alias name you want.
Note the query now has "peanut:" in all the element names.
<!-- you do not need a namespace for this example, but I left it in for future reference -->
<XmlPeek Namespaces="<Namespace Prefix='peanut' Uri='http://quartznet.sourceforge.net/JobSchedulingData'/>"
XmlInputPath=".\Parameters.xml"
Query="//peanut:job-scheduling-data/peanut:schedule/peanut:trigger/peanut:cron/peanut:name[text()='ATrigger']/../..">
<Output TaskParameter="Result" ItemName="Peeked" />
</XmlPeek>
Note my "../.."
Once you find the correct element, finding its parent(s) is simple as the ".." notation.
You'll need to figure out how to add the namespace and alias to your Task (XmlConfig)
APPEND:
http://sourceforge.net/p/wix/bugs/2384/
Hmmm...dealing with a namespace isn't trivial. I think you're having a similar issue to what is reported there.
APPEND:
"Inline" Namespacing ... (Yuck)
<XmlPeek
XmlInputPath=".\Parameters.xml"
Query="//*[local-name()='job-scheduling-data' and namespace-uri()='http://quartznet.sourceforge.net/JobSchedulingData']/*[local-name()='schedule' and namespace-uri()='http://quartznet.sourceforge.net/JobSchedulingData']/*[local-name()='trigger' and namespace-uri()='http://quartznet.sourceforge.net/JobSchedulingData']/*[local-name()='cron' and namespace-uri()='http://quartznet.sourceforge.net/JobSchedulingData']/*[local-name()='name' and namespace-uri()='http://quartznet.sourceforge.net/JobSchedulingData'][text()='ATrigger']/../..">
<Output TaskParameter="Result" ItemName="Peeked" />
</XmlPeek>
Aka, try this Xpath:
"//*[local-name()='job-scheduling-data' and namespace-uri()='http://quartznet.sourceforge.net/JobSchedulingData']/*[local-name()='schedule' and namespace-uri()='http://quartznet.sourceforge.net/JobSchedulingData']/*[local-name()='trigger' and namespace-uri()='http://quartznet.sourceforge.net/JobSchedulingData']/*[local-name()='cron' and namespace-uri()='http://quartznet.sourceforge.net/JobSchedulingData']/*[local-name()='name' and namespace-uri()='http://quartznet.sourceforge.net/JobSchedulingData'][text()='ATrigger']/../.."
This is my first question on stackoverflow.
I searched over the web to no avail, and I really can't figure out what's wrong, so here we go.
I am trying to add a dialog window to Marionnet. The window information is mostly contained in the glade file, with some bits modified from code. lablgtk is the framework that allows gtk2 (and thus glade-generated files) to be used with the ocaml language.
The application is successfully compiled, however it generates this runtime error at launch:
(marionnet.byte:5384): libglade-CRITICAL **: glade_xml_build_interface: assertion `wid != NULL' failed
Fatal error: exception Failure("Glade error: GtkDialog:dialog_RELATIVIZATION is not accessible.")
Raised at file "pervasives.ml", line 22, characters 22-33
Called from file "gui.ml", line 617, characters 9-85
Called from file "gui/gui_menubar_MARIONNET.ml", line 356, characters 17-49
Called from unknown location
Called from unknown location
The error suggests that the class constructor doesn't exist or something like that, but I checked multiple times and I didn't spot any typo in the identifiers I used. What am I missing here? What does the exception actually mean?
To prove that there are no typos or missing identifiers, I'll show you the file contents.
The file gui.ml is generated by lablgladecc2, which reads the contents of gui.xml (the glade file). This is an extract from gui.xml:
<widget class="GtkDialog" id="dialog_RELATIVIZATION">
<property name="visible">True</property>
<property name="title" translatable="yes">Relativization</property>
<property name="resizable">False</property>
<property name="modal">True</property>
<property name="destroy_with_parent">True</property>
<property name="icon">marionnet-launcher.png</property>
<property name="type_hint">dialog</property>
<child internal-child="vbox">
[...]
So the id "dialog_RELATIVIZATION" is there. Indeed, the generated gui.ml file has the correct class and method:
[...]
class dialog_RELATIVIZATION ?(file="gui.glade.patched") ?domain ?autoconnect(*=true*) () =
let xmldata = Glade.create ~file ~root:"dialog_RELATIVIZATION" ?domain () in
object (self)
inherit Glade.xml ?autoconnect xmldata
val toplevel =
new GWindow.dialog_any (GtkWindow.Dialog.cast
(Glade.get_widget_msg ~name:"dialog_RELATIVIZATION" ~info:"GtkDialog" xmldata))
method toplevel = toplevel
val dialog_RELATIVIZATION =
new GWindow.dialog_any (GtkWindow.Dialog.cast
(Glade.get_widget_msg ~name:"dialog_RELATIVIZATION" ~info:"GtkDialog" xmldata))
method dialog_RELATIVIZATION = dialog_RELATIVIZATION
[...]
This is the code where I try to access the window:
let rel_dialog = new Gui.dialog_RELATIVIZATION () in
rel_dialog#toplevel#set_title (s_ "Relativization");
rel_dialog#label_frequency#set_label (s_ "Frequency");
rel_dialog#label_convergence#set_label (s_ "Convergence");
rel_dialog#checkb_existing_machines#set_label (s_ "Apply to existing machines");
Google didn't help me, and I did not find good documentation about lablgtk. Does anyone know what the exception means and what the cause could be?
H,
I need to get a user input during installation then use it as an argument for an application which is executed in the processPanle. How can I get the variable which contains the user input in the processPanel?
You can reference the variable using ${} syntax like shown in the following example.
userInputSpec.xml (snippet):
<field type="rule" variable="tomcat_http_port">
<spec txt="HTTP-Port:" id="panel0.field2.label" set="0:80" layout="N:5:5" />
</field>
process.xml (snippet):
<job name="Launching Browser">
<executeclass name="edu.ccdb.util.BareBonesBrowserLauncher">
<arg>http://localhost:${tomcat_http_port}/klaros-web</arg>
</executeclass>
</job>
Background:
I want to take some xml from one file, put it in a template file and then save the modified template as a new file. It works, but when I save the file out, all the nodes that I added have a default namespace prepeneded, i.e.
<default:ComponentRef Id="C__AD1817F9C64A42F0A14DDDDC82DFC8D9"/>
<default:ComponentRef Id="C__157DD41D70854617A3D6D1E4A39B589F"/>
<default:ComponentRef Id="C__2E6D8662F38FE62CAFA9F8842A28F510"/>
<default:ComponentRef Id="C__54E5E2181323D4A5F37293DAA87B4230"/>
Which I want to be just:
<ComponentRef Id="C__AD1817F9C64A42F0A14DDDDC82DFC8D9"/>
<ComponentRef Id="C__157DD41D70854617A3D6D1E4A39B589F"/>
<ComponentRef Id="C__2E6D8662F38FE62CAFA9F8842A28F510"/>
<ComponentRef Id="C__54E5E2181323D4A5F37293DAA87B4230"/>
The following is my ruby code:
file = "wixmain/generated/DarkOutput.wxs"
template = "wixmain/generated/MsiComponentTemplate.wxs"
output = "wixmain/generated/MSIComponents.wxs"
dark_output = Nokogiri::XML(File.open(file))
template_file = Nokogiri::XML(File.open(template))
#get stuff from dark output
components = dark_output.at_css("Directory[Id='TARGETDIR']")
component_ref = dark_output.at_css("Feature[Id='DefaultFeature']")
#where to insert in template doc
template_component_insert_point = template_file.at_css("DirectoryRef[Id='InstallDir']")
template_ref_insert_point = template_file.at_css("ComponentGroup[Id='MSIComponentGroup']")
template_component_insert_point.children= components.children()
template_ref_insert_point.children= component_ref.children()
#write out filled template to output file
File.open(output, 'w') { |f| template_file.write_xml_to f }
Update
Example of my template file:
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>
<Fragment>
<ComponentGroup Id='MSIComponentGroup'>
</ComponentGroup>
</Fragment>
<Fragment Id='MSIComponents'>
<DirectoryRef Id='InstallDir'>
</DirectoryRef>
</Fragment>
</Wix>
Workaround was to remove the xmlns attribute in the input file.
Or to use the remove_namespaces! method when opening the input file
input_file = Nokogiri::XML(File.open(input))
input_file.remove_namespaces!
I think you are missing a sample of the template file. Also, is the sample from the input complete?
Nokogiri is either finding the default: namespace during its parsing of one of the two files, and you are inheriting it, or maybe it is not happy with the sample during parsing and is unable to parse cleanly, and as a result somehow adding the default: namespace. You can check the emptiness of the errors array after parsing the dark_output and template_file to see if Nokogiri is happy.
dark_output = Nokogiri::XML(File.open(file))
template_file = Nokogiri::XML(File.open(template))
if (dark_output.errors.any? || template_file.errors.any?)
[... do something here ...]
end
For the fastest answer, you might want to take this question directly to the developers via the Nokogiri-Talk mail-list.