Friday, September 3. 2010

State of Company

August is officially over (according to Julius Caesar) so time again for another State of the Company.  The big news this month is that  we have expanded!  An incredible office opened up on the third floor and since things were getting a little cramped up in the tower we decided to get it.  Half of the new office is for Peter and half has been converted into an employee lounge of sorts.  It's pretty swanky.  Unfortunately I keep forgetting to bring my camera into the office so no pictures yet but as soon as I remember I'll update this post.

For any budding entrepreneurs out there considering whether to get an office or work out of a garage, definitely get the office.  Yep it's a little extra money a month (when we were first looking prices ranged from ~$275-$600 per month for single offices) but the ability to go somewhere outside of your house and focus on your work is priceless.

On the work front Kevin is still working diligently on his office management project.  In fact, due to a shortage of decent backup programs Kevin spent part of August porting Duplicity from Linux to Windows!  Woohoo Kevin!  While we are waiting on some items to be sorted out with the heat mapping project Peter has been working on a GUI for Git which sounds like it is coming along nicely although I haven't seen it yet so it could be a lie just like the cake.  Finally I have been finishing up the real estate search plug-in for Joomanager, making modifications to the Huffing For Stuffing site and working on my Orbit presentation. We are going to have a ton of great information at our Orbit presentations (the first two will be in Big Fork on the 22nd and Frenchtown on the 23rd) so come by if you can make it.  Also the next LAN party will be on Saturday October 9th at the Library.  See you next month!

Posted by Mike Archer at 12:59 | Comments (0) | Trackbacks (0)

Wednesday, August 25. 2010

Xcode and 'Fix and Continue'

A quick pro tip:

Coming from the Java world and the eclipse IDE, I fell in love with the 'Drop to Frame' feature and the ability to change code on the fly while debugging. In Xcode, you can get half way there with the 'Fix' command (under the Run menu, enabled only while paused while debugging). The frustrating thing is that in the most recent version of Xcode (v3.2.3) this command is constantly disabled.

If you read the Apple's "Xcode Debugging Guide" (http://developer.apple.com/mac/library/documentation/DeveloperTools/Conceptual/XcodeDebugging/230-Modifying_Running_Code/modifying_running_code.html) and follow its guidelines about how to set up your environment to enable the menu item, it'll most likely stay disabled. The thing that the guide doesn't mention, and therefore is probably a bug and one that hopefully gets patched in Xcode 4, is that your build architecture must be 32-bit only. Since the default architecture is 32/64 bit universal, the fix command is unavailable by default until you change it.

Posted by Peter Nix at 11:03
Defined tags for this entry: xcode

Wednesday, August 18. 2010

LAN Aftermath Part 2

The August 5th LAN went off without a hitch (well only one).  Thank you so much to everyone that came, played, helped set up, pick up, and donated posters (Carson)!  The library ended up being a great spot.  Internet was super fast, the network was super fast and we had lots of room.  The only minor problem we ran into is that the library shuts off their internet at 10:00 p.m.  In the future we'll see if there is anything we can do about that, if not we will just start the gaming a little earlier to compensate.  Plus, bonus, I am about to send off a check to Eagle Mount for $50.  Thank you to everyone who donated despite our ample seating! :-)  Expect an announcement in the next couple of days regarding the date of our next LAN! 
Posted by Mike Archer at 14:18 | Comments (0) | Trackbacks (0)

Friday, August 13. 2010

Passing pipes to subprocesses in Python in Windows

Passing pipes around in Windows is a bit more complicated than it is in Unix-like operating systems. This post is a bit of information about how file descriptor inheritance works in Windows and a quick example of how to do it.

The first difficulty to overcome is that file descriptors are not inherited by subprocesses in Windows as they are in Linux. However, OS file handles can be inheritable, and it is possible to retrieve the OS file handle associated with a C file descriptor using the _get_osfhandle function. It is also possible to convert the OS file handle back to a C file descriptor in the child process using _open_osfhandle. However, the OS file handle is not inheritable (see Python Bug 4708 - although on a side note, I don't think they should be default-inheritable since there is no preexec_fn in which to close them and prevent deadlock situations where a child holds the write end of a pipe open, but that is another matter), so to get an inheritable OS file handle it must be duplicated using DuplicateHandle.

The operating system-specific functions described above can be accessed through the _subprocess and msvcrt modules. Their use can be seen in the source for the subprocess module, if desired. However, note that the interface in _subprocess is not stable and should not be depended on, but since there is no alternative (that I am aware of - short of writing another module in C) it is the best solution. Now, an example:

parent.py:

import os
import subprocess
import sys

if sys.platform == "win32":
    import msvcrt
    import _subprocess
else:
    import fcntl

# Create pipe for communication
pipeout, pipein = os.pipe()

# Prepare to pass to child process
if sys.platform == "win32":
    curproc = _subprocess.GetCurrentProcess()
    pipeouth = msvcrt.get_osfhandle(pipeout)
    pipeoutih = _subprocess.DuplicateHandle(curproc, pipeouth, curproc, 0, 1,
            _subprocess.DUPLICATE_SAME_ACCESS)

    pipearg = str(int(pipeoutih))  
else:
    pipearg = str(pipeout)

    # Must close pipe input if child will block waiting for end
    # Can also be closed in a preexec_fn passed to subprocess.Popen
    fcntl.fcntl(pipein, fcntl.F_SETFD, fcntl.FD_CLOEXEC)

# Start child with argument indicating which FD/FH to read from
subproc = subprocess.Popen(['python', 'child.py', pipearg], close_fds=False)

# Close read end of pipe in parent
os.close(pipeout)
if sys.platform == "win32":
    pipeoutih.Close()

# Write to child (could be done with os.write, without os.fdopen)
pipefh = os.fdopen(pipein, 'w')
pipefh.write("Hello from parent.")
pipefh.close()

# Wait for the child to finish
subproc.wait()
 
child.py:

import os
import sys

if sys.platform == "win32":
    import msvcrt

# Get file descriptor from argument
pipearg = int(sys.argv[1])
if sys.platform == "win32":
    pipeoutfd = msvcrt.open_osfhandle(pipearg)
else:
    pipeoutfd = pipearg

# Read from pipe
# Note:  Could be done with os.read/os.close directly, instead of os.fdopen
pipeout = os.fdopen(pipeoutfd, 'r')
print pipeout.read()
pipeout.close()
 

Note: For this example to work, python must be on on the executable search path (i.e. in the %PATH% environment variable). If it is not, change the subprocess invocation to include the full path to python.exe. Note also that there is some complication with OS file handle leakage. When a _subprocess_handle object is garbage collected the handle that it holds is closed, unless it has been attached. Therefore, if the subprocess will outlive the scope in which the handle variable is defined, it must be detached (by calling its Detach method) to prevent closing during garbage collection. But this solution has its own problems as there is no way (that I am aware of) to close the handle from the child process, which means a file handle will be leaked.

Above caveats aside, this method does work for passing pipes between parent and child processes on Windows. I hope you find it useful.

Posted by Kevin Locke in Software Development at 21:00 | Comments (0) | Trackbacks (0)

Monday, August 9. 2010

BAD_POOL_HEADER in VirtualBox

I have been evaluating different virtualization software recently and have been quite impressed with VirtualBox for desktop virtualization. The user interface is simple and easy to use, and the hardware video acceleration is a real plus. Recently, while installing Windows XP in VirtualBox I encountered a BAD_POOL_HEADER BSOD when booting from an XP installation CD created with nLite (just after "Starting Windows..." is displayed in the status bar). With some help from a thread on MSFN, I tracked the issue down to the Intel drivers that I had included on the CD. I was using version 9.6.0.1014 of the Intel Matrix Storage Manager Floppy Configuration Utility (f6flpy), recreating the CD with version 8.9.0.1023 (from the archives) solved the problem. Note: The choice of IDE controller in the VirtualBox configuration does not appear to matter, both ICH6 and PIIX4 resulted in the BSOD.
Posted by Kevin Locke in Troubleshooting at 17:41 | Comments (0) | Trackbacks (0)

Thursday, August 5. 2010

Prevent Web Pages from Stealing Focus

I have had enough of web pages arbitrarily changing the cursor focus. Enough of typing half of a URL into the URL bar and half into the text box that stole focus. Enough of typing half of a password into a password box and half into the text box that stole focus. Enough! If you have had enough, check out the NoFocus Greasemonkey script. This script prevents pages from changing focus during page load and, optionally, for the entire life of the page.

This is not a new problem. It has been discussed before on superuser and elsewhere. There are also alternative solutions, such as using Firefox's Configurable Security Policies to disallow focus, or using another Greasemonkey script such as NoFocusForYou and Disable Focus on Window Load. However, NoFocus has several advantages:

  • No exceptions are thrown, as with CSPs. Most page authors are not expecting focus to throw exceptions (rightly so), and when this happens it will often completely break the pages by preventing the remainder of the script from running.
  • Disables focus immediately (well, in the DOMContentLoaded event, when Greasemonkey runs its scripts). Other scripts only disable focus changing once the load event has fired, which doesn't address focus changes before this event occurrs.
  • Disables focus changes for all elements currently on the page and all dynamically created elements. Rather than disabling focus for the elements on the page during load or DOMContentLoaded, this script disables focus for all elements current and future.
  • Provides warnings when focus change is prevented. Inevitably, when debugging a page sometime in the future, we will forget that focus changing is prevented (if only briefly) and will fail to understand why a page is not working as expected. NoFocus counteracts this problem by using the Greasemonkey logging to write a warning message into the error log that focus change has been prevented. Making it easier to determine why focus is not performing as expected.

I hope you enjoy the script and enjoy not losing focus!

Posted by Kevin Locke at 08:24 | Comments (0) | Trackbacks (0)

Sunday, August 1. 2010

State of the company August 1st

The blog has recently started to look like it was written by programming robots.  To show that we are actually real life people with feelings and emotions and organs I figured I would write a little about what we have been up to.

Wednesday was the Emerging Technologies Symposium hosted by the Chamber of Commerce.  We all went and got to talk with some cool folks.  I got us a booth right across from Microsoft thinking Kevin could wage an all-out war in order to release some of the pent up frustration he has had building since he started working with the Microsoft Sync framework.  Unfortunately Microsoft sent a non-Microsoft lackey probably realizing full-well that we were planning on ambushing them.  Next time Microsoft!  Otherwise I thought it was an excellent way to advertise and spend the day.  Especially considering the booth only cost $150 and we all got lunch+$25 gift card from HP.

What We Are Doing Right Now

Peter is finishing up work on the heat mapping software he has been working on for NWB Sensors.  If you need the best heat camera+software solution that money can buy contact one of the guys at NWB!  Kevin has been working hard on the big office management suite he is making for HCS as well as on a super secret project demo.  As I mentioned above some of the office management suite functionality was being done using Microsoft Sync but I'm pretty sure Kevin gave up on that and moved back to Git which is great because we now have office t-shirts that say "Git Forked" and this is just one more reason to wear them.  I have been working on a PHP script to download MLS files from a repository and add property listings to a Joomanager database as well as create search functionality for said database.  Unfortunately because Joomanager is set up to allow you enter any number of fields you want dealing with the database is a gigantic pain.  Fortunately it is a kind of fun challenge and I'm almost done!

What We Will Do In The Future (Probably)

This Friday the 6th is our second LAN party.  We will be holding it at the Bozeman public library from 3:00 p.m.-Midnight'ish and the theme is StarCraft II but everyone and all games are welcome.  Our official LAN website is: http://www.digitalenginesoftware.com/lan/ .  Further out I will be helping to teach classes in rural Montana towns on how to setup and market your small business website.  This program is being put on by the Tech Ranch and you can find out more at the Orbit Montana website.  Peter will be working on our speculative project which is just getting to the exciting parts and Kevin will be planning his revenge.  I'll update more next month!

 

Posted by Mike Archer at 16:26 | Comments (0) | Trackbacks (0)

Monday, July 12. 2010

The case of the missing tiff plugin

As a little background to this post, during the course of a recent client project involving image manipulation, I wrote some code to handle images in the tiff format. I used the Java Advanced Imaging (JAI) library's ImageIO class, which made reading from the image file super easy through the use of ImageIO.read(File) which automatically determines the file format based on the extension and performs the file read internally, returning a fully usable BufferedImage object. It really makes reading data from an image super easy, and I highly recommend using it.

While working on the project I needed to write a simple utility to count the number of unique colors in an image and print out how many pixels in the image were that color (useful for debugging the main application). Its a really simple Java program that loops through the image, incrementing the count in a hash map of color values to pixel counts. I copy/pasted the image reading code from the main program, and was surprised to see the test program start generating errors stating that the tiff file could not be read as there was no image reader associated with the tiff file format. Lacking a tiff reader is really surprising because this test utility is just another class file within the same eclipse project as the main application, and therefore has the same class path. Both the jai_core.jar and the jai_codec.jar (the two jars that make up the JAI library) are on the project's class path, so there should be no reason that one java file would have access to them, but another java file does not.

It turns out this was also a problem for gif and jpeg images in versions past, as evidenced by this FAQ question on the JAI home page:

On Solaris, Java Advanced Imaging complains about lack of access to an X server.
Java Advanced Imaging versions previous to JAI 1.1.1 used the AWT toolkit to load GIF and JPEG files. This problem is a manifestation of a JDK bug in which creation of the AWT Toolkit class results in an attempt to open the X display. To work around this problem in Java Advanced Imaging versions prior to 1.1.1, either make an X display available to the Java runtime using the DISPLAY environment variable (no windows will appear on the display), or consider running a dummy X server that will satisfy the AWT, such as the Xvfb utility included with the X11R6.4 distribution.

In the JAI 1.1.1 version, the GIF and JPEG decoders were improved to no longer have a dependency on the X server.

The answer it turns out is that my simple utility does not set up the AWT windowing system (since I wrote it as a CLI utilizing System.in) and therefore does not end up loading the tiff image reader plugin because of this fact. It turns out that in order to utilize the tiff reader plugin from the JAI library your code must perform at least one of the following calls:

  1. Instantiate a JFrame
  2. Call Toolkit.getDefaultToolkit()
  3. Call Application.getApplication() (Mac OS X java extension)

While I still don't know the exact nature of the behavior, all evidence points to the fact that in a java program that needs to utilize the tiff image reader, you must set up the AWT windowing system in some manner. Even if your program (like my test utility) doesn't need to create a window or deal with the windowing system in any fashion, you must do one of the above methods in order to correctly register the tiff reader.

Posted by Peter Nix at 14:29
Defined tags for this entry: awt, jai, java, tiff

Sunday, July 11. 2010

Clone Only HEAD Using Git-SVN

A quick tip for git-svn users: When checking out an SVN repository where only the HEAD revision is desired, the following snippet may be useful:


git svn clone -$(svn log -q --limit 1 $SVN_URL | awk '/^r/{print $1}') $SVN_URL
 

The above snippet determines the most recent SVN revision number (using svn log) and passes it to git-svn-clone. This can also be added to git as an alias by adding the following to .gitconfig:

[alias] svn-clone-head = "!f() { git svn clone -`svn log -q --limit 1 $1 | awk '/^r/{print $1}'` $1 $2; }; f"

For checking out the last $N commits, a similar convention can be used:


git svn clone -$(svn log -q --limit $N $SVN_URL | awk '/^r/{rev=$1};END{print rev}') $SVN_URL
 
Posted by Kevin Locke in Software Development at 19:44 | Comments (0) | Trackbacks (0)

Friday, July 9. 2010

HttpHandlers in Virtual Directories on IIS6

Background

I recently encountered an interesting problem related to how Virtual Directories interact with web.config when dealing with an HttpHandler. The website was virtually rooted at "/webapp", physically rooted at "C:\inetpub\wwwroot\webapp". Inside the application, I wanted "files" ("/webapp/files") to be physically rooted on another drive at "E:\files" so that large data files could be stored on a more appropriate drive. Furthermore, I wanted a custom Http Handler which would generate a few files inside "files" on the fly. Initially, this was setup by creating a virtual directory named "files" which pointed to "E:\files", the HttpHandler was placed in App_Code, and web.config contained the following:


<?xml version="1.0"?>
<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
  <system.web>
    <httpHandlers>
      <add verb="GET" path="files/generated.txt" type="WebApp.MyHttpHandler" />
    </httpHandlers>
  </system.web>
</configuration>
 
The Problem

As I quickly found out, this doesn't work (for several reasons, as we will see). First, requests for .txt files are not handled by isapi_aspnet.dll (by default), so whatever is done in the ASP.NET code is irrelevant because IIS will not call ASP.NET to handle the request. To fix this problem, the .txt extension can be added to the list of extensions handled by isapi_aspnet.dll (which will cause extra overhead as each request is run through the ASP.NET ISAPI handler, even when the file exists on disk) or the extension of the generated file can be changed to something mapped to isapi_aspnet.dll (like .aspx).

Next, unless the content of "files" is going to be substantially different from the rest of the application, the "files" Virtual Directory must not be a Virtual Application. If the "files" mapping is really a Virtual Application, it will not share code with the parent application so the HttpHandler class will not be found.

Finally, due to how the ASP.NET Configuration File Hierarchy and Inheritance works, web.config will be (essentially) re-applied in the virtual directory, so "files/generated.aspx" will be "files/files/generated.aspx" when considered from inside of the "files" virtual directory. To fix this (while not also creating a "/generated.aspx" alias as well), remove the httpHandlers section in the global web.config and create a web.config inside of the physical directory for "files" with path="generated.aspx"

Once all of the above steps are completed, the generated file should appear correctly and everything should be golden. If not, I strongly recommend replacing the real content of the custom HttpHandler with code that simply writes a string to the response and exits. This way any internal errors in the HttpHandler will not confound any issues with whether or not the handler is being called.

Posted by Kevin Locke in ASP.NET at 13:22 | Comments (0) | Trackbacks (0)

Thursday, July 8. 2010

Microsoft Sync Framework (v2) Not Thread Friendly

As a quick note for other developers that may be getting the same (difficult to understand) error, the Microsoft Sync Framework version 2 is not as thread-friendly as one might expect. The API documentation makes it clear that class instances in the framework are not thread-safe, however, this thread-unsafety goes farther. Even when the instance is protected by proper locking to prevent concurrent access, it may still error when accessed from multiple threads. For example, if a SyncOrchestrator and 2 FileSyncProviders are initialized on one thread and (later) Synchronize is called from another thread, the following exception will be thrown:

System.InvalidCastException: Specified cast is not valid. at Microsoft.Synchronization.CoreInterop.SyncServicesClass.CreateSyncSession(ISyncProvider pDestinationProvider, ISyncProvider pSourceProvider) at Microsoft.Synchronization.KnowledgeSyncOrchestrator.DoOneWaySyncHelper(SyncIdFormatGroup sourceIdFormats, SyncIdFormatGroup destinationIdFormats, KnowledgeSyncProviderConfiguration destinationConfiguration, SyncCallbacks DestinationCallbacks, ISyncProvider sourceProxy, ISyncProvider destinationProxy, ChangeDataAdapter callbackChangeDataAdapter, SyncDataConverter conflictDataConverter, Int32& changesApplied, Int32& changesFailed) at Microsoft.Synchronization.KnowledgeSyncOrchestrator.DoOneWayKnowledgeSync(SyncDataConverter sourceConverter, SyncDataConverter destinationConverter, SyncProvider sourceProvider, SyncProvider destinationProvider, Int32& changesApplied, Int32& changesFailed) at Microsoft.Synchronization.KnowledgeSyncOrchestrator.Synchronize() at Microsoft.Synchronization.SyncOrchestrator.Synchronize() at DigitalEngine.SyncMgrFileSync.SyncItem.Synchronize() in File.cs:line num

To work around such errors, make sure all sync instances are only accessed from a single thread.

Posted by Kevin Locke in Software Development at 08:33 | Comments (0) | Trackbacks (0)

Friday, June 25. 2010

SQL Server Missing from Synchronization Manager

Symptoms

After (re-)creating a subscription to a pull merge replication publication from SQL Server Express 2005, the subscription fails to appear in Synchronization Manager. After further investigation, the symptom was determined to be restricted to non-Administrators.

Things To Check
  • Make sure sp_addmergepullsubscription_agent was run with @enabled_for_syncmgr = 'TRUE'. This requirement differs from previous SQL Server versions where this was the default. When this parameter is not set to 'TRUE', the subscription will not appear in Synchronization Manager
  • Make sure the subscription can be synchronized outside of Synchronization Manager (to confirm that it is a problem when run through replsync.dll - in Synchronization Manager). The easiest way to do this is using replmerg from the command-line.
  • Make sure the user has permissions to write to HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\80\Replication\Subscriptions. Without write permission, SQL Server will silently fail to appear in Synchronization Manager. Also, by default in many configurations, non-Administrators do not have write access to this key so it must be adjusted manually.

The last item is particularly important and required quite a bit of my time to determine... which resulted in the need for this post. Hopefully one of the above suggestions will help you avoid spending the same amount of time that I did to solve this problem.

Posted by Kevin Locke in SQL Server at 11:18 | Comments (0) | Trackbacks (0)

Sunday, June 20. 2010

Triggers, NOT FOR REPLICATION Identity, and Merge Replication

Initial Note/Warning

I hope that there is a more elegant, simple, and robust method for dealing with the issues described in this post than the one that I present herein. My method is a rather ugly kludge that relies on undocumented features of SQL Server and is not nearly as parallelizable as I would like. If you are aware of a better method (which I hope exists), please don't hesitate to post it in the comments. Until a better method is posted, I invite you to use and/or learn from the method presented in this post.

Background

Consider an SQL Server 2005 database which is published for merge replication from a single publisher with multiple subscribers. The database contains 2 tables which we are considering: Forms and InboxForms. Forms contains some sort of form data and InboxForms references all forms which are present in a user's "inbox". Each of the tables contains an INT IDENTITY primary key column and several other columns of data that are not relevant to the problem at hand. The publication is filtered based on the Forms that each user is able to view (determined by some separate mechanism not described here). When a new row is inserted into Forms, a trigger is used to route the forms into the appropriate inbox(es).

The Problem

The routing can not occur (exclusively) at the subscribers, because the filter for the subscriber will not necessarily include user information for the recipient of the form and the form can not be placed into InboxForms if it recipient user does not exist on the subscriber. So, the trigger must run on the publisher during synchronization when inserts are performed by the merge agent (i.e. the trigger must not be marked NOT FOR REPLICATION). However, in this configuration, when the merge agent runs, the following error message is produced:

Msg 545, Level 16, State 1, Line 3
Explicit value must be specified for identity column in table 'InboxForms' either when IDENTITY_INSERT is set to ON or when a replication user is inserting into a NOT FOR REPLICATION identity column.

The problem is that the INT IDENTITY column in InboxForms was marked NOT FOR REPLICATION when the publication was created in order to facilitate automatic identity range management, which is described in the Replicating Identity Columns article in the SQL Server Books Online. NOT FOR REPLICATION behaves very similarly to IDENTITY_INSERT (as hinted at in the error message), such that when a row is inserted by the merge agent, the ideneity seed value is not incremented and the value of the identity column must be explicitly specified. Note, however, that it is not the same mechanism as IDENTITY_INSERT, so changing IDENTITY_INSERT in the trigger will not remove the requirement for explicitly specified identity values.

The Solution

One method to solve this problem is to disable NOT FOR REPLICATION, as suggested in KB908711 (which specifically addresses this issue). However, using this option will interfere with automatic identity range management, since the identity values generated on the subscribers can not be copied to the publisher, and other steps will need to be taken to manually manage identity values. For me, this was an unacceptably high price to pay and another solution was required.

A solution which does not interfere with automatic identity range management is to calculate values for the identity columns and explicitly specify those values when they are required. In order to accomplish this, understanding several features of T-SQL is required: In order to determine when the values are required, the trigger needs to test if it is being run from the merge replication agent. This can be done by testing for the 'replication_agent' SESSIONPROPERTY. In order to determine appropriate values for the identity column, use IDENT_CURRENT and IDENT_INCR. Note that using the maximum value for the identity column is not necessarily correct because the maximum identity range will not necessarily be allocated to the publisher. DBCC CHECKIDENT can be used to update the identity seed value (which is not affected by explicitly inserted identity values).

One other complicating factor in our implementation is that there is no way to atomically insert explicit identity values and update the identity seed value. Therefore, locking is required to prevent multiple connections from simultaneously updating the values and causing collisions. (Or collision errors must be caught and retried) In the following implementation, an exclusive table lock is acquired which prevents any inserts from occurring on the table when the trigger is running. This is a serious performance problem as it prevents any other operations on the locked table from completing while the trigger is executing. Keep this in mind when designing the queries that will run while the lock is held.

Now, without further ado, here's the trigger:


ALTER TRIGGER TR_RouteForms
ON dbo.Forms
AFTER INSERT
AS
BEGIN
    -- Client isn't expecting routing counts from their insert
    SET NOCOUNT ON;

    IF SESSIONPROPERTY('replication_agent') <> 0
    BEGIN
        -- Running from the replication agent
        -- Need explicit value for NOT FOR REPLICATION IDENTITY columns

        -- Use transaction to limit lock scope
        BEGIN TRAN
            -- Variables for IDENT_CURRENT and IDENT_INCR, required
            -- because DBCC CHECKIDENT syntax won't support nested parens
            DECLARE @Ident INT, @Incr INT;

            -- RowCnt used to preserve @@ROWCOUNT
            DECLARE @RowCnt INT;

            -- Must acquire exclusive lock on InboxForms to prevent other
            -- inserts (which would invalidate the identity and cause
            -- collisions in the identity column).
            -- Select into variable to prevent resultset going to client
            -- WHERE clause quickly evaluated, returns small (empty) result
            DECLARE @Dummy INT;
            SELECT @Dummy = InboxFormID
            FROM InboxForms WITH (TABLOCK, XLOCK, HOLDLOCK)
            WHERE InboxFormID = 0;

            -- Perform the form routing (inserts into InboxForms)
            SET @Ident = IDENT_CURRENT('InboxForms');
            SET @Incr  = IDENT_INCR('InboxForms');
            INSERT INTO InboxForms (InboxFormID, FormID, ...)
            SELECT @Ident + @Incr * ROW_NUMBER() OVER (ORDER BY FormID) AS InboxFormID, FormID, ...
            FROM inserted
            WHERE ...routing criteria...
            SET @RowCnt = @@ROWCOUNT;
            IF @RowCnt > 0
            BEGIN
                -- At least 1 form was routed, update the identity seed value
                -- Note:  Can't use MAX(InboxFormID) since publisher may not
                -- have been allocated the maximum identity range
                SET @Ident = @Ident + @Incr * @RowCnt;
                DBCC CHECKIDENT (InboxForms, RESEED, @Ident)
                    WITH NO_INFOMSGS;
            END
        COMMIT TRAN
    END
    ELSE
    BEGIN
        -- NOT running from the replication agent
        -- Can insert normally into NOT FOR REPLICATION IDENTITY columns

        -- Perform the form routing (inserts into InboxForms)
        INSERT INTO InboxForms (InboxFormID, FormID, ...)
        SELECT @Ident + @Incr * ROW_NUMBER() OVER (ORDER BY FormID) AS InboxFormID, FormID, ...
        FROM inserted
        WHERE ...routing criteria...
    END
END
 
Posted by Kevin Locke in SQL Server at 20:34 | Comments (0) | Trackbacks (0)

Friday, June 18. 2010

LAN Party version 1.1

After having so much fun with the LAN for Kids event we decided to make the event a permanent fixture.  The next LAN will be held on Friday August 6th at the Bozeman Library.  The event is now free ($5 if you want to reserve a seat)!  For more information check out our new site: http://www.digitalenginesoftware.com/lan/ or join our Facebook group .
Posted by Mike Archer at 23:33 | Comments (0) | Trackbacks (0)

Thursday, June 10. 2010

Non-strongly typed attributes in ASP.NET

Quick Note: Upon encountering the following error:
Type 'ClassName' does not have a public property named 'propertyname'.
I realized that I had no understanding of how to support non-strongly typed (i.e. non-property) attributes on a custom server control. The answer was simple: Implement IAttributeAccessor.
Posted by Kevin Locke in ASP.NET at 15:10 | Comments (0) | Trackbacks (0)
(Page 1 of 4, totaling 49 entries) » next page

Quicksearch

Syndicate This Blog

XML RSS 1.0 feed
XML RSS 2.0 feed
ATOM/XML ATOM 1.0 feed

Authors

XML Kevin Locke
XML Mike Archer
XML Peter Nix

All authors

Show tagged entries

xml java

Archives

September 2010
August 2010
July 2010
Recent...
Older...

Blog Administration

Open login screen

© Copyright 2006, nerdwg.org design by Luka Cvrk, port for s9y by nerdwg.org