Object subclass: #JdmColumn instanceVariableNames: 'table name size type flags decimalPlaces ' classVariableNames: '' poolDictionaries: '' category: 'Mysql-Driver'! !JdmColumn methodsFor: 'testing' stamp: 'jb 2/28/1999 17:52'! hasFlag: aFlag ^(self flags bitAnd: aFlag) > 0! ! !JdmColumn methodsFor: 'testing' stamp: 'jb 2/28/1999 17:52'! isAutoIncrement ^self hasFlag: self class autoIncrementFlag! ! !JdmColumn methodsFor: 'testing' stamp: 'jb 2/28/1999 17:52'! isBinary ^self hasFlag: self class binaryFlag! ! !JdmColumn methodsFor: 'testing' stamp: 'jb 2/28/1999 17:53'! isBlob ^self hasFlag: self class blobFlag! ! !JdmColumn methodsFor: 'testing' stamp: 'jb 2/28/1999 17:53'! isEnumeration ^self hasFlag: self class enumFlag! ! !JdmColumn methodsFor: 'testing' stamp: 'jb 2/28/1999 17:53'! isMultipleKey ^self hasFlag: self class multipleKeyFlag! ! !JdmColumn methodsFor: 'testing' stamp: 'jb 2/28/1999 17:53'! isNotNull ^self hasFlag: self class notNullFlag! ! !JdmColumn methodsFor: 'testing' stamp: 'jb 2/28/1999 17:53'! isPrimaryKey ^self hasFlag: self class primaryKeyFlag! ! !JdmColumn methodsFor: 'testing' stamp: 'jb 2/28/1999 17:53'! isTimestamp ^self hasFlag: self class timestampFlag! ! !JdmColumn methodsFor: 'testing' stamp: 'jb 2/28/1999 17:53'! isUniqueKey ^self hasFlag: self class uniqueKeyFlag! ! !JdmColumn methodsFor: 'testing' stamp: 'jb 2/28/1999 17:53'! isZerofill ^self hasFlag: self class zerofillFlag! ! !JdmColumn methodsFor: 'accessing' stamp: 'jb 2/28/1999 17:53'! decimalPlaces ^decimalPlaces! ! !JdmColumn methodsFor: 'accessing' stamp: 'jb 2/28/1999 17:53'! flags ^flags! ! !JdmColumn methodsFor: 'accessing' stamp: 'jb 2/28/1999 17:53'! name ^name! ! !JdmColumn methodsFor: 'accessing' stamp: 'jb 2/28/1999 17:53'! size ^size! ! !JdmColumn methodsFor: 'accessing' stamp: 'jb 2/28/1999 17:53'! table ^table! ! !JdmColumn methodsFor: 'accessing' stamp: 'jb 2/28/1999 17:54'! type ^type! ! !JdmColumn methodsFor: 'reading' stamp: 'jb 2/28/1999 17:54'! readDecimalPlaces: aReadStream decimalPlaces := aReadStream next asInteger! ! !JdmColumn methodsFor: 'reading' stamp: 'jb 3/3/1999 19:34'! readFlags: aReadStream "Currently the size of both the flags field and decimalPlaces field is specified as a sum of the two. I am guessing that the size of the flags is more likely to change than that of the decimalPlaces. Right now I assume that the flags are all bytes but the last and that the last is the decimalPlaces" | ba | ba := (aReadStream next: aReadStream next asInteger - 1) asByteArray. flags := JdmConnection byteArrayAsInteger: ba. ! ! !JdmColumn methodsFor: 'reading' stamp: 'jb 2/28/1999 17:55'! readFrom: aReadStream self readTable: aReadStream; readName: aReadStream; readSize: aReadStream; readType: aReadStream; readFlags: aReadStream; readDecimalPlaces: aReadStream! ! !JdmColumn methodsFor: 'reading' stamp: 'jb 2/28/1999 17:55'! readName: aReadStream name := (aReadStream next: aReadStream next asInteger)! ! !JdmColumn methodsFor: 'reading' stamp: 'jb 3/3/1999 19:33'! readSize: aReadStream " size := (aReadStream next: aReadStream next asInteger) asByteArray asInteger " | ba | ba := (aReadStream next: aReadStream next asInteger) asByteArray. size := JdmConnection byteArrayAsInteger: ba. ! ! !JdmColumn methodsFor: 'reading' stamp: 'jb 2/28/1999 17:55'! readTable: aReadStream table := (aReadStream next: aReadStream next asInteger)! ! !JdmColumn methodsFor: 'reading' stamp: 'jb 3/3/1999 19:34'! readType: aReadStream | ba | ba := (aReadStream next: aReadStream next asInteger) asByteArray. type := JdmConnection byteArrayAsInteger: ba. ! ! "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "! JdmColumn class instanceVariableNames: ''! !JdmColumn class methodsFor: 'constants-types'! blobType ^252! ! !JdmColumn class methodsFor: 'constants-types'! dateType ^10! ! !JdmColumn class methodsFor: 'constants-types'! datetimeType ^12! ! !JdmColumn class methodsFor: 'constants-types'! decimalType ^0! ! !JdmColumn class methodsFor: 'constants-types'! doubleType ^5! ! !JdmColumn class methodsFor: 'constants-types'! enumType ^247! ! !JdmColumn class methodsFor: 'constants-types'! floatType ^4! ! !JdmColumn class methodsFor: 'constants-types'! int24Type ^9! ! !JdmColumn class methodsFor: 'constants-types'! longBlobType ^251! ! !JdmColumn class methodsFor: 'constants-types'! longType ^3! ! !JdmColumn class methodsFor: 'constants-types'! longlongType ^8! ! !JdmColumn class methodsFor: 'constants-types'! mediumBlobType ^250! ! !JdmColumn class methodsFor: 'constants-types'! newDateType ^14! ! !JdmColumn class methodsFor: 'constants-types'! nullType ^6! ! !JdmColumn class methodsFor: 'constants-types'! setType ^248! ! !JdmColumn class methodsFor: 'constants-types'! shortType ^2! ! !JdmColumn class methodsFor: 'constants-types'! stringType ^254! ! !JdmColumn class methodsFor: 'constants-types'! timeType ^11! ! !JdmColumn class methodsFor: 'constants-types'! timestampType ^7! ! !JdmColumn class methodsFor: 'constants-types'! tinyBlobType ^249! ! !JdmColumn class methodsFor: 'constants-types'! tinyType ^1! ! !JdmColumn class methodsFor: 'constants-types'! varStringType ^253! ! !JdmColumn class methodsFor: 'constants-types'! yearType ^13! ! !JdmColumn class methodsFor: 'constants-flags'! autoIncrementFlag ^512! ! !JdmColumn class methodsFor: 'constants-flags'! binaryFlag ^128! ! !JdmColumn class methodsFor: 'constants-flags'! blobFlag ^16! ! !JdmColumn class methodsFor: 'constants-flags'! enumFlag ^256! ! !JdmColumn class methodsFor: 'constants-flags'! multipleKeyFlag ^8! ! !JdmColumn class methodsFor: 'constants-flags'! notNullFlag ^1! ! !JdmColumn class methodsFor: 'constants-flags'! primaryKeyFlag ^2! ! !JdmColumn class methodsFor: 'constants-flags'! timestampFlag ^1024! ! !JdmColumn class methodsFor: 'constants-flags'! uniqueKeyFlag ^4! ! !JdmColumn class methodsFor: 'constants-flags'! unsignedFlag ^32! ! !JdmColumn class methodsFor: 'constants-flags'! zerofillFlag ^64! ! !JdmColumn class methodsFor: 'instance creation'! readFrom: aReadStream ^self new readFrom: aReadStream! ! Object subclass: #JdmConnection instanceVariableNames: 'socket readStream writeStream serverInfo hashesByProtocol responsePacket clientCapabilities connectionSpec packetClass ' classVariableNames: '' poolDictionaries: '' category: 'Mysql-Driver'! !JdmConnection methodsFor: 'closing' stamp: 'jb 2/28/1999 19:26'! close self closeRequest; closeReadStream; closeWriteStream; closeSocket! ! !JdmConnection methodsFor: 'closing' stamp: 'jb 2/28/1999 19:26'! closeReadStream responsePacket := nil. readStream isNil ifFalse: [readStream close]. readStream := nil! ! !JdmConnection methodsFor: 'closing' stamp: 'jb 2/28/1999 19:26'! closeRequest (self requestPacket writeStream) nextPutCommand: (JdmMysqlCommand withCommandNamed: #quit message: ''); flush! ! !JdmConnection methodsFor: 'closing' stamp: 'jb 2/28/1999 19:26'! closeSocket socket isNil ifFalse: [socket close]. socket := nil! ! !JdmConnection methodsFor: 'closing' stamp: 'jb 2/28/1999 19:26'! closeWriteStream writeStream isNil ifFalse: [writeStream close]. writeStream := nil! ! !JdmConnection methodsFor: 'initialize-release' stamp: 'jb 3/2/1999 18:47'! initialize self initializeConnection; initializeUser; initializeDatabase! ! !JdmConnection methodsFor: 'initialize-release' stamp: 'jb 3/3/1999 18:54'! initializeConnection | a | packetClass := JdmInputPacket. a := self class protocolHashes. hashesByProtocol := Dictionary new. hashesByProtocol at: (a at: 1) put: (a at: 2). hashesByProtocol at: (a at: 3) put: (a at: 4). " socket := SocketAccessor newTCPclientToHost: connectionSpec host port: connectionSpec port. " socket := SimpleClientSocket new connectTo: (connectionSpec host) port: (connectionSpec port). socket waitForConnectionUntil: Socket standardDeadline. readStream := SocketReadStream new. readStream socket: socket. readStream stream: (ReadStream on: (String new: 2000)). writeStream := SocketWriteStream new. writeStream socket: socket. writeStream stream: (WriteStream on: (String new: 2000)). " readStream := socket readStream lineEndTransparent. writeStream := socket writeStream lineEndTransparent. " serverInfo := JdmServerInfo on: self. serverInfo serverVersion >= self class largeSizesVersion ifTrue: [packetClass := JdmLargeSizeInputPacket]. clientCapabilities := serverInfo protocol = 10 ifTrue: [1] ifFalse: [0]. ! ! !JdmConnection methodsFor: 'initialize-release' stamp: 'jb 3/3/1999 17:21'! initializeDatabase (self requestPacket writeStream) nextPutCommand: (JdmMysqlCommand withCommandNamed: #initializeDatabase message: connectionSpec database); flush. self responsePacket checkStatusOnError: #setDatabase! ! !JdmConnection methodsFor: 'initialize-release' stamp: 'jb 3/3/1999 17:15'! initializeUser | replyStream password c s | password := connectionSpec password isEmpty ifTrue: [''] ifFalse: [self hash: connectionSpec password seed: self serverInfo hashSeed for: self serverInfo protocol]. replyStream := self replyPacket writeStream. c := String new: 2. c at: 1 put: (self clientCapabilities) asCharacter. c at: 2 put: 0 asCharacter. s := String new: 3. s at: 1 put: 0 asCharacter. s at: 2 put: 0 asCharacter. s at: 3 put: 1 asCharacter. replyStream nextPutAll: c; nextPutAll: s; nextPutAllNullTerminated: connectionSpec user; nextPutAllNullTerminated: password. " replyStream nextPutAll: (self clientCapabilities asByteArray: 2) asByteString; nextPutAll: (65536 asByteArray: 3) asByteString; nextPutAllNullTerminated: connectionSpec user; nextPutAllNullTerminated: password. " replyStream flush. self responsePacket checkStatusOnError: #authenticate! ! !JdmConnection methodsFor: 'hashing' stamp: 'jb 2/28/1999 18:36'! getHashFor: aProtocol ^hashesByProtocol at: aProtocol ifAbsent: [nil]! ! !JdmConnection methodsFor: 'hashing' stamp: 'jb 2/28/1999 19:19'! hash: aString seed: aSeed for: aProtocol | aHashMethod | aHashMethod := self getHashFor: aProtocol. aHashMethod isNil ifTrue: [^aString]. ^self class perform: aHashMethod with: aString with: aSeed! ! !JdmConnection methodsFor: 'accessing' stamp: 'jb 3/2/1999 18:49'! clientCapabilities ^clientCapabilities! ! !JdmConnection methodsFor: 'accessing' stamp: 'jb 3/2/1999 18:49'! connectionSpec ^connectionSpec! ! !JdmConnection methodsFor: 'accessing' stamp: 'jb 3/2/1999 18:49'! connectionSpec: anObject connectionSpec := anObject! ! !JdmConnection methodsFor: 'accessing' stamp: 'jb 3/2/1999 18:49'! createStatement ^JdmStatement on: self! ! !JdmConnection methodsFor: 'accessing' stamp: 'jb 3/3/1999 18:49'! replyPacket "| s | s := String new: 2000. writeStream := WriteStream on: s from: 1 to: (s size). " ^(JdmOutputPacket on: writeStream) packetNumber: responsePacket packetNumber + 1! ! !JdmConnection methodsFor: 'accessing' stamp: 'jb 3/3/1999 18:46'! requestPacket ^JdmOutputPacket on: writeStream ! ! !JdmConnection methodsFor: 'accessing' stamp: 'jb 3/3/1999 18:45'! responsePacket | | "socket waitForDataQueryingUserEvery: 30." "socket dataAvailable ifFalse: [self error: 'socket data notavailable.']." " buf := socket getData. Transcript show: buf; cr. readStream := ReadStream on: buf. " ^responsePacket := JdmInputPacket on: readStream ! ! !JdmConnection methodsFor: 'accessing' stamp: 'jb 3/2/1999 18:50'! serverInfo ^serverInfo! ! !JdmConnection methodsFor: 'accessing' stamp: 'jb 3/2/1999 18:50'! serverInfo: anObject serverInfo := anObject! ! "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "! JdmConnection class instanceVariableNames: ''! !JdmConnection class methodsFor: 'constants' stamp: 'jb 2/28/1999 19:21'! largeSizesVersion ^(JdmServerVersion new initialize) fileFormat: 3; serverRelease: 22; version: 7! ! !JdmConnection class methodsFor: 'constants' stamp: 'jb 2/28/1999 19:21'! protocolHashes ^#(9 #hash1:seed: 10 #hash2:seed:)! ! !JdmConnection class methodsFor: 'hashing' stamp: 'jb 2/28/1999 19:22'! hash1: aString seed: aSeed "This algorithm is for protocol 9." | hashedString maxValue array num1 num2 num3 | hashedString := String new: aSeed size. array := self randomInit1: aString seed: aSeed. maxValue := array at: 1. num1 := array at: 2. num2 := array at: 3. 1 to: hashedString size do: [:index | num1 := (num1 * 3 + num2) \\ maxValue. num2 := (num1 + num2 + 33) \\ maxValue. num3 := (num1 / maxValue * 31) truncated + 64. hashedString at: index put: num3 asCharacter]. ^hashedString! ! !JdmConnection class methodsFor: 'hashing' stamp: 'jb 2/28/1999 19:23'! hash2: aString seed: aSeed "This algorithm is for clientProtocol 10." | hashedString maxValue result num1 num2 num3 | hashedString := String new: aSeed size. result := self randomInit2: aString seed: aSeed. maxValue := result at: 1. num1 := result at: 2. num2 := result at: 3. 1 to: hashedString size do: [:index | num1 := (num1 * 3 + num2) \\ maxValue. num2 := (num1 + num2 + 33) \\ maxValue. num3 := (num1 / maxValue * 31) truncated + 64. hashedString at: index put: num3 asCharacter]. num1 := (num1 * 3 + num2) \\ maxValue. num2 := (num1 + num2 + 33) \\ maxValue. num3 := (num1 / maxValue * 31) truncated. hashedString inject: 1 into: [:index :character | hashedString at: index put: (character asInteger bitXor: num3) asCharacter. index + 1]. ^hashedString! ! !JdmConnection class methodsFor: 'hashing' stamp: 'jb 2/28/1999 19:24'! hash: aString "Hash algorithm taken from mysql in order to send password to the server" | num1 num2 num3 charValue | num1 := 1345345333. num2 := 305419889. num3 := 7. aString do: [:character | (character = Character space or: [character = Character tab]) ifFalse: [ charValue := character asInteger. num1 := num1 bitXor: ((num1 bitAnd: 63) + num3) * charValue + (num1 bitShift: 8). num2 := num2 + ((num2 bitShift: 8) bitXor: num1). num3 := num3 + charValue]]. ^Array with: (num1 bitAnd: 2147483647) with: (num2 bitAnd: 2147483647)! ! !JdmConnection class methodsFor: 'hashing' stamp: 'jb 2/28/1999 19:25'! randomInit1: aString seed: aSeed | result array1 array2 | result := Array new: 3. array1 := self hash: aString. array2 := self hash: aSeed. result at: 1 put: 16r01FFFFFF. result at: 2 put: ((array1 at: 1) bitXor: (array2 at: 1)) \\ (result at: 1). result at: 3 put: (result at: 2) // 2. ^result! ! !JdmConnection class methodsFor: 'hashing' stamp: 'jb 2/28/1999 19:25'! randomInit2: aString seed: aSeed | result array1 array2 | result := Array new: 3. array1 := self hash: aString. array2 := self hash: aSeed. result at: 1 put: 16r3FFFFFFF. result at: 2 put: ((array1 at: 1) bitXor: (array2 at: 1)) \\ (result at: 1). result at: 3 put: ((array1 at: 2) bitXor: (array2 at: 2)) \\ (result at: 1). ^result! ! !JdmConnection class methodsFor: 'misc' stamp: 'jb 3/3/1999 16:46'! byteArrayAsByteString: ba | size s | size := ba size. s := String new: size. 1 to: size do: [:index | s at: index put: ((ba at: index) asCharacter). ]. ^s.! ! !JdmConnection class methodsFor: 'misc' stamp: 'jb 3/3/1999 16:39'! byteArrayAsInteger: ba ^self byteArrayAsInteger: ba from: 1 for: ba size ! ! !JdmConnection class methodsFor: 'misc' stamp: 'jb 3/3/1999 16:34'! byteArrayAsInteger: ba from: anOffset for: aLength | shiftAmount anInteger | shiftAmount := 0. anInteger := 0. anOffset to: aLength do: [:index | anInteger := anInteger bitOr: ((ba at: index) bitShift: shiftAmount). shiftAmount := shiftAmount + 8]. ^anInteger ! ! !JdmConnection class methodsFor: 'misc' stamp: 'jb 3/3/1999 16:36'! integerAsByteArray: int length: aLength | aByteArray shiftAmount mask | aByteArray := ByteArray new: aLength. shiftAmount := 0. mask := 16rFF. 1 to: aLength do: [:index | aByteArray at: index put: (mask bitAnd: (int bitShift: shiftAmount)). shiftAmount := shiftAmount - 8]. ^aByteArray ! ! !JdmConnection class methodsFor: 'misc' stamp: 'jb 3/3/1999 16:32'! symbolAsClass: aSymbol ^Smalltalk at: aSymbol. ! ! !JdmConnection class methodsFor: 'misc' stamp: 'jb 3/4/1999 20:35'! test " | connection statement resultSet value | connection := JdmConnection on: (JdmConnectionSpec new initialize user: 'root'; password: 'p'). statement := connection createStatement. resultSet := statement executeQuery: 'select * from person'. [resultSet next] whileTrue: [value := resultSet valueNamed: 'name'. Transcript show: value printString. Transcript cr. ] "! ! !JdmConnection class methodsFor: 'instance creation' stamp: 'jb 2/28/1999 19:21'! on: aConnectionSpec ^(self new) connectionSpec: aConnectionSpec; initialize! ! Object subclass: #JdmConnectionSpec instanceVariableNames: 'database host port user password ' classVariableNames: '' poolDictionaries: '' category: 'Mysql-Driver'! !JdmConnectionSpec methodsFor: 'accessing'! database ^database! ! !JdmConnectionSpec methodsFor: 'accessing'! database: anObject database := anObject! ! !JdmConnectionSpec methodsFor: 'accessing'! host ^host! ! !JdmConnectionSpec methodsFor: 'accessing'! host: anObject host := anObject! ! !JdmConnectionSpec methodsFor: 'accessing'! password ^password! ! !JdmConnectionSpec methodsFor: 'accessing'! password: anObject password := anObject! ! !JdmConnectionSpec methodsFor: 'accessing'! port ^port! ! !JdmConnectionSpec methodsFor: 'accessing'! port: anObject port := anObject! ! !JdmConnectionSpec methodsFor: 'accessing'! user ^user! ! !JdmConnectionSpec methodsFor: 'accessing'! user: anObject user := anObject! ! !JdmConnectionSpec methodsFor: 'initialize-release' stamp: 'jb 3/3/1999 17:11'! initialize database := 'joerg'. "host := 'localhost'. " host := NetNameResolver localHostAddress. port := 3306. user := ''. password := ''! ! Object subclass: #JdmDateHolder instanceVariableNames: 'date ' classVariableNames: '' poolDictionaries: '' category: 'Mysql-Driver'! !JdmDateHolder methodsFor: 'printing'! printOn: aStream | aPolicy tokens | aPolicy := aStream policy dateAndTimePolicy. tokens := JdmTimestampPrintPolicy timestampPrintPolicy policyNamed: #JdmDate. aPolicy print: date on: aStream policy: tokens! ! !JdmDateHolder methodsFor: 'intialize-release'! initialize date := Date today! ! !JdmDateHolder methodsFor: 'accessing'! value ^date! ! !JdmDateHolder methodsFor: 'accessing'! value: aDate date := aDate! ! "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "! JdmDateHolder class instanceVariableNames: ''! !JdmDateHolder class methodsFor: 'instance creation'! readFrom: aStream ^self new value: (JdmTimestampPrintPolicy timestampPrintPolicy reader readDateFrom: aStream)! ! Object subclass: #JdmDateTime instanceVariableNames: 'date time ' classVariableNames: '' poolDictionaries: '' category: 'Mysql-Driver'! !JdmDateTime methodsFor: 'accessing'! date ^date! ! !JdmDateTime methodsFor: 'accessing'! date: aJdmDate date := aJdmDate! ! !JdmDateTime methodsFor: 'accessing'! time ^time! ! !JdmDateTime methodsFor: 'accessing'! time: aJdmTime time := aJdmTime! ! !JdmDateTime methodsFor: 'printing'! printOn: aStream self date printOn: aStream. aStream nextPut: $ . self time printOn: aStream! ! "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "! JdmDateTime class instanceVariableNames: ''! !JdmDateTime class methodsFor: 'instance creation'! fromDate: aJdmDate andTime: aJdmTime ^(self new) date: aJdmDate; time: aJdmTime! ! !JdmDateTime class methodsFor: 'instance creation'! readFrom: aStream ^JdmTimestampPrintPolicy timestampPrintPolicy reader readMysqlDateTimeFrom: aStream! ! Object subclass: #JdmDoubleHolder instanceVariableNames: 'double ' classVariableNames: '' poolDictionaries: '' category: 'Mysql-Driver'! !JdmDoubleHolder methodsFor: 'printing'! printOn: aStream | readStream character | readStream := ReadStream on: double printString. [character := readStream next. character isNil] whileFalse: [character = $d ifTrue: [character := readStream next. character isNil ifTrue: [^self]. aStream nextPut: $e. character = $- ifFalse: [aStream nextPut: $+]]. aStream nextPut: character]! ! !JdmDoubleHolder methodsFor: 'accessing'! value ^double! ! !JdmDoubleHolder methodsFor: 'accessing'! value: aDouble double := aDouble! ! !JdmDoubleHolder methodsFor: 'initialize-release'! initialize double := 0d! ! "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "! JdmDoubleHolder class instanceVariableNames: ''! !JdmDoubleHolder class methodsFor: 'instance creation'! readFrom: aStream | writeStream character | writeStream := WriteStream on: String new. [character := aStream next. character isNil] whileFalse: [character = $e ifTrue: [writeStream nextPut: $d. character := aStream next. character = $+ ifTrue: [character := aStream next]]. writeStream nextPut: character]. ^self new value: (Double readFrom: (ReadStream on: writeStream contents))! ! Object subclass: #JdmErrorTable instanceVariableNames: 'errors ' classVariableNames: 'ErrorTable ' poolDictionaries: '' category: 'Mysql-Driver'! !JdmErrorTable methodsFor: 'actions'! throwException: aSymbol self throwException: aSymbol message: ''! ! !JdmErrorTable methodsFor: 'actions'! throwException: aSymbol message: aString self error: (self errors at: aSymbol ifAbsent: ['Unknown']) , ': ' , aString! ! !JdmErrorTable methodsFor: 'initialize-release'! initialize errors := IdentityDictionary withKeysAndValues: self class errorTableMap! ! !JdmErrorTable methodsFor: 'accessing'! errors ^errors! ! "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "! JdmErrorTable class instanceVariableNames: ''! !JdmErrorTable class methodsFor: 'singleton'! errorTable ErrorTable isNil ifTrue: [ErrorTable := self new initialize]. ^ErrorTable! ! !JdmErrorTable class methodsFor: 'singleton'! resetErrorTable ErrorTable := nil! ! !JdmErrorTable class methodsFor: 'errors'! errorTableMap "JdmErrorTable resetErrorTable" ^#(#protocol 'Invalid Protocol' #authentication 'Access denied' #setDatabase 'Could not set the database' #invalidQuery 'Invalid query' #invalidSize 'Read size out of bounds')! ! Object subclass: #JdmFieldConverter instanceVariableNames: 'types ' classVariableNames: 'Instance ' poolDictionaries: '' category: 'Mysql-Driver'! !JdmFieldConverter methodsFor: 'actions'! convert: aValue from: aColumn ^self perform: (types at: aColumn type) with: aValue with: aColumn! ! !JdmFieldConverter methodsFor: 'private-initialize'! buildTypeMap types := Dictionary new. types at: JdmColumn tinyType put: #toInteger:column:; at: JdmColumn shortType put: #toInteger:column:; at: JdmColumn longType put: #toInteger:column:; at: JdmColumn int24Type put: #toInteger:column:; at: JdmColumn longlongType put: #toInteger:column:; at: JdmColumn floatType put: #toFloat:column:; at: JdmColumn doubleType put: #toDouble:column:; at: JdmColumn decimalType put: #toDouble:column:; at: JdmColumn dateType put: #toDate:column:; at: JdmColumn datetimeType put: #toDateTime:column:; at: JdmColumn timeType put: #toTime:column:; at: JdmColumn timestampType put: #toTimestamp:column:; at: JdmColumn enumType put: #toString:column:; at: JdmColumn setType put: #toSet:column:; at: JdmColumn tinyBlobType put: #toByteArray:column:; at: JdmColumn mediumBlobType put: #toByteArray:column:; at: JdmColumn longBlobType put: #toByteArray:column:; at: JdmColumn blobType put: #toByteArray:column:; at: JdmColumn varStringType put: #toString:column:; at: JdmColumn stringType put: #toString:column:! ! !JdmFieldConverter methodsFor: 'initialize-release'! initialize self buildTypeMap! ! !JdmFieldConverter methodsFor: 'converting'! toByteArray: aString column: aColumn aColumn isBinary ifFalse: [^aString]. ^aString asByteArray! ! !JdmFieldConverter methodsFor: 'converting'! toDate: aString column: aColumn ^JdmDateHolder readFrom: (ReadStream on: aString)! ! !JdmFieldConverter methodsFor: 'converting'! toDateTime: aString column: aColumn ^JdmDateTime readFrom: (ReadStream on: aString)! ! !JdmFieldConverter methodsFor: 'converting'! toDouble: aString column: aColumn ^JdmDoubleHolder readFrom: (ReadStream on: aString)! ! !JdmFieldConverter methodsFor: 'converting'! toFloat: aString column: aColumn ^JdmFloatHolder readFrom: (ReadStream on: aString)! ! !JdmFieldConverter methodsFor: 'converting'! toInteger: aString column: aColumn ^Integer readFrom: (ReadStream on: aString)! ! !JdmFieldConverter methodsFor: 'converting'! toString: aString column: aColumn ^aString! ! !JdmFieldConverter methodsFor: 'converting'! toTime: aString column: aColumn ^JdmTimeHolder readFrom: (ReadStream on: aString)! ! !JdmFieldConverter methodsFor: 'converting'! toTimestamp: aString column: aColumn ^JdmTimestampHolder readFrom: (ReadStream on: aString)! ! "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "! JdmFieldConverter class instanceVariableNames: ''! !JdmFieldConverter class methodsFor: 'singleton'! fieldConverter Instance isNil ifTrue: [Instance := self new initialize]. ^Instance! ! !JdmFieldConverter class methodsFor: 'singleton'! resetFieldConverter "JdmFieldConverter resetFieldConverter" Instance := nil! ! Object subclass: #JdmFloatHolder instanceVariableNames: 'float ' classVariableNames: '' poolDictionaries: '' category: 'Mysql-Driver'! !JdmFloatHolder methodsFor: 'accessing'! value ^float! ! !JdmFloatHolder methodsFor: 'accessing'! value: aFloat float := aFloat! ! !JdmFloatHolder methodsFor: 'printing'! printOn: aStream | readStream character | readStream := ReadStream on: float printString. [character := readStream next. character isNil] whileFalse: [character = $e ifTrue: [aStream nextPut: character. character := readStream next. character = $- ifFalse: [aStream nextPut: $+]]. aStream nextPut: character]! ! !JdmFloatHolder methodsFor: 'initialize-release'! initialize float := 0.0! ! "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "! JdmFloatHolder class instanceVariableNames: ''! !JdmFloatHolder class methodsFor: 'instance creation'! readFrom: aStream | writeStream character | writeStream := WriteStream on: String new. [character := aStream next. character isNil] whileFalse: [character = $+ ifFalse: [writeStream nextPut: character]]. ^self new value: (Float readFrom: (ReadStream on: writeStream contents))! ! ReadStream subclass: #JdmLargeSizeReadStream instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Mysql-Driver'! !JdmLargeSizeReadStream methodsFor: 'accessing'! readSize ^self readSize64! ! Object subclass: #JdmMysqlCommand instanceVariableNames: 'command message ' classVariableNames: '' poolDictionaries: '' category: 'Mysql-Driver'! !JdmMysqlCommand methodsFor: 'private-accessing'! command: aCommand command := aCommand! ! !JdmMysqlCommand methodsFor: 'accessing'! command ^command! ! !JdmMysqlCommand methodsFor: 'accessing'! message ^message! ! !JdmMysqlCommand methodsFor: 'accessing'! message: aMessage message := aMessage isNil ifTrue: [' '] ifFalse: [aMessage]! ! "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "! JdmMysqlCommand class instanceVariableNames: ''! !JdmMysqlCommand class methodsFor: 'instance creation'! withCommand: aCommand ^self withCommand: aCommand message: nil! ! !JdmMysqlCommand class methodsFor: 'instance creation'! withCommand: aCommand message: aMessage ^(self new) command: aCommand; message: aMessage! ! !JdmMysqlCommand class methodsFor: 'instance creation'! withCommandNamed: aCommandName ^self withCommandNamed: aCommandName message: nil! ! !JdmMysqlCommand class methodsFor: 'instance creation'! withCommandNamed: aCommandName message: aMessage ^(self new) command: (self perform: aCommandName); message: aMessage! ! !JdmMysqlCommand class methodsFor: 'mysql-constants'! connect ^11! ! !JdmMysqlCommand class methodsFor: 'mysql-constants'! createDatabase ^5! ! !JdmMysqlCommand class methodsFor: 'mysql-constants'! debug ^13! ! !JdmMysqlCommand class methodsFor: 'mysql-constants'! dropDatabase ^6! ! !JdmMysqlCommand class methodsFor: 'mysql-constants'! fieldList ^4! ! !JdmMysqlCommand class methodsFor: 'mysql-constants'! initializeDatabase ^2! ! !JdmMysqlCommand class methodsFor: 'mysql-constants'! killProcess ^12! ! !JdmMysqlCommand class methodsFor: 'mysql-constants'! processInfo ^10! ! !JdmMysqlCommand class methodsFor: 'mysql-constants'! query ^3! ! !JdmMysqlCommand class methodsFor: 'mysql-constants'! quit ^1! ! !JdmMysqlCommand class methodsFor: 'mysql-constants'! refresh ^7! ! !JdmMysqlCommand class methodsFor: 'mysql-constants'! shutdown ^8! ! !JdmMysqlCommand class methodsFor: 'mysql-constants'! sleep ^0! ! !JdmMysqlCommand class methodsFor: 'mysql-constants'! statistics ^9! ! Object subclass: #JdmPacket instanceVariableNames: 'packetNumber size buffer stream ' classVariableNames: '' poolDictionaries: '' category: 'Mysql-Driver'! !JdmPacket methodsFor: 'accessing'! packetNumber ^packetNumber! ! !JdmPacket methodsFor: 'accessing'! packetNumber: anInteger packetNumber := anInteger! ! !JdmPacket methodsFor: 'accessing'! size ^size! ! !JdmPacket methodsFor: 'accessing'! size: anObject size := anObject! ! !JdmPacket methodsFor: 'accessing'! stream ^stream! ! !JdmPacket methodsFor: 'accessing'! stream: anObject stream := anObject! ! "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "! JdmPacket class instanceVariableNames: ''! !JdmPacket class methodsFor: 'constants'! defaultBufferSize ^8192! ! !JdmPacket class methodsFor: 'constants'! headerSize ^4! ! !JdmPacket class methodsFor: 'constants'! packetNumberOffset ^4! ! !JdmPacket class methodsFor: 'constants'! packetNumberSize ^1! ! !JdmPacket class methodsFor: 'constants'! sizeOffset ^1! ! !JdmPacket class methodsFor: 'constants'! sizeSize ^3! ! !JdmPacket class methodsFor: 'instance creation' stamp: 'jb 3/3/1999 18:45'! on: aStream ^(self new) stream: aStream; initialize! ! JdmPacket subclass: #JdmInputPacket instanceVariableNames: 'readStream ' classVariableNames: '' poolDictionaries: '' category: 'Mysql-Driver'! !JdmInputPacket methodsFor: 'initialize-release' stamp: 'jb 3/3/1999 18:33'! initialize size := self readPacketSize. packetNumber := self readPacketNumber. buffer := self readBuffer. readStream := JdmReadStream on: buffer.! ! !JdmInputPacket methodsFor: 'reading' stamp: 'jb 3/2/1999 17:33'! checkForStatus: anInteger onError: aSymbol (self readStatusOnError: aSymbol) = anInteger ifFalse: [self handleError: aSymbol]! ! !JdmInputPacket methodsFor: 'reading' stamp: 'jb 3/2/1999 17:33'! checkStatusOnError: aSymbol self checkForStatus: 0 onError: aSymbol! ! !JdmInputPacket methodsFor: 'reading' stamp: 'jb 3/2/1999 17:32'! handleError: aSymbol JdmErrorTable errorTable throwException: aSymbol message: (readStream next: 2) asByteArray asInteger printString , ' ' , readStream readNullTerminatedString! ! !JdmInputPacket methodsFor: 'reading' stamp: 'jb 3/2/1999 17:32'! readBuffer ^self stream next: self size! ! !JdmInputPacket methodsFor: 'reading' stamp: 'jb 3/2/1999 18:20'! readPacketNumber | ba o int1 | o := (self stream next: self class packetNumberSize). ba := o asByteArray. int1 := ba basicAt: 1. ^int1. " ^(self stream next: self class packetNumberSize) asByteArray asInteger "! ! !JdmInputPacket methodsFor: 'reading' stamp: 'jb 3/2/1999 18:16'! readPacketSize | ba o int1 int2 int3 | o := (self stream next: self class sizeSize). ba := o asByteArray. int1 := ba basicAt: 1. int2 := ba basicAt: 2. int2 := int2 bitShift: 8. int3 := ba basicAt: 3. int3 := int3 bitShift: 16. ^int1 + int2 + int3. " s := ba asString. n := Integer readFrom: (ReadStream on: s). n inspect. ^ba asInteger "! ! !JdmInputPacket methodsFor: 'reading' stamp: 'jb 3/2/1999 17:32'! readStatusOnError: aSymbol | status | status := readStream next asInteger. status = 255 ifFalse: [^status]. self handleError: aSymbol! ! !JdmInputPacket methodsFor: 'accessing' stamp: 'jb 3/3/1999 18:20'! readStream ^readStream! ! JdmInputPacket subclass: #JdmLargeSizeInputPacket instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Mysql-Driver'! !JdmLargeSizeInputPacket commentStamp: '' prior: 0! JdmLargeSizeInputPacket was created instead of created for performance reasons. JdmInputPacket could do a comparison on versions every time it is created, but I thought it better to let the connection do it once and then create the appropriate InputPacket class. ! !JdmLargeSizeInputPacket methodsFor: 'initialize-release'! initialize size := self readPacketSize. packetNumber := self readPacketNumber. buffer := self readBuffer. readStream := JdmLargeSizeReadStream on: buffer! ! JdmPacket subclass: #JdmOutputPacket instanceVariableNames: 'writeStream ' classVariableNames: '' poolDictionaries: '' category: 'Mysql-Driver'! !JdmOutputPacket methodsFor: 'accessing' stamp: 'jb 3/2/1999 18:44'! writeStream ^writeStream! ! !JdmOutputPacket methodsFor: 'actions' stamp: 'jb 3/3/1999 18:45'! flush | aString ba s bytesSend | aString := self writeStream contents. self writeStream close. self size: aString size - self class headerSize. ba := JdmConnection integerAsByteArray: self size length: self class sizeSize. s := JdmConnection byteArrayAsByteString: ba. aString replaceFrom: 1 to: self class sizeSize with: s startingAt: 1. " aString replaceFrom: 1 to: self class sizeSize with: (self size asByteArray: self class sizeSize) asByteString startingAt: 1. " aString at: self class sizeSize + 1 put: self packetNumber asCharacter. (self stream) nextPutAll: aString; flush " bytesSend := socket sendData: aString. (bytesSend = aString size) ifFalse: [self error: 'error'.]. " ! ! !JdmOutputPacket methodsFor: 'initialize-release' stamp: 'jb 3/2/1999 20:41'! initialize packetNumber := 0. buffer := String new: self class defaultBufferSize. writeStream := JdmWriteStream on: buffer startingAt: (self class headerSize) outputPacket: (self). "This is a bit of a hack...I should utilize events instead" " writeStream expressInterestIn: #flush for: self sendBack: #flush "! ! ReadStream subclass: #JdmReadStream instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Mysql-Driver'! !JdmReadStream methodsFor: 'accessing' stamp: 'jb 3/2/1999 17:33'! readNullTerminatedString ^self upTo: self class null asCharacter! ! !JdmReadStream methodsFor: 'accessing' stamp: 'jb 3/2/1999 17:33'! readSize ^self readSize32! ! !JdmReadStream methodsFor: 'accessing' stamp: 'jb 3/2/1999 17:34'! readSize32 | aSize | aSize := self next asInteger. (aSize < 0 or: [aSize > 254]) ifTrue: [JdmErrorTable throwException: #invalidSize message: aSize printString]. aSize < 251 ifTrue: [^aSize]. aSize = 251 ifTrue: [^0]. ^(self next: (aSize bitAnd: 3) + 2) asByteArray asInteger! ! !JdmReadStream methodsFor: 'accessing' stamp: 'jb 3/2/1999 17:35'! readSize64 | aSize | aSize := self next asInteger. (aSize < 0 or: [aSize > 254]) ifTrue: [JdmErrorTable throwException: #invalidSize message: aSize printString]. aSize < 251 ifTrue: [^aSize]. aSize = 251 ifTrue: [^0]. aSize < 254 ifTrue: [^(self next: (aSize bitAnd: 3) + 2) asByteArray asInteger]. ^(self next: 8) asByteArray asInteger! ! "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "! JdmReadStream class instanceVariableNames: ''! !JdmReadStream class methodsFor: 'constants'! null ^0! ! Object subclass: #JdmResult instanceVariableNames: 'value type ' classVariableNames: '' poolDictionaries: '' category: 'Mysql-Driver'! !JdmResult methodsFor: 'testing'! hasResultSet ^type = #read! ! !JdmResult methodsFor: 'accessing'! type ^type! ! !JdmResult methodsFor: 'accessing'! type: aType type := aType! ! !JdmResult methodsFor: 'accessing'! value ^value! ! !JdmResult methodsFor: 'accessing'! value: aValue value := aValue! ! Object subclass: #JdmResultSet instanceVariableNames: 'columns connection columnsByName currentRow ' classVariableNames: '' poolDictionaries: '' category: 'Mysql-Driver'! !JdmResultSet methodsFor: 'private-accessing'! currentRow ^currentRow! ! !JdmResultSet methodsFor: 'accessing'! columnAt: index ^columns at: index! ! !JdmResultSet methodsFor: 'accessing'! columnNamed: aName ^self columnAt: (columnsByName at: aName ifAbsent: [^nil])! ! !JdmResultSet methodsFor: 'accessing'! columns ^columns! ! !JdmResultSet methodsFor: 'accessing'! connection ^connection! ! !JdmResultSet methodsFor: 'accessing'! connection: anObject connection := anObject! ! !JdmResultSet methodsFor: 'accessing'! next currentRow := (JdmRow withNumColumns: columns size) readFrom: connection responsePacket readStream. ^currentRow isEmpty not! ! !JdmResultSet methodsFor: 'accessing'! rawValueAt: anIndex ^self currentRow at: anIndex! ! !JdmResultSet methodsFor: 'accessing'! rawValueNamed: aName ^self rawValueAt: (columnsByName at: aName)! ! !JdmResultSet methodsFor: 'accessing'! valueAt: anIndex ^JdmFieldConverter fieldConverter convert: (self currentRow at: anIndex) from: (self columns at: anIndex)! ! !JdmResultSet methodsFor: 'accessing'! valueNamed: aName ^self valueAt: (columnsByName at: aName)! ! !JdmResultSet methodsFor: 'initialize-release' stamp: 'jb 3/3/1999 19:26'! initialize | column rpacket | columnsByName := Dictionary new. rpacket := connection responsePacket. columns := Array new: (rpacket readStatusOnError: #invalidQuery). 1 to: columns size do: [:index | rpacket := connection responsePacket. column := JdmColumn readFrom: rpacket readStream. columns at: index put: column. columnsByName at: column name put: index]. connection responsePacket checkForStatus: 254 onError: #invalidQuery. currentRow := JdmRow withNumColumns: columns size.! ! "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "! JdmResultSet class instanceVariableNames: ''! !JdmResultSet class methodsFor: 'instance creation'! on: aConnection ^(self new) connection: aConnection; initialize! ! Object subclass: #JdmRow instanceVariableNames: 'numColumns values isEmpty ' classVariableNames: '' poolDictionaries: '' category: 'Mysql-Driver'! !JdmRow methodsFor: 'reading'! checkForEndOrNull: aReadStream "This is a bit unclean...the value 254 has been overloaded in the protocol. When it is the only value in the stream, it indicates there are no more rows. It also indicates that the following 4 bytes contain the size of the field value. The problem is that there is another condition that produces a single value on the stream...a row with one column whose value is NULL." | endOrNull | aReadStream size = 1 ifFalse: [^false]. endOrNull := aReadStream next asInteger. endOrNull = 254 ifTrue: [isEmpty := true. ^true]. endOrNull = 251 ifTrue: [^true]. "Unexpected Value" JdmErrorTable throwException: #invalidQuery message: 'Unexpected value ' , endOrNull printString. ^true! ! !JdmRow methodsFor: 'reading'! readFrom: aReadStream (self checkForEndOrNull: aReadStream) ifTrue: [^self]. self readRowsFrom: aReadStream! ! !JdmRow methodsFor: 'reading'! readRowsFrom: aReadStream | aSize | 1 to: numColumns do: [:index | aSize := aReadStream readSize32. aSize = 0 ifFalse: [values at: index put: (aReadStream next: aSize)]]! ! !JdmRow methodsFor: 'initialize-release'! initialize values := Array new: numColumns. self initializeWithNulls. isEmpty := false.! ! !JdmRow methodsFor: 'initialize-release'! initializeWithNulls 1 to: numColumns do: [:index | values at: index put: nil]! ! !JdmRow methodsFor: 'accessing'! at: anIndex ^values at: anIndex! ! !JdmRow methodsFor: 'accessing'! numColumns: anInteger numColumns := anInteger! ! !JdmRow methodsFor: 'testing'! isEmpty ^isEmpty! ! "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "! JdmRow class instanceVariableNames: ''! !JdmRow class methodsFor: 'instance creation'! withNumColumns: anInteger ^(self new) numColumns: anInteger; initialize! ! Object subclass: #JdmServerInfo instanceVariableNames: 'protocol serverVersion serverThread hashSeed options ' classVariableNames: '' poolDictionaries: '' category: 'Mysql-Driver'! !JdmServerInfo methodsFor: 'initialize-release' stamp: 'jb 2/28/1999 18:28'! initialize serverVersion := JdmServerVersion new initialize. hashSeed := String new. protocol := -1. serverThread := -1. options := -1! ! !JdmServerInfo methodsFor: 'accessing'! hashSeed ^hashSeed! ! !JdmServerInfo methodsFor: 'accessing'! hashSeed: anObject hashSeed := anObject! ! !JdmServerInfo methodsFor: 'accessing'! options ^options! ! !JdmServerInfo methodsFor: 'accessing'! options: anObject options := anObject! ! !JdmServerInfo methodsFor: 'accessing'! protocol ^protocol! ! !JdmServerInfo methodsFor: 'accessing'! protocol: aProtocol self validateProtocol: aProtocol. protocol := aProtocol! ! !JdmServerInfo methodsFor: 'accessing'! serverThread ^serverThread! ! !JdmServerInfo methodsFor: 'accessing'! serverThread: anObject serverThread := anObject! ! !JdmServerInfo methodsFor: 'accessing'! serverVersion ^serverVersion! ! !JdmServerInfo methodsFor: 'accessing'! serverVersion: anObject serverVersion := anObject! ! !JdmServerInfo methodsFor: 'reading' stamp: 'jb 3/2/1999 17:31'! readFrom: aResponsePacket self readProtocolFrom: aResponsePacket; readServerVersionFrom: aResponsePacket; readServerThreadFrom: aResponsePacket; readHashSeedFrom: aResponsePacket; readOptionsFrom: aResponsePacket! ! !JdmServerInfo methodsFor: 'reading'! readHashSeedFrom: aResponsePacket hashSeed := aResponsePacket readStream readNullTerminatedString! ! !JdmServerInfo methodsFor: 'reading' stamp: 'jb 3/2/1999 18:23'! readOptionsFrom: aResponsePacket | ba int1 int2 | ba := (aResponsePacket readStream next: 2) asByteArray . int1 := ba basicAt: 1. int2 := ba basicAt: 2. int2 := int2 bitShift: 8. options := int1 + int2. ! ! !JdmServerInfo methodsFor: 'reading'! readProtocolFrom: aResponsePacket protocol := (aResponsePacket readStatusOnError: #protocol)! ! !JdmServerInfo methodsFor: 'reading' stamp: 'jb 3/2/1999 18:22'! readServerThreadFrom: aResponsePacket | ba int1 int2 int3 int4 | ba := (aResponsePacket readStream next: 4) asByteArray . int1 := ba basicAt: 1. int2 := ba basicAt: 2. int2 := int2 bitShift: 8. int3 := ba basicAt: 3. int3 := int3 bitShift: 16. int4 := ba basicAt: 4. int4 := int4 bitShift: 24. serverThread := int1 + int2 + int3 + int4. ! ! !JdmServerInfo methodsFor: 'reading'! readServerVersionFrom: aResponsePacket serverVersion := JdmServerVersion readFrom: aResponsePacket readStream! ! !JdmServerInfo methodsFor: 'validation'! validateProtocol: aProtocol (aProtocol = 9 or: [aProtocol = 10]) ifFalse: [JdmErrorTable errorTable error: #protocol]! ! "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "! JdmServerInfo class instanceVariableNames: ''! !JdmServerInfo class methodsFor: 'constants'! clientProtocolSize ^1! ! !JdmServerInfo class methodsFor: 'constants'! optionsSize ^2! ! !JdmServerInfo class methodsFor: 'constants'! serverThreadSize ^4! ! !JdmServerInfo class methodsFor: 'instance creation' stamp: 'jb 3/2/1999 17:26'! on: aConnection ^self new readFrom: aConnection responsePacket! ! Magnitude subclass: #JdmServerVersion instanceVariableNames: 'fileFormat release version ' classVariableNames: '' poolDictionaries: '' category: 'Mysql-Driver'! !JdmServerVersion methodsFor: 'initialize-release'! initialize fileFormat := 0. release := 0. version := 0.! ! !JdmServerVersion methodsFor: 'printing'! printOn: aStream aStream nextPutAll: fileFormat printString; nextPut: $.; nextPutAll: release printString; nextPut: $.; nextPutAll: version printString! ! !JdmServerVersion methodsFor: 'reading' stamp: 'jb 3/1/1999 19:42'! readFrom: aStream fileFormat := Integer readFrom: aStream. aStream next. release := Integer readFrom: aStream. aStream next. version := Integer readFrom: aStream. aStream readNullTerminatedString! ! !JdmServerVersion methodsFor: 'accessing'! fileFormat ^fileFormat! ! !JdmServerVersion methodsFor: 'accessing'! fileFormat: anInteger fileFormat := anInteger! ! !JdmServerVersion methodsFor: 'accessing'! serverRelease "Renamed this because of a conflict with the Object method release" ^release! ! !JdmServerVersion methodsFor: 'accessing'! serverRelease: anInteger release := anInteger! ! !JdmServerVersion methodsFor: 'accessing'! version ^version! ! !JdmServerVersion methodsFor: 'accessing'! version: anInteger version := anInteger! ! !JdmServerVersion methodsFor: 'comparing'! < aJdmServerVersion ^aJdmServerVersion fileFormat > fileFormat or: [(aJdmServerVersion fileFormat = fileFormat and: [aJdmServerVersion serverRelease > release]) or: [aJdmServerVersion serverRelease = release and: [aJdmServerVersion version > version]]]! ! !JdmServerVersion methodsFor: 'comparing'! = aJdmServerVersion ^fileFormat = aJdmServerVersion fileFormat and: [release = aJdmServerVersion serverRelease and: [version = aJdmServerVersion version]]! ! "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "! JdmServerVersion class instanceVariableNames: ''! !JdmServerVersion class methodsFor: 'instance creation'! readFrom: aStream ^self new readFrom: aStream! ! Object subclass: #JdmStatement instanceVariableNames: 'connection ' classVariableNames: 'MysqlQueries ' poolDictionaries: '' category: 'Mysql-Driver'! !JdmStatement methodsFor: 'private-accessing' stamp: 'jb 2/28/1999 18:25'! connection: aConnection connection := aConnection! ! !JdmStatement methodsFor: 'private-accessing' stamp: 'jb 2/28/1999 18:25'! createResult: queryInfo ^self perform: ((queryInfo at: 1) , 'Result:') asSymbol with: queryInfo! ! !JdmStatement methodsFor: 'private-accessing' stamp: 'jb 3/3/1999 17:02'! readResult: queryInfo | symbol aClass | symbol := (JdmResult new) type: (queryInfo at: 1); value: ((queryInfo at: 2)). aClass := JdmConnection symbolAsClass: (queryInfo at: 2) asSymbol. ^aClass on: connection. " ^(JdmResult new) type: (queryInfo at: 1); value: ((queryInfo at: 2) inspect). "! ! !JdmStatement methodsFor: 'private-accessing' stamp: 'jb 2/28/1999 18:26'! updateResult: queryInfo "Right now the insert id is being dropped." | responsePacket affectedRows insertID | responsePacket := connection responsePacket. responsePacket checkStatusOnError: #invalidQuery. affectedRows := responsePacket readStream readSize. insertID := responsePacket readStream readSize. ^(JdmResult new) type: (queryInfo at: 1); value: affectedRows! ! !JdmStatement methodsFor: 'accessing' stamp: 'jb 3/3/1999 17:52'! executeQuery: aQuery | queryInfo r | queryInfo := self class queryInfoFor: aQuery. queryInfo isNil ifTrue: [JdmErrorTable errorTable throwException: #invalidQuery message: aQuery]. (connection requestPacket writeStream) nextPutCommand: (JdmMysqlCommand withCommandNamed: #query message: aQuery); flush. r := self createResult: queryInfo. ^r.! ! "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "! JdmStatement class instanceVariableNames: ''! !JdmStatement class methodsFor: 'constants' stamp: 'jb 2/28/1999 18:24'! mysqlQueries "To be added: DESCRIBE, EXPLAIN, SHOW" ^#( #('SELECT' #(#read #JdmResultSet)) #('INSERT' #(#update)) #('UPDATE' #(#update)) #('DELETE' #(#update)) #('CREATE' #(#update)) #('DROP' #(#update)) #('ALTER' #(#update )) #('LOCK' #(#update )) #('UNLOCK' #(#update )) #('SET' #(#update )) #('GRANT' #(#update )) #('REPLACE' #(#update )))! ! !JdmStatement class methodsFor: 'private-parsing' stamp: 'jb 2/28/1999 18:23'! getCommand: aQuery | readStream writeStream aCharacter | writeStream := WriteStream on: String new. readStream := ReadStream on: aQuery. readStream skipSeparators. [readStream atEnd or: [aCharacter := readStream next. aCharacter isSeparator]] whileFalse: [writeStream nextPut: aCharacter asUppercase]. ^writeStream contents! ! !JdmStatement class methodsFor: 'accessing' stamp: 'jb 2/28/1999 18:22'! queryInfoFor: aQuery ^MysqlQueries at: (self getCommand: aQuery) ifAbsent: [nil]! ! !JdmStatement class methodsFor: 'initialize-release' stamp: 'jb 2/28/1999 18:25'! initialize "JdmStatement initialize" MysqlQueries := Dictionary new. self mysqlQueries do: [:association | MysqlQueries add: (Association key: (association at: 1) value: (association at: 2))]! ! !JdmStatement class methodsFor: 'initialize-release' stamp: 'jb 2/28/1999 18:25'! initializeOnLoad self initialize! ! !JdmStatement class methodsFor: 'instance creation' stamp: 'jb 2/28/1999 18:25'! on: aConnection ^self new connection: aConnection! ! JdmStatement initialize! Object subclass: #JdmTimeHolder instanceVariableNames: 'time ' classVariableNames: '' poolDictionaries: '' category: 'Mysql-Driver'! !JdmTimeHolder methodsFor: 'printing'! printOn: aStream | aPolicy tokens | aPolicy := aStream policy dateAndTimePolicy. tokens := JdmTimestampPrintPolicy timestampPrintPolicy policyNamed: #JdmTime. aPolicy print: time on: aStream policy: tokens! ! !JdmTimeHolder methodsFor: 'initialize-release'! initialize time := Time now! ! !JdmTimeHolder methodsFor: 'accessing'! value ^time! ! !JdmTimeHolder methodsFor: 'accessing'! value: aTime time := aTime! ! "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "! JdmTimeHolder class instanceVariableNames: ''! !JdmTimeHolder class methodsFor: 'instance creation'! readFrom: aStream ^self new value: (JdmTimestampPrintPolicy timestampPrintPolicy reader readTimeFrom: aStream)! ! Object subclass: #JdmTimestampHolder instanceVariableNames: 'timestamp ' classVariableNames: '' poolDictionaries: '' category: 'Mysql-Driver'! !JdmTimestampHolder methodsFor: 'accessing'! value ^timestamp! ! !JdmTimestampHolder methodsFor: 'accessing'! value: aTimestamp timestamp := aTimestamp! ! !JdmTimestampHolder methodsFor: 'initialize-release'! initialize timestamp := Timestamp now! ! !JdmTimestampHolder methodsFor: 'printing'! printOn: aStream | aPolicy tokens | aPolicy := aStream policy dateAndTimePolicy. tokens := JdmTimestampPrintPolicy timestampPrintPolicy policyNamed: #JdmTimestamp. aPolicy print: timestamp on: aStream policy: tokens! ! "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "! JdmTimestampHolder class instanceVariableNames: ''! !JdmTimestampHolder class methodsFor: 'instance creation'! readFrom: aStream ^self new value: (JdmTimestampPrintPolicy timestampPrintPolicy reader readTimestampFrom: aStream)! ! nil subclass: #JdmTimestampPrintPolicy instanceVariableNames: '' classVariableNames: 'Instance ' poolDictionaries: '' category: 'Mysql-Driver'! !JdmTimestampPrintPolicy methodsFor: 'initialize-release'! mysql self us; policyNamed: #JdmTimestamp putString: 'yyyymmddhhmmss'; policyNamed: #JdmTime putString: 'hh:mm:ss'; policyNamed: #JdmDate putString: 'yyyy-mm-dd'! ! !JdmTimestampPrintPolicy methodsFor: 'accessing'! reader ^(JdmTimestampReader newFor: localeID) printPolicy: self; yourself! ! "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "! JdmTimestampPrintPolicy class instanceVariableNames: ''! !JdmTimestampPrintPolicy class methodsFor: 'singleton'! resetTimestampPrintPolicy Instance := nil! ! !JdmTimestampPrintPolicy class methodsFor: 'singleton'! timestampPrintPolicy Instance isNil ifTrue: [Instance := self newFor: #mysql]. ^Instance! ! nil subclass: #JdmTimestampReader instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Mysql-Driver'! !JdmTimestampReader methodsFor: 'initialize'! mysql timeSelector := #readMysqlTimeFrom:. dateSelector := #readMysqlDateFrom:. timestampSelector := #readMysqlTimestampFrom:! ! !JdmTimestampReader methodsFor: 'private-reading'! readIntegerFrom: aStream next: anInteger ^Integer readFrom: (ReadStream on: (aStream next: anInteger))! ! !JdmTimestampReader methodsFor: 'reading mysql'! readMysqlDateFrom: aStream | day month year | year := Integer readFrom: aStream. aStream next. month := Integer readFrom: aStream. aStream next. day := Integer readFrom: aStream. ^Date newDay: day monthNumber: month year: year! ! !JdmTimestampReader methodsFor: 'reading mysql'! readMysqlDateTimeFrom: aStream | aJdmDate aJdmTime | aJdmDate := JdmDateHolder new value: (self readMysqlDateFrom: aStream). aStream next. aJdmTime := JdmTimeHolder new value: (self readMysqlTimeFrom: aStream). ^JdmDateTime fromDate: aJdmDate andTime: aJdmTime! ! !JdmTimestampReader methodsFor: 'reading mysql'! readMysqlTimeFrom: aStream | hour minute second | hour := Integer readFrom: aStream. aStream next. minute := Integer readFrom: aStream. aStream next. second := Integer readFrom: aStream. ^Time fromSeconds: 60 * (60 * hour + minute) + second! ! !JdmTimestampReader methodsFor: 'reading mysql'! readMysqlTimestampFrom: aStream | year month day hour minute second | year := self readIntegerFrom: aStream next: 4. month := self readIntegerFrom: aStream next: 2. day := self readIntegerFrom: aStream next: 2. hour := self readIntegerFrom: aStream next: 2. minute := self readIntegerFrom: aStream next: 2. second := self readIntegerFrom: aStream next: 2. ^Timestamp fromDate: (Date newDay: day monthNumber: month year: year) andTime: (Time fromSeconds: 60 * (60 * hour + minute) + second)! ! WriteStream subclass: #JdmWriteStream instanceVariableNames: 'outputPacket ' classVariableNames: '' poolDictionaries: '' category: 'Mysql-Driver'! !JdmWriteStream methodsFor: 'accessing' stamp: 'jb 3/2/1999 20:43'! close " super close. self breakDependents "! ! !JdmWriteStream methodsFor: 'accessing' stamp: 'jb 3/2/1999 20:38'! flush " super flush. " self outputPacket flush.! ! !JdmWriteStream methodsFor: 'accessing' stamp: 'jb 3/2/1999 20:17'! nextPutAllNullTerminated: aCollection2 self nextPutAll: aCollection2. self nextPut: self class null asCharacter.! ! !JdmWriteStream methodsFor: 'accessing' stamp: 'jb 3/2/1999 19:29'! nextPutCommand: aCommand self nextPut: aCommand command asCharacter; nextPutAllNullTerminated: aCommand message! ! !JdmWriteStream methodsFor: 'accessing' stamp: 'jb 3/2/1999 20:37'! outputPacket ^outputPacket! ! !JdmWriteStream methodsFor: 'accessing' stamp: 'jb 3/2/1999 20:38'! outputPacket: p outputPacket := p! ! !JdmWriteStream methodsFor: 'accessing'! setWritePosition: aPosition position := aPosition > writeLimit ifTrue: [writeLimit] ifFalse: [aPosition]! ! !JdmWriteStream methodsFor: 'initialize'! initialize! ! "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "! JdmWriteStream class instanceVariableNames: ''! !JdmWriteStream class methodsFor: 'instance creation' stamp: 'jb 3/2/1999 20:40'! on: aCollection startingAt: aPosition outputPacket: op | ws | ws := (self on: aCollection) setWritePosition: aPosition. ws outputPacket: op. ^ws! ! !JdmWriteStream class methodsFor: 'instance creation' stamp: 'jb 3/2/1999 20:40'! xon: aCollection outputPacket: op | ws | ws := (super on: aCollection) initialize. ws outputPacket: op. ^ws! ! !JdmWriteStream class methodsFor: 'constants'! null ^0! ! Object subclass: #SocketStream instanceVariableNames: 'socket stream ' classVariableNames: '' poolDictionaries: '' category: 'Mysql-Driver'! !SocketStream methodsFor: 'as yet unclassified' stamp: 'jb 3/3/1999 18:39'! socket ^socket! ! !SocketStream methodsFor: 'as yet unclassified' stamp: 'jb 3/3/1999 18:39'! socket: s socket := s! ! !SocketStream methodsFor: 'as yet unclassified' stamp: 'jb 3/3/1999 18:52'! stream ^stream! ! !SocketStream methodsFor: 'as yet unclassified' stamp: 'jb 3/3/1999 18:52'! stream: s stream := s! ! SocketStream subclass: #SocketReadStream instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Mysql-Driver'! !SocketReadStream methodsFor: 'as yet unclassified' stamp: 'jb 3/3/1999 19:25'! next: anInt | s received | s := String new: anInt. (socket waitForDataUntil: Socket standardDeadline) ifFalse: [self error: 'receive timeout']. received := socket receiveDataInto: s. " Transcript show: s; cr. Transcript show: anInt printString. Transcript show: ','. Transcript show: received printString. Transcript cr. " ^s.! ! SocketStream subclass: #SocketWriteStream instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Mysql-Driver'! !SocketWriteStream methodsFor: 'as yet unclassified' stamp: 'jb 3/3/1999 18:59'! flush socket sendData: stream contents. stream := WriteStream on: (String new: 2000).! ! !SocketWriteStream methodsFor: 'as yet unclassified' stamp: 'jb 3/3/1999 18:53'! nextPutAll: s self stream nextPutAll: s.! !