samadhiweb

smalltalk programming for the web



Glorp with PostgresV2 on Pharo 4

3 April 2015

Using the Pharo v40592 image with which I had verified NBSQLite3 for Glorp, in this blog post I go through doing the same with the PostgresV2 pure-Smalltalk database driver.

Outside of Smalltalk, create the database 'sodbxtest', user 'sodbxtest' with password 'sodbxtest':

# su postgres -c psql
postgres=# create role sodbxtest with password 'sodbxtest' login;
CREATE ROLE 
postgres=# create database sodbxtest;
CREATE DATABASE
postgres=# \q
#

In Smalltalk, firstly, install PostgresV2:

Gofer it
    smalltalkhubUser: 'PharoExtras' 
    project: 'PostgresV2';
    package: 'ConfigurationOfPostgresV2';
    load.
((Smalltalk at: #ConfigurationOfPostgresV2) project version: '2.4') load.

Open Test Runner and runs the PostgresV2 tests. On my Linux Mint machine, using a vanilla PostgreSQL 9.3 installation, 23 of 24 tests passed, and TestPGConnection>>#testNotify2 erred.

Now that we know the PostgresV2 driver can talk to our database, using the Monticello browser, open the PostgresV2 repository and load the package GlorpDriverPostgreSQL. Here I had to edit NativePostgresDriver>>connectionArgsFromCurrentLogin: to comment out the second last line:

connectionArgs clientEncoding: aLogin encodingStrategy asSymbol

This is because GlorpDatabaseLoginResource class>defaultPostgreSQLLocalLogin does not specify encodingStrategy, meaning it is nil and will respond to #asSymbol with DNU.

Next, in a playground, execute the following:

GlorpDemoTablePopulatorResource invalidateSetup.
GlorpDatabaseLoginResource
    defaultLogin: GlorpDatabaseLoginResource defaultPostgreSQLLocalLogin

Open Test Runner and run the Glorp tests.

Tested on Linux Mint 17.

Scaling Web Applications on PostgreSQL

29 March 2014

Konstantin Gredeskoul, CTO of Wanelo, gave a great talk entitled "12-Step Program for Scaling Web Applications on PostgreSQL"; slides here. Wanelo uses Rails, and as the title says, the talk is heavily focused on PostgreSQL, but many of the points should be applicable to Smalltalk web programming.

Hat tip to Josh Berkus.

Seven Databases for Pharo and Squeak

7 December 2013

I'm reading the book Seven Databases in Seven Weeks by Eric Redmond and Jim Wilson. The databases covered are PostgreSQL, Riak, HBase, MongoDB, CouchDB, Neo4J and Redis.

There are several Pharo/Squeak libraries for PostgreSQL:

Riak:

HBase runs on JVM. It supports a RESTful HTTP API, Thrift, and a Java API. The first is probably the easiest way to write a Smalltalk interface.

MongoDB:

  • Estaban Lorenzano's Voyage is an object persistence layer that works with MongoDB.
  • MongoTalk, by Kent Beck and others.

CouchDB:

Neo4J is a graph database. It is provides a RESTful API. I've not played with Neo4J, but I'd imagine the Smalltalk environment, and by extension any Smalltalk object persistence mechanism, make up a graph database. Probably speaking from ignorance here, but I'm not sure what interest a Smalltalk programmer will have in a graph database written in Java. :-)

Finally, there is Redis Client by Mike Hale and others.

I haven't finished the book, but so far I haven't seen any discussion on authentication or security of these HTTP-speaking NoSQL databases. If the database is lacking authentication or SSL, and if your threat model covers that, probably the easiest is to put these behind a proxy. And, for database and other such connectivity from the Smalltalk client, I suggest SpsSplitPasswordStore.

PostgresV3 Protocol State Machine using GraphViz

28 April 2013

In the previous post I wrote about visualizing the PostgresV3 pure Smalltalk implementation of the PostgreSQL v3 wire protocol. That "visualization" was in text, which is not nearly as visual as seeing the protocol state machine graphically.

In this post, let's use GraphViz to do that. Building on the code previously written:

| skip states statesMap gv |

skip := #('PG3NoticeResponse' 'PG3NotificationResponse' 'PG3ParameterStatus').
states := OrderedCollection new.

PG3ServerState createStateGraph valuesDo: [ :inst |
  inst transitions keysAndValuesDo: [ :k :v |
    (skip includes: k asString) ifFalse: [
      states add: (Array with: inst with: k with: v first with: v second) ]]].

states do: [ :ea |
  Transcript show: 'From ', ea first name; 
    show: ' on ', ea second asString.
  ea fourth ifNotNil: [ Transcript show: ' perform #', ea fourth ].
  Transcript show: ' goto ', ea third name; cr; flush ].

statesMap := Dictionary new.
states do: [ :ea |
  (statesMap includesKey: ea first name) ifFalse: [
    statesMap at: ea first name put: OrderedCollection new ].
  (statesMap at: ea first name) add: ea ].

gv := GraphViz new.
gv beDirected;
  name: 'PostgresV3 Protocol State Machine';
  add: #graph with: { #overlap -> #scale. #concentrate -> #true };
  add: #edge with: { #arrowsize -> 0.5 }.
	
statesMap keysAndValuesDo: [ :k :v |
  gv add: k with: { #shape -> #box. #fontsize -> 10 }.
  v do: [ :ea |
    gv add: ea third name with: { #shape -> #box. #fontsize -> 10 }.
    gv add: k -> ea third name with: { #label -> ea second asString. #fontsize -> 8 } ]].

gv openInWindow.

PostgresV3 Protocol State Machine

28 April 2013

PostgresV3 is a pure Smalltalk implementation of the PostgreSQL v3 wire protocol (and a database access API) by Levente Uzonyi and Balazs Kosi.

In code, the protocol is implemented as a state machine, created by "PG3ServerState createStateGraph", which invokes methods such as this:

initializingBackendStateDescription

(self state: #InitializingBackend)
  on: PG3BackendKeyData
  connectionDo: #registerBackendKeyData:
  goto: #InitializingBackend;

  on: PG3ReadyForQuery
  connectionDo: #readyForQuery:
  goto: #WaitingForQuery

"on:connectionDo:goto:" looks like this:

on: aPG3MessageClass connectionDo: selector goto: aSymbol
  transitions at: aPG3MessageClass put: { (self state: aSymbol). selector }

I wanted to map out all state transitions, to better visualize the protocol flow. This is done by walking through the "transitions" inst-var of each instance of PG3ServerState:

| skip states |

skip := #('PG3NoticeResponse' 'PG3NotificationResponse' 'PG3ParameterStatus').
states := OrderedCollection new.

PG3ServerState createStateGraph valuesDo: [ :inst |
  inst transitions keysAndValuesDo: [ :k :v |
    (skip includes: k asString) ifFalse: [
      states add: (Array with: inst with: k with: v first with: v second) ]]].

states do: [ :ea |
  Transcript show: 'From ', ea first name; 
    show: ' on ', ea second asString.
  ea fourth ifNotNil: [ Transcript show: ' perform #', ea fourth ].
  Transcript show: ' goto ', ea third name; cr; flush ].

Here's the output:

From InitializingBackend on PG3ReadyForQuery perform #readyForQuery: goto WaitingForQuery
From InitializingBackend on PG3BackendKeyData perform #registerBackendKeyData: goto InitializingBackend
From GotDataRow on PG3ErrorResponse perform #handleError: goto GotErrorResponseDuringSimpleQuery
From GotDataRow on PG3CommandComplete perform #commandComplete: goto GotCommandComplete
From GotDataRow on PG3DataRow perform #dataRow: goto GotDataRow
From GotErrorResponseDuringSimpleQuery on PG3ReadyForQuery perform #readyForQuery: goto WaitingForQuery
From GotEmptyQueryResponse on PG3ReadyForQuery perform #readyForQuery: goto WaitingForQuery
From GotEmptyQueryResponse on PG3ErrorResponse perform #handleError: goto GotErrorResponseDuringSimpleQuery
From Querying on PG3ErrorResponse perform #handleError: goto GotErrorResponseDuringSimpleQuery
From Querying on PG3CommandComplete perform #commandComplete: goto GotCommandComplete
From Querying on PG3RowDescription perform #rowDescription: goto GotRowDescription
From Querying on PG3EmptyQueryResponse goto GotEmptyQueryResponse
From Authenticating on PG3AuthenticationMD5Password perform #respondToAuthenticationMD5PasswordRequest: goto AuthenticatingWithMD5
From Authenticating on PG3AuthenticationOkMessage goto InitializingBackend
From AuthenticatingWithMD5 on PG3AuthenticationOkMessage goto InitializingBackend
From GotCommandComplete on PG3ReadyForQuery perform #readyForQuery: goto WaitingForQuery
From GotCommandComplete on PG3ErrorResponse perform #handleError: goto GotErrorResponseDuringSimpleQuery
From GotCommandComplete on PG3CommandComplete perform #commandComplete: goto GotCommandComplete
From GotCommandComplete on PG3RowDescription perform #rowDescription: goto GotRowDescription
From GotRowDescription on PG3ErrorResponse perform #handleError: goto GotErrorResponseDuringSimpleQuery
From GotRowDescription on PG3CommandComplete perform #commandComplete: goto GotCommandComplete
From GotRowDescription on PG3DataRow perform #dataRow: goto GotDataRow