diff --git a/P3/P3Client.class.st b/P3/P3Client.class.st index f88e5fd..14e5886 100644 --- a/P3/P3Client.class.st +++ b/P3/P3Client.class.st @@ -695,6 +695,8 @@ P3Client >> prepare: query named: queryName [ createPreparedStatementNamed: queryName withParameters: parameterDescriptions andFields: rowDescriptions. + + statement source: query. self logPreparedStatement: statement query: query ]. @@ -794,6 +796,7 @@ P3Client >> query: query [ ^ self critical: [ self withConnection: [ + properties at: #sql_source put: query. self ensureConnected; writeQueryMessage: query; @@ -905,10 +908,13 @@ P3Client >> runExtendedQueryResult: descriptions [ out nextPut: (self processDataRowUsing: descriptions). self readMessage ] ]. - result := P3Result descriptions: descriptions - rows: rows - message: (self converter asciiCStringFrom: message readStream). - + result := P3Result + descriptions: descriptions + data: rows + results: (self converter asciiCStringFrom: message readStream). + + result source: (properties at: #sql_source ifAbsent: nil). + self logResult: result. ^ result @@ -950,6 +956,7 @@ P3Client >> runQueryResult [ self readMessage tag = $S ifTrue: [ self processParameterStatus: message readStream; readMessage ]. message tag = $Z ] whileFalse. + result source: (properties at: #sql_source ifAbsent: nil). self logResult: result. ^ result ] @@ -1054,6 +1061,11 @@ P3Client >> setSSL [ settings at: #ssl put: true ] +{ #category : #private } +P3Client >> setSource: sql [ + properties at: #sql_source put: sql +] + { #category : #'error handling' } P3Client >> signal: exceptionClass using: info [ | exception | diff --git a/P3/P3FormattedStatement.class.st b/P3/P3FormattedStatement.class.st index b1b1297..613e1ea 100644 --- a/P3/P3FormattedStatement.class.st +++ b/P3/P3FormattedStatement.class.st @@ -22,7 +22,7 @@ Class { #superclass : #Object, #instVars : [ 'client', - 'sql' + 'source' ], #category : #'P3-Core' } @@ -32,7 +32,7 @@ P3FormattedStatement >> bind: arguments [ "Build and return the actual SQL statement by splicing in the arguments for all placeholders in the template" ^ String streamContents: [ :out | | readStream | - readStream := sql readStream. + readStream := self source readStream. [ readStream atEnd ] whileFalse: [ | char | (char := readStream next) = $$ ifTrue: [ | index argument | @@ -202,7 +202,14 @@ P3FormattedStatement >> queryAll: argumentsCollection [ ^ argumentsCollection collect: [ :each | self query: each ] ] +{ #category : #accessing } +P3FormattedStatement >> source [ + "Return my SQL source" + + ^ source +] + { #category : #initialization } P3FormattedStatement >> sql: anSQLTemplateString [ - sql := anSQLTemplateString + source := anSQLTemplateString ] diff --git a/P3/P3PreparedStatement.class.st b/P3/P3PreparedStatement.class.st index 967d920..9269e0b 100644 --- a/P3/P3PreparedStatement.class.st +++ b/P3/P3PreparedStatement.class.st @@ -40,7 +40,8 @@ Class { 'client', 'name', 'paramDescriptions', - 'fieldDescriptions' + 'fieldDescriptions', + 'source' ], #category : #'P3-Core' } @@ -105,6 +106,7 @@ P3PreparedStatement >> execute: inputRow [ "Execute this SQL query with inputRow as the ordered collection of parameters. Assume no rows will be returned." + client setSource: self source. self bindStrings: inputRow. self writeExecuteMessage: 0. client writeSyncMessage. @@ -120,6 +122,7 @@ P3PreparedStatement >> executeBatch: inputRows [ inputRows isEmpty ifTrue: [ ^ #() ]. + client setSource: self source. inputRows do: [ :eachRow | self bindStrings: eachRow. self writeExecuteMessage: 0 ]. @@ -173,6 +176,7 @@ P3PreparedStatement >> query: inputRow [ "Execute this SQL query with inputRow as the ordered collection of parameters. Answer a P3Result object with the field descriptions and rows." + client setSource: self source. self bindStrings: inputRow. self writeExecuteMessage: 0. client writeSyncMessage. @@ -188,6 +192,7 @@ P3PreparedStatement >> queryAll: inputRows [ inputRows isEmpty ifTrue: [ ^ #() ]. + client setSource: self source. inputRows do: [ :eachRow | self bindStrings: eachRow. self writeExecuteMessage: 0 ]. @@ -196,6 +201,18 @@ P3PreparedStatement >> queryAll: inputRows [ ^ client runExtendedQueryResults: fieldDescriptions ] +{ #category : #accessing } +P3PreparedStatement >> source [ + "Return my SQL source" + + ^ source +] + +{ #category : #accessing } +P3PreparedStatement >> source: anSQLTemplateString [ + source := anSQLTemplateString +] + { #category : #'input/output' } P3PreparedStatement >> writeCloseMessage: aName type: aChar [ diff --git a/P3/P3Result.class.st b/P3/P3Result.class.st index 8efff9f..ef60146 100644 --- a/P3/P3Result.class.st +++ b/P3/P3Result.class.st @@ -1,7 +1,7 @@ " I am P3Result, I encapsulate the result from a PostgreSQL query. -I hold 3 things: +I hold 4 things: - results - the command completion tags, a String (singular if there was only one query) or a collection of Strings (if there were multiple queries) in the form of 'SELECT 100' @@ -9,6 +9,8 @@ I hold 3 things: - data - a collection of records with each field value converted to objects, nil if there is no data +- source - the SQL source string that generated me, nil if unavailable + Even if there are multiple queries, there can only be one stream of records. Most of the time, results is singular. In the case of multiple queries, there will be multiple results (an array of results), one for each query. However, only the last record stream will be in the data and descriptions. " @@ -18,19 +20,19 @@ Class { #instVars : [ 'results', 'descriptions', - 'data' + 'data', + 'source' ], #category : #'P3-Core' } { #category : #'instance creation' } -P3Result class >> descriptions: descriptions rows: aRowArray message: aString [ - +P3Result class >> descriptions: descriptions data: aRowArray results: aString [ ^ self new - descriptions: descriptions; - data: aRowArray; - results: aString; - yourself + descriptions: descriptions; + data: aRowArray; + results: aString; + yourself ] { #category : #'private-accessing' } @@ -134,6 +136,11 @@ P3Result >> hasResults [ ^ results notNil ] +{ #category : #testing } +P3Result >> hasSource [ + ^ source notNil +] + { #category : #accessing } P3Result >> lastResult [ "Return the SQL query execution result, or the last one if there are multiple results. @@ -244,6 +251,25 @@ P3Result >> rowCountFromCommandResultTag: string [ ^ ($ split: string) last asInteger ] +{ #category : #convenience } +P3Result >> rows [ + "Return the rows that I hold, also known as my data" + + ^ data +] + +{ #category : #accessing } +P3Result >> source [ + "Return the SQL source that generated me (if available)" + + ^ source +] + +{ #category : #accessing } +P3Result >> source: sqlString [ + source := sqlString +] + { #category : #accessing } P3Result >> totalRowCount [ "Return the total integer count of the number of record returned or modified in all results"