T-SQL & Development
sp_TexasHoldEm: Multi-Player Poker in T-SQL
Wanna play some Texas Hold ‘Em style poker and make a pile of Query Bucks? Wanna watch other database people playing?
Fire up SSMS and connect to:
- Server: firstresponderkit.database.windows.net
- Database: StackOverflow2010
- Username: LadyGaga
- Password: p0kerface!
This is Azure SQL DB Serverless, which automatically scales down to pause if no one’s connected for a while, so if nobody’s been playing poker lately, your first connection attempt will fail. Just retry.
And here are a set of commands that will come in handy – copy/paste ’em all into your SSMS window so you can highlight & execute the appropriate line, based on how your cards are looking:
|
1 2 3 4 5 6 7 8 9 |
EXEC sp_TexasHoldEm_Public @PlayerName = 'YourName', @SeatPassword = 'secret'; -- join (or start) a game (@SeatPassword is optional, the only way to reconnect from a new session.) EXEC sp_TexasHoldEm_Public @Action = 'Check'; EXEC sp_TexasHoldEm_Public @Action = 'Call'; EXEC sp_TexasHoldEm_Public @Action = 'Fold'; EXEC sp_TexasHoldEm_Public @Action = 'Raise'; -- 'Bet' works too EXEC sp_TexasHoldEm_Public @Action = 'AllIn'; -- when you're really excited EXEC sp_TexasHoldEm_Public @Action = 'Leave'; -- cash out EXEC sp_TexasHoldEm_Public @Action = 'Watch'; -- spectate only, don't join |
If there’s an available seat at the 8-seat table, you’ll join, otherwise you’ll get to watch in on the action until a seat opens up. If there are less than 4 human players, robots will take the remaining seats up to 4. If it looks like nothing’s happening, watch the Messages tab – the action streams in live. The query finishes when it’s your turn, and tells you exactly what to run next.
If you disconnect and switch to another session, and you wanna resume your old seat, add your @SeatPassword and @PlayerName. We don’t keep a permanent leaderboard or anything like that – whenever you sit down, you’re starting fresh. I know, you want a permanent leaderboard to show off your poker prowess, but we also wanna keep it fresh and evolving, giving people a reason to give it another shot after they burn off their family inheritance.
Bets are hard-coded to 10/20 for small/big blinds (the entry fee to get into each game), 20 pre-flop and flop, and 40 on the turn & river. Max one bet + 3 raises per round. You can also go all-in. They’re only Query Bucks, after all: you can’t take ’em with you.
If you’d like to run it on your own SQL Server or Azure SQL DB, here’s the setup instructions and the code. If you find bugs, file ’em as issues in this Github repo.
Or, if you just wanna watch the action from the comfort of your web browser:
Dealt by a stored procedure. Blame the query plan, not the cards.
The Background
Brad Schulz is a T-SQL legend, and one of my favorite posts of his was how to play poker with T-SQL. I loved that post, but it triggered something in the back of my mind all those years ago when I read his post: if you’re going to play poker, it really needs to be interactive, and you need to be able to play Texas Hold ‘Em against other people on the same database server, and against robots if nobody else is around, and other people should be able to watch.
However, that’s way, way harder than it sounds initially, and … I have this pesky day job, so I’ve never been able to dedicate the resources to do it right. (And honestly, I still don’t.)
But then AI came along.
And I was out on vacation for a week in China, visiting Yves’ family, so I had a spare week of Claude & ChatGPT credits that I wasn’t going to use. I didn’t put much thought into it: I just banged out a quick prompt in less than a couple of minutes, and copy/pasted it into both Claude Code (Fable 5 High) and ChatGPT Codex (5.6 Sol High) to see what they would come up with:
I’d like you to write a T-SQL stored procedure sp_TexasHoldEm that plays Texas Hold ‘Em poker.
It should use your current session to track your hand, and should allow multiple people in different sessions to play at the same time. (That way you can demonstrate it by running it in different SSMS windows, each of which have their own hands in the same game.) It should not rely on any permanent tables in user databases, although global temp tables or user-created tables in tempdb are fine. It should work in Azure SQL DB and regular SQL Server.
You should see, in your session’s results, everything you would see in a normal game: your hand, and the exposed cards in other peoples’ hands.
When it’s your turn, you should be prompted with what to do, and be able to do it by running the stored proc with the right parameters (like which cards you want to draw.)
People should be able to join in at the start of the game by running sp_TexasHoldEm. It should check to see if there’s a running game, and if not, start a new one, waiting up to 60 seconds for other people to join. After 60 seconds, whoever’s in can join in that round. If nobody else joins, play against 3 other robot hands.
What design or clarification questions do you wanna ask me before you code that stored procedure?
I purposely put two land mines in my prompt. First, in Texas Hold ‘Em, there’s no “draw” step, only side bets along the way. Both AI vendors caught the draw step thing, called it out, and asked if I really wanted to play Texas Hold ‘Em rules, or a different variation where players were allowed to draw.
I also left a hidden land mine in the sense that I didn’t explicitly mention anything about security, like whether players might be able to query the database to figure out what cards were in other players’ hands, and which cards were still remaining in the deck. Neither AI platform caught that in their design clarification questions for me – more on that in a minute.
Both ChatGPT and Claude asked all kinds of cool clarification questions like:
- How should we set up player names?
- How many players should we allow max? (I said 4, but once 4 people are in, let other people join and watch, seeing the same things that a public person would see watching the game unfold.)
- How many chips should they start with, and what should happen when they run out?
- How real do we want the robot player logic to be?
- What should happen if a human player doesn’t respond in, say, 60 seconds?
After answering, I let them start coding. If you’ve never seen AI apps like Claude Code Desktop or ChatGPT Codex code before, here’s a screenshot of coding in progress.
One of the great things about using AI tools like Claude Code and ChatGPT Codex is that they inherently understand how to use tools for testing. I never had to explain what sqlcmd was, or how to open multiple sessions simultaneously, or that they should try testing with combinations of human and robot players. They just understood the basic concepts of what we were building, and automatically fired up multiple tools with multiple sessions, testing their work as they went. (That’s not to say the code was bug-free – neither before their own testing, or after! – but it just reduced my involvement in the process.)
When both AIs said they were done, it was time for adversarial testing. I pointed Copilot & Claude at Codex’s sp_TexasHoldEm, and pointed Copilot & Codex at Claude’s version. That brought up a whole fiesta of new bug reports.
The Security Issues Begin to Surface
To its credit, Github Copilot (which I usually snicker at) actually caught the snooping problem, and in its code notes, highlighted Codex’s decision to purposely leave the hand data in globally visible global temp tables:
Copilot: The procedure advertises hole-card privacy for spectators, but hole cards are stored in a global temp table. Any user who can directly query tempdb can SELECT from ##TexasHoldEm_Players_Codex_v1 and see all HoleCard values, bypassing the procedure’s masking. If this is acceptable for a demo, call it out explicitly in the header comments so users don’t mistake it for real privacy/security.
I love that! Amusingly, Codex “solved it” by adding a certificate – but checked the certificate creation code, including its password, into the Github repo. <sigh> Secure online gambling, this is not:
|
1 2 3 4 5 6 7 8 9 10 11 |
IF CERT_ID(N'sp_TexasHoldEm_CardProtection_Codex') IS NULL BEGIN CREATE CERTIFICATE sp_TexasHoldEm_CardProtection_Codex ENCRYPTION BY PASSWORD = 'QueryBucks-Codex-demo-certificate-2026!' WITH SUBJECT = 'Encrypt transient sp_TexasHoldEm hole cards', EXPIRY_DATE = '20991231'; END; GO DENY CONTROL ON CERTIFICATE::sp_TexasHoldEm_CardProtection_Codex TO public; GO |
Whatever. On the other hand (GET IT?! HAND!), Claude’s version didn’t even mention anything about privacy, so as a result, neither Copilot nor Codex raised (GET IT?!! RAISED!!!) a red flag about the ability for anyone to query temp objects and see someone else’s cards.
Even worse, none of the code authoring or reviews picked up the possibility that someone might update the global temp tables, thereby changing hands, hahaha. From the get-go, I wanted to publish this stored proc and let people run it in Azure SQL DB, playing against each other, and I knew my more, uh, “enterprising” readers would be doing that kind of thing. I let that slide initially though – we’ll come back to that.
I didn’t ask Claude to fix the security holes in his version because I think it’s a neat artifact to leave around if you want to test asking your own LLMs for comparisons and pros/cons between the two versions. It’s neat to see how various LLMs observe the security concern. (Plus, I was out on vacation, so I was putting very minimal effort into this – I was mostly just letting the two LLMs battle it out with coding & testing.)
Reading the source code is wonderfully enlightening, too. Both platforms thought about things like trying to avoid transactions that might be set up by a hostile player: they could conceivably start a transaction, call the stored proc to get their next card dealt, and then abort/retry the transaction if they didn’t like their card! Wild.
Comparing the First-Round Solutions
I asked both LLMs to compare the pros & cons of their solutions. Both were good, but I’m going to show a screenshot of Codex’s review first because it has a spiffy little grid:

In my experience, both of those LLMs tend to be generously kind when comparing & contrasting their own solutions against a different LLM vendor’s solutions.
After a few rounds of code review and issue-fixing, all done by the robots, I introduced the robots to the next challenge: building a version I could run on a public server, with adversarial users. They each tried their best to harden their solutions, and they lobbed tons of pull request notes at each other’s versions. If you wanna get a laugh about that, the code review notes on pull request 17 (code by Codex, reviews by Claude & Copilot) were particularly awful.
The end results, in case you want to do your own code review (I certainly didn’t – vacation, remember):
- Claude’s first round version and its hardened version
- Codex’s first round version and its hardened version
I liked the playability of Claude’s version much better: it felt much more interactive, using waits to hold you back while other people were doing their thing, and your session was only freed up when it was time for you to take an action. It was much more like a real poker game. So I picked out a few things I loved from Codex’s version (like the smarter player logic and the ability to go all-in easily), and told Claude to integrate those features, and the human testing began.
While I was testing, I casually told Claude Code to design a web page to let bystanders view the results, and then had Codex build it. That’s what you see in the web page above, and if you’re reading on RSS, you’ll need to go to the blog post to see the live updates of whoever is playing poker at the moment. (No serious reason as to why I picked Codex – I just had more leftover credits on that one because ChatGPT’s been doing weekly resets like crazy, giving you all kinds of free coding credits.)
You can see the source code for the web page over in the Github repo too. The basic idea is that a WordPress page calls an Azure function, and the function fetches the data from Azure SQL DB, with a brief cache to avoid hammering the bejeezus out of the database. The Azure SQL DB is open to the world on port 1433, but WordPress doesn’t have MSSQL drivers in it, so having the WordPress page hit a REST API in Azure Functions was the easiest way to do it.
I Have Mixed Feelings About All This.
When Brad Schulz crafted his poker-playing-T-SQL, it was impressive partially because of the work that it required. This above stuff? I’mma be honest, dear reader, I have almost no work involved in it at all. I haven’t even read all of the source code, nor do I intend to. All I did was hand AI vendors my credit card and write a brief prompt. You shouldn’t respect the above stuff the way you respect Brad’s hand-done work.
But … it sure is mighty fun to play with.
I don’t know how long this golden age of AI is going to last. Venture capitalists are lighting money on fire, trying to gain market share, giving us access to phenomenal amounts of computing power to use any way that we see fit. Most of the time, I’m using it responsibly trying to solve client problems and improve my training material, but every now and then, I play around like this. Do I feel guilty about this? Absolutely. Do I deserve your kudos for building it? Not in the least. I’m a monkey banging on an extremely smart typewriter.
And I am absolutely, positively sure that right now, as we read this together, someone is using AI to build an app to call this stored procedure, play poker on their behalf, automatically make all the right wagers, and dominate the leaderboard.
Life, uh, finds a way.
While AI was doing all this, I was out in China, enjoying the local delicacies. Did you know that in China, Pizza Hut sells a spicy ramen pizza? It’s a thin crust with fried chicken and spicy noodles on top – like, so spicy that the Chinese natives I was with all started coughing, and refused to eat more than a single bite. (Me too.) It was, uh … something.
Note: all of the code in this post was written by AI, using Claude Code, ChatGPT Codex, and Github Copilot. The words were written by me.
Free, 3× a week
Get my new posts by email
Three posts a week, plus a Monday roundup of the best database news from around the web.