peasys-ruby 1.0.2 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/lib/pea_client.rb CHANGED
@@ -1,478 +1,482 @@
1
- require 'socket'
2
- require 'json'
3
- require 'uri'
4
- require 'net/http'
5
-
6
- class PeaClient
7
- @@end_pack = "dipsjbiemg"
8
-
9
- ##
10
- # Initialize a new instance of the PeaClient class. Initiates a connexion with the AS/400 server.
11
- #
12
- # Params:
13
- # +partition_name+:: DNS name (name of the partition) of the remote AS/400 server.
14
- # +port+:: Port used for the data exchange between the client and the server.
15
- # +username+:: Username of the AS/400 profile used for connexion.
16
- # +password+:: Password of the AS/400 profile used for connexion.
17
- # +id_client+:: ID of the client account on the DIPS website.
18
- # +online_version+:: Set to true if you want to use the online version of Peasys (<see cref="https://dips400.com/docs/connexion"/>).
19
- # +retrieve_statistics+:: Set to true if you want the statistics of the license key use to be collect.
20
- #
21
- # raises a PeaInvalidCredentialsError if credentials are empty.
22
- # raises a PeaConnexionError if an error occured during the connexion process.
23
- # raises a PeaInvalidCredentialsError if IBMi credentials are invalid.
24
-
25
- def initialize(ip_adress, partition_name, port, username, password, id_client, online_version, retrieve_statistics)
26
-
27
- if ip_adress.empty? || username.empty? || password.empty?
28
- raise PeaInvalidCredentialsError.new("Parameters of the PeaClient should not be either null or empty")
29
- end
30
-
31
- @ip_adress = ip_adress
32
- @id_client = id_client
33
- @partition_name = partition_name
34
- @username = username
35
- @password = password
36
- @port = port
37
- @online_version = online_version
38
- @retrieve_statistics = retrieve_statistics
39
- @connexion_status = "ds"
40
- @connexion_message = "ds"
41
-
42
- token = "xqdsg27010wmca6052009050000000IDSP1tiupozxreybjhlk"
43
- if online_version
44
- begin
45
- uri = URI("https://dips400.com/api/license-key/retrieve-token/#{partition_name}/#{id_client}")
46
- res = Net::HTTP.get_response(uri)
47
-
48
- data = JSON.parse(res.body)
49
- token = data["token"]
50
- is_valid = data["isValid"]
51
-
52
- if not(is_valid)
53
- raise PeaInvalidLicenseKeyError.new("Your subscription is not valid, visit https://dips400.com/account/subscriptions for more information.")
54
- end
55
-
56
- rescue PeaInvalidLicenseKeyError => e
57
- raise e
58
- rescue StandardError => error
59
- # If dips400.com doesn't respond, let's try an affline verification with the offline token
60
- end
61
- end
62
-
63
- begin
64
- @tcp_client = TCPSocket.new ip_adress, port
65
- rescue => error
66
- raise PeaConnexionError.new(error.full_message)
67
- else
68
- login = username.ljust(10, " ") + token.ljust(50, " ") + password
69
- @tcp_client.send(login, 0)
70
- @connexion_status = @tcp_client.read(1)
71
-
72
- case @connexion_status
73
- when "1"
74
- @connexion_message = "Connected"
75
- @connexion_status = 1
76
- when "2"
77
- @connexion_message = "Unable to set profile, check profile validity."
78
- @connexion_status = 2
79
- raise PeaConnexionError.new("Unable to set profile, check profile validity.")
80
- when "3"
81
- @connexion_message = "Invalid credential"
82
- @connexion_status = 1
83
- raise PeaInvalidCredentialsError.new("Invalid userName or password, check again")
84
- when "B"
85
- @connexion_message = "Peasys Online : your token connexion is no longer valid, retry to connect."
86
- @connexion_status = 5
87
- raise PeaConnexionError.new("Peasys Online : your token connexion is no longer valid, retry to connect.")
88
- when "D"
89
- @connexion_message = "Peasys Online : the partition name you provided doesn't match the actual name of the machine."
90
- @connexion_status = 6
91
- raise PeaConnexionError.new("Peasys Online : the partition name you provided doesn't match the actual name of the machine.")
92
- when "E"
93
- @connexion_message = "You reached the max number of simultaneously connected peasys users for that partition and license key. Contact us for upgrading your license."
94
- @connexion_status = 7
95
- raise PeaConnexionError.new("You reached the max number of simultaneously connected peasys users for that partition and license key. Contact us for upgrading your license.")
96
- when "F"
97
- @connexion_message = "Your license is no longer valid. Subscribe to another license in order to continue using Peasys."
98
- @connexion_status = 8
99
- raise PeaConnexionError.new("Your license is no longer valid. Subscribe to another license in order to continue using Peasys.")
100
- when "0" , "A" , "C" , "G"
101
- @connexion_message = "Error linked to DIPS source code. Please, contact us immediatly to fix the issue."
102
- @connexion_status = -1
103
- raise PeaConnexionError.new("Error linked to DIPS source code. Please, contact us immediatly to fix the issue.")
104
- else
105
- raise PeaConnexionError.new("Exception during connexion process, contact us for more informations")
106
- end
107
- end
108
- end
109
-
110
- ##
111
- # Sends the SELECT SQL query to the server that execute it and retrieve the desired data.
112
- #
113
- # Params:
114
- # +query+:: SQL query that should start with the SELECT keyword.
115
- #
116
- # raises a PeaInvalidSyntaxQueryError if query is empty or doesn't start with SELECT.
117
-
118
- def execute_select(query)
119
- if query.empty?
120
- raise PeaInvalidSyntaxQueryError.new("Query should not be either null or empty")
121
- end
122
- if !query.upcase.start_with?("SELECT")
123
- raise PeaInvalidSyntaxQueryError.new("Query should start with the SELECT SQL keyword")
124
- end
125
-
126
- result, list_name, nb_row, sql_state, sql_message = build_data(query)
127
-
128
- return PeaSelectResponse.new(sql_message.eql?("00000"), sql_message, sql_state, result, nb_row, list_name)
129
- end
130
-
131
- ##
132
- # Sends the UPDATE SQL query to the server that execute it and retrieve the desired data.
133
- #
134
- # Params:
135
- # +query+:: SQL query that should start with the UPDATE keyword.
136
- #
137
- # raises a PeaInvalidSyntaxQueryError if query is empty or doesn't start with UPDATE.
138
-
139
- def execute_update(query)
140
- if query.empty?
141
- raise PeaInvalidSyntaxQueryError.new("Query should not be either null or empty")
142
- end
143
- if !query.upcase.start_with?("UPDATE")
144
- raise PeaInvalidSyntaxQueryError.new("Query should start with the UPDATE SQL keyword")
145
- end
146
-
147
- nb_row, sql_state, sql_message = modify_table(query)
148
- has_succeeded = sql_state.eql?("00000") || sql_state.eql?("01504")
149
-
150
- return PeaUpdateResponse.new(has_succeeded, sql_message, sql_state, nb_row)
151
- end
152
-
153
- ##
154
- # Sends the CREATE SQL query to the server that execute it and retrieve the desired data.
155
- #
156
- # Params:
157
- # +query+:: SQL query that should start with the CREATE keyword.
158
- #
159
- # raises a PeaInvalidSyntaxQueryError if query is empty or doesn't start with CREATE.
160
-
161
- def execute_create(query)
162
- if query.empty?
163
- raise PeaInvalidSyntaxQueryError.new("Query should not be either null or empty")
164
- end
165
- if !query.upcase.start_with?("CREATE")
166
- raise PeaInvalidSyntaxQueryError.new("Query should start with the CREATE SQL keyword")
167
- end
168
-
169
- nb_row, sql_state, sql_message = modify_table(query)
170
-
171
- query_words = query.split(' ')
172
- tb_schema = Hash.new()
173
- if query_words[1].upcase.eql?("TABLE")
174
- names = query_words[2].split('/')
175
- tb_query = """SELECT COLUMN_NAME, ORDINAL_POSITION, DATA_TYPE, LENGTH, NUMERIC_SCALE, IS_NULLABLE, IS_UPDATABLE, NUMERIC_PRECISION FROM
176
- QSYS2.SYSCOLUMNS WHERE SYSTEM_TABLE_NAME = '""" + names[1].upcase + "' AND SYSTEM_TABLE_SCHEMA = '" + names[0].upcase + "'"
177
-
178
- result, list_name, nb_row, sql_state, sql_message = build_data(tb_query)
179
-
180
- for i in 0..(nb_row - 1) do
181
- tb_schema["column_name"] = ColumnInfo.new(result["COLUMN_NAME"][i], result["ORDINAL_POSITION"][i], result["DATA_TYPE"][i], result["LENGTH"][i],
182
- result["NUMERIC_SCALE"][i], result["IS_NULLABLE"][i], result["IS_UPDATABLE"][i], result["NUMERIC_PRECISION"][i])
183
- end
184
- end
185
-
186
- case query_words[1].upcase
187
- when "TABLE"
188
- return PeaCreateResponse.new(sql_message.eql?("00000"), sql_message, sql_state, "", "", tb_schema)
189
- when "INDEX"
190
- return PeaCreateResponse.new(sql_message.eql?("00000"), sql_message, sql_state, "", query_words[2], "")
191
- when "DATABASE"
192
- return PeaCreateResponse.new(sql_message.eql?("00000"), sql_message, sql_state, query_words[2], "", "")
193
- else
194
- raise PeaConnexionError.new("Exception during connexion process, contact us for more informations")
195
- end
196
- end
197
-
198
- ##
199
- # Sends the DELETE SQL query to the server that execute it and retrieve the desired data.
200
- #
201
- # Params:
202
- # +query+:: SQL query that should start with the DELETE keyword.
203
- #
204
- # raises a PeaInvalidSyntaxQueryError if query is empty or doesn't start with DELETE.
205
-
206
- def execute_delete(query)
207
- if query.empty?
208
- raise PeaInvalidSyntaxQueryError.new("Query should not be either null or empty")
209
- end
210
- if !query.upcase.start_with?("DELETE")
211
- raise PeaInvalidSyntaxQueryError.new("Query should start with the DELETE SQL keyword")
212
- end
213
-
214
- nb_row, sql_state, sql_message = modify_table(query)
215
-
216
- return PeaDeleteResponse.new(sql_message.eql?("00000"), sql_message, sql_state, nb_row)
217
- end
218
-
219
- ##
220
- # Sends the ALTER SQL query to the server that execute it and retrieve the desired data.
221
- #
222
- # Params:
223
- # +query+:: SQL query that should start with the ALTER keyword.
224
- #
225
- # raises a PeaInvalidSyntaxQueryError if query is empty or doesn't start with ALTER.
226
-
227
- def execute_alter(query, retrieve_table_schema)
228
- if query.empty?
229
- raise PeaInvalidSyntaxQueryError.new("Query should not be either null or empty")
230
- end
231
- if !query.upcase.start_with?("ALTER")
232
- raise PeaInvalidSyntaxQueryError.new("Query should start with the ALTER SQL keyword")
233
- end
234
-
235
- nb_row, sql_state, sql_message = modify_table(query)
236
-
237
- tb_schema = Hash.new()
238
- if retrieve_table_schema
239
- query_words = query.split(' ')
240
- names = query_words[2].split('/')
241
- tb_query = """SELECT COLUMN_NAME, ORDINAL_POSITION, DATA_TYPE, LENGTH, NUMERIC_SCALE, IS_NULLABLE, IS_UPDATABLE, NUMERIC_PRECISION FROM
242
- QSYS2.SYSCOLUMNS WHERE SYSTEM_TABLE_NAME = '""" + names[1].upcase + "' AND SYSTEM_TABLE_SCHEMA = '" + names[0].upcase + "'"
243
-
244
- result, list_name, nb_row, sql_state, sql_message = build_data(tb_query)
245
-
246
- for i in 0..(nb_row - 1) do
247
- tb_schema["column_name"] = ColumnInfo.new(result["COLUMN_NAME"][i], result["ORDINAL_POSITION"][i], result["DATA_TYPE"][i], result["LENGTH"][i],
248
- result["NUMERIC_SCALE"][i], result["IS_NULLABLE"][i], result["IS_UPDATABLE"][i], result["NUMERIC_PRECISION"][i])
249
- end
250
- end
251
-
252
- return PeaAlterResponse.new(sql_message.eql?("00000"), sql_message, sql_state, tb_schema)
253
- end
254
-
255
- ##
256
- # Sends the DROP SQL query to the server that execute it and retrieve the desired data.
257
- #
258
- # Params:
259
- # +query+:: SQL query that should start with the DROP keyword.
260
- #
261
- # raises a PeaInvalidSyntaxQueryError if query is empty or doesn't start with DROP.
262
-
263
- def execute_drop(query)
264
- if query.empty?
265
- raise PeaInvalidSyntaxQueryError.new("Query should not be either null or empty")
266
- end
267
- if !query.upcase.start_with?("DROP")
268
- raise PeaInvalidSyntaxQueryError.new("Query should start with the DROP SQL keyword")
269
- end
270
-
271
- nb_row, sql_state, sql_message = modify_table(query)
272
-
273
- return PeaDropResponse.new(sql_message.eql?("00000"), sql_message, sql_state)
274
- end
275
-
276
- ##
277
- # Sends the INSERT SQL query to the server that execute it and retrieve the desired data.
278
- #
279
- # Params:
280
- # +query+:: SQL query that should start with the INSERT keyword.
281
- #
282
- # raises a PeaInvalidSyntaxQueryError if query is empty or doesn't start with INSERT.
283
-
284
- def execute_insert(query)
285
- if query.empty?
286
- raise PeaInvalidSyntaxQueryError.new("Query should not be either null or empty")
287
- end
288
- if !query.upcase.start_with?("INSERT")
289
- raise PeaInvalidSyntaxQueryError.new("Query should start with the INSERT SQL keyword")
290
- end
291
-
292
- nb_row, sql_state, sql_message = modify_table(query)
293
-
294
- return PeaInsertResponse.new(sql_message.eql?("00000"), sql_message, sql_state, nb_row)
295
- end
296
-
297
- ##
298
- # Sends the SQL query to the server that execute it and retrieve the desired data.
299
- #
300
- # Params:
301
- # +query+:: SQL query.
302
- #
303
- # raises a PeaInvalidSyntaxQueryError if query is empty.
304
-
305
- def execute_sql(query)
306
- if query.empty?
307
- raise PeaInvalidSyntaxQueryError.new("Query should not be either null or empty")
308
- end
309
-
310
- nb_row, sql_state, sql_message = modify_table(query)
311
-
312
- return PeaResponse.new(sql_message.eql?("00000"), sql_message, sql_state)
313
- end
314
-
315
- ##
316
- # Sends a OS/400 command to the server and retreives the potential warning messages.
317
- #
318
- # Params:
319
- # +command+:: The command that will be sent to the server.
320
-
321
- def execute_command(command)
322
- data = retrieve_data("exas" + command + @@end_pack)
323
- description_offset = 112
324
- result = Array.new()
325
-
326
- /C[A-Z]{2}[0-9]{4}/.match(data) do |m|
327
-
328
- if !m[0].start_with?("CPI") && m.offset(0)[0] + description_offset < data.length
329
- description = data[m.offset(0)[0] + description_offset..(data.length - (m.offset(0)[0] + description_offset))]
330
- description = description[0..description.index(".")]
331
- description = description.gsub(/[^a-zA-Z0-9 ._'*:-]/, '')
332
- end
333
-
334
- result.append(m[0] + " " + description)
335
-
336
- end
337
- return PeaCommandResponse.new(result)
338
- end
339
-
340
- ##
341
- # Closes the TCP connexion with the server.
342
-
343
- def disconnect()
344
- @tcp_client.send("stopdipsjbiemg", 0)
345
- @tcp_client.close()
346
- end
347
-
348
- def id_client
349
- @id_client
350
- end
351
-
352
- def partition_name
353
- @partition_name
354
- end
355
-
356
- def username
357
- @username
358
- end
359
-
360
- def port
361
- @port
362
- end
363
-
364
- def online_version
365
- @online_version
366
- end
367
-
368
- def retrieve_statistics
369
- @retrieve_statistics
370
- end
371
-
372
- def connexion_status
373
- @connexion_status
374
- end
375
-
376
- def connexion_message
377
- @connexion_message
378
- end
379
-
380
- private
381
-
382
- def build_data(query)
383
- header = retrieve_data("geth" + query + @@end_pack)
384
- sql_state = "00000"
385
- sql_message = "SELECT correctly executed"
386
-
387
- begin
388
- header_data = JSON.parse(header)
389
- rescue
390
- sql_state = header[1..5];
391
- sql_message = header[6..];
392
- else
393
- list_name = Array.new()
394
- list_type = Array.new()
395
- list_prec = Array.new()
396
- list_scal = Array.new();
397
-
398
- header_data.each do |item|
399
- list_name = list_name.append(item["name"].strip)
400
- list_type = list_type.append(item["type"].to_i)
401
- list_prec = list_prec.append(item["prec"].to_i)
402
- list_scal = list_scal.append(item["scal"].to_i)
403
- end
404
- end
405
-
406
- nb_col = list_name.length
407
- sum_precision = 0
408
- result = Hash.new()
409
- list_prec.each_index do |i|
410
- sum_precision += list_prec[i]
411
- result[list_name[i]] = Array.new()
412
- end
413
-
414
- data = retrieve_data("getd" + query + @@end_pack)
415
-
416
- # sends statistics
417
-
418
- nb_row = data.length / sum_precision;
419
- pointer = 0;
420
- while pointer != data.length
421
- for m in 0..(nb_col - 1) do
422
- scale = list_scal[m]
423
- precision = list_prec[m]
424
- type = list_type[m]
425
- name = list_name[m]
426
-
427
- if ((type == 484 && scale != 0) || (type == 485 && scale != 0) || (type == 488 && scale != 0) || (type == 489 && scale != 0)) # numeric packed
428
- temp_float_data = data[pointer..(pointer + precision - 1)].to_f / 10 ** scale
429
- pointer += precision;
430
- result[name].append(temp_float_data.to_s);
431
- elsif (type == 492 || type == 493) # long
432
- result[name].append(data[pointer..(pointer + 20 - 1)].strip);
433
- pointer += 20;
434
- elsif (type == 496 || type == 497) # int
435
- result[name].append(data[pointer..(pointer + 10 - 1)].strip);
436
- pointer += 10;
437
- elsif (type == 500 || type == 501) # short
438
- result[name].append(data[pointer..(pointer + 5 - 1)].strip);
439
- pointer += 5;
440
- else # string, date, time, timestamp
441
- result[name].append(data[pointer..(pointer + precision - 1)].strip);
442
- pointer += precision;
443
- end
444
- end
445
- end
446
- return result, list_name, nb_row, sql_state, sql_message
447
- end
448
-
449
- def modify_table(query)
450
- header = retrieve_data("updt" + query + @@end_pack)
451
- sql_state = header[1..5]
452
- sql_message = header[6..]
453
-
454
- # retrieve stats
455
-
456
- row_count = 0
457
- if query.upcase.start_with?("INSERT") || query.upcase.start_with?("UPDATE") || query.upcase.start_with?("DELETE")
458
- row_count = sql_state.eql?("00000") ? sql_message[..1].to_i : 0
459
- end
460
-
461
- return row_count, sql_state, sql_message
462
- end
463
-
464
- def retrieve_data(command)
465
-
466
- @tcp_client.send(command, 0)
467
-
468
- data = ""
469
- if command.start_with?("geth") || command.start_with?("updt")
470
- data += "["
471
- end
472
-
473
- while data.length < @@end_pack.length || data[(data.length - @@end_pack.length)..(data.length-1)] != @@end_pack
474
- data += @tcp_client.read(1)
475
- end
476
- return data[0..(data.length - (@@end_pack.length + 1))]
477
- end
1
+ require 'socket'
2
+ require 'json'
3
+ require 'uri'
4
+ require 'net/http'
5
+
6
+
7
+ class PeaClient
8
+ @@end_pack = "dipsjbiemg"
9
+
10
+ ##
11
+ # Initialize a new instance of the PeaClient class. Initiates a connexion with the AS/400 server.
12
+ #
13
+ # Params:
14
+ # +partition_name+:: DNS name (name of the partition) of the remote AS/400 server.
15
+ # +port+:: Port used for the data exchange between the client and the server.
16
+ # +username+:: Username of the AS/400 profile used for connexion.
17
+ # +password+:: Password of the AS/400 profile used for connexion.
18
+ # +id_client+:: ID of the client account on the DIPS website.
19
+ # +online_version+:: Set to true if you want to use the online version of Peasys (<see cref="https://dips400.com/docs/connexion"/>).
20
+ # +retrieve_statistics+:: Set to true if you want the statistics of the license key use to be collect.
21
+ #
22
+ # raises a PeaInvalidCredentialsError if credentials are empty.
23
+ # raises a PeaConnexionError if an error occured during the connexion process.
24
+ # raises a PeaInvalidCredentialsError if IBMi credentials are invalid.
25
+
26
+ def initialize(ip_adress, partition_name, port, username, password, id_client, online_version, retrieve_statistics)
27
+
28
+ if ip_adress.empty? || username.empty? || password.empty?
29
+ raise PeaInvalidCredentialsError.new("Parameters of the PeaClient should not be either null or empty")
30
+ end
31
+
32
+ @ip_adress = ip_adress
33
+ @id_client = id_client
34
+ @partition_name = partition_name
35
+ @username = username
36
+ @password = password
37
+ @port = port
38
+ @online_version = online_version
39
+ @retrieve_statistics = retrieve_statistics
40
+ @connexion_status = "ds"
41
+ @connexion_message = "ds"
42
+
43
+ token = "xqdsg27010wmca6052009050000000IDSP1tiupozxreybjhlk"
44
+ if online_version
45
+ begin
46
+ uri = URI("https://dips400.com/api/license-key/retrieve-token/#{partition_name}/#{id_client}")
47
+ res = Net::HTTP.get_response(uri)
48
+
49
+ data = JSON.parse(res.body)
50
+ token = data["token"]
51
+ is_valid = data["isValid"]
52
+
53
+ if not(is_valid)
54
+ raise PeaInvalidLicenseKeyError.new("Your subscription is not valid, visit https://dips400.com/account/subscriptions for more information.")
55
+ end
56
+
57
+ rescue PeaInvalidLicenseKeyError => e
58
+ raise e
59
+ rescue StandardError => error
60
+ # If dips400.com doesn't respond, let's try an affline verification with the offline token
61
+ end
62
+ end
63
+
64
+ begin
65
+ @tcp_client = TCPSocket.new ip_adress, port
66
+ rescue => error
67
+ raise PeaConnexionError.new(error.full_message)
68
+ else
69
+ login = username.ljust(10, " ") + token.ljust(50, " ") + password
70
+ @tcp_client.send(login, 0)
71
+ @connexion_status = @tcp_client.read(1)
72
+
73
+ case @connexion_status
74
+ when "1"
75
+ @connexion_message = "Connected"
76
+ @connexion_status = 1
77
+ when "2"
78
+ @connexion_message = "Unable to set profile, check profile validity."
79
+ @connexion_status = 2
80
+ raise PeaConnexionError.new("Unable to set profile, check profile validity.")
81
+ when "3"
82
+ @connexion_message = "Invalid credential"
83
+ @connexion_status = 1
84
+ raise PeaInvalidCredentialsError.new("Invalid userName or password, check again")
85
+ when "B"
86
+ @connexion_message = "Peasys Online : your token connexion is no longer valid, retry to connect."
87
+ @connexion_status = 5
88
+ raise PeaConnexionError.new("Peasys Online : your token connexion is no longer valid, retry to connect.")
89
+ when "D"
90
+ @connexion_message = "Peasys Online : the partition name you provided doesn't match the actual name of the machine."
91
+ @connexion_status = 6
92
+ raise PeaConnexionError.new("Peasys Online : the partition name you provided doesn't match the actual name of the machine.")
93
+ when "E"
94
+ @connexion_message = "You reached the max number of simultaneously connected peasys users for that partition and license key. Contact us for upgrading your license."
95
+ @connexion_status = 7
96
+ raise PeaConnexionError.new("You reached the max number of simultaneously connected peasys users for that partition and license key. Contact us for upgrading your license.")
97
+ when "F"
98
+ @connexion_message = "Your license is no longer valid. Subscribe to another license in order to continue using Peasys."
99
+ @connexion_status = 8
100
+ raise PeaConnexionError.new("Your license is no longer valid. Subscribe to another license in order to continue using Peasys.")
101
+ when "0" , "A" , "C" , "G"
102
+ @connexion_message = "Error linked to DIPS source code. Please, contact us immediatly to fix the issue."
103
+ @connexion_status = -1
104
+ raise PeaConnexionError.new("Error linked to DIPS source code. Please, contact us immediatly to fix the issue.")
105
+ else
106
+ raise PeaConnexionError.new("Exception during connexion process, contact us for more informations")
107
+ end
108
+ end
109
+ end
110
+
111
+ ##
112
+ # Sends the SELECT SQL query to the server that execute it and retrieve the desired data.
113
+ #
114
+ # Params:
115
+ # +query+:: SQL query that should start with the SELECT keyword.
116
+ #
117
+ # raises a PeaInvalidSyntaxQueryError if query is empty or doesn't start with SELECT.
118
+
119
+ def execute_select(query)
120
+ if query.empty?
121
+ raise PeaInvalidSyntaxQueryError.new("Query should not be either null or empty")
122
+ end
123
+ if !query.upcase.start_with?("SELECT") && !query.upcase.start_with?("WITH")
124
+ raise PeaInvalidSyntaxQueryError.new("Query should start with the SELECT or WITH SQL keyword")
125
+ end
126
+
127
+ result, list_name, nb_row, sql_state, sql_message = build_data(query)
128
+
129
+ return PeaSelectResponse.new(sql_message.eql?("00000"), sql_message, sql_state, result, nb_row, list_name)
130
+ end
131
+
132
+ ##
133
+ # Sends the UPDATE SQL query to the server that execute it and retrieve the desired data.
134
+ #
135
+ # Params:
136
+ # +query+:: SQL query that should start with the UPDATE keyword.
137
+ #
138
+ # raises a PeaInvalidSyntaxQueryError if query is empty or doesn't start with UPDATE.
139
+
140
+ def execute_update(query)
141
+ if query.empty?
142
+ raise PeaInvalidSyntaxQueryError.new("Query should not be either null or empty")
143
+ end
144
+ if !query.upcase.start_with?("UPDATE")
145
+ raise PeaInvalidSyntaxQueryError.new("Query should start with the UPDATE SQL keyword")
146
+ end
147
+
148
+ nb_row, sql_state, sql_message = modify_table(query)
149
+ has_succeeded = sql_state.eql?("00000") || sql_state.eql?("01504")
150
+
151
+ return PeaUpdateResponse.new(has_succeeded, sql_message, sql_state, nb_row)
152
+ end
153
+
154
+ ##
155
+ # Sends the CREATE SQL query to the server that execute it and retrieve the desired data.
156
+ #
157
+ # Params:
158
+ # +query+:: SQL query that should start with the CREATE keyword.
159
+ #
160
+ # raises a PeaInvalidSyntaxQueryError if query is empty or doesn't start with CREATE.
161
+
162
+ def execute_create(query)
163
+ if query.empty?
164
+ raise PeaInvalidSyntaxQueryError.new("Query should not be either null or empty")
165
+ end
166
+ if !query.upcase.start_with?("CREATE")
167
+ raise PeaInvalidSyntaxQueryError.new("Query should start with the CREATE SQL keyword")
168
+ end
169
+
170
+ nb_row, sql_state, sql_message = modify_table(query)
171
+
172
+ query_words = query.split(' ')
173
+ tb_schema = Hash.new()
174
+ if query_words[1].upcase.eql?("TABLE")
175
+ names = query_words[2].split('/')
176
+ tb_query = """SELECT COLUMN_NAME, ORDINAL_POSITION, DATA_TYPE, LENGTH, NUMERIC_SCALE, IS_NULLABLE, IS_UPDATABLE, NUMERIC_PRECISION FROM
177
+ QSYS2.SYSCOLUMNS WHERE SYSTEM_TABLE_NAME = '""" + names[1].upcase + "' AND SYSTEM_TABLE_SCHEMA = '" + names[0].upcase + "'"
178
+
179
+ result, list_name, nb_row, sql_state, sql_message = build_data(tb_query)
180
+
181
+ for i in 0..(nb_row - 1) do
182
+ tb_schema["column_name"] = ColumnInfo.new(result["COLUMN_NAME"][i], result["ORDINAL_POSITION"][i], result["DATA_TYPE"][i], result["LENGTH"][i],
183
+ result["NUMERIC_SCALE"][i], result["IS_NULLABLE"][i], result["IS_UPDATABLE"][i], result["NUMERIC_PRECISION"][i])
184
+ end
185
+ end
186
+
187
+ case query_words[1].upcase
188
+ when "TABLE"
189
+ return PeaCreateResponse.new(sql_message.eql?("00000"), sql_message, sql_state, "", "", tb_schema)
190
+ when "INDEX"
191
+ return PeaCreateResponse.new(sql_message.eql?("00000"), sql_message, sql_state, "", query_words[2], "")
192
+ when "DATABASE"
193
+ return PeaCreateResponse.new(sql_message.eql?("00000"), sql_message, sql_state, query_words[2], "", "")
194
+ else
195
+ raise PeaConnexionError.new("Exception during connexion process, contact us for more informations")
196
+ end
197
+ end
198
+
199
+ ##
200
+ # Sends the DELETE SQL query to the server that execute it and retrieve the desired data.
201
+ #
202
+ # Params:
203
+ # +query+:: SQL query that should start with the DELETE keyword.
204
+ #
205
+ # raises a PeaInvalidSyntaxQueryError if query is empty or doesn't start with DELETE.
206
+
207
+ def execute_delete(query)
208
+ if query.empty?
209
+ raise PeaInvalidSyntaxQueryError.new("Query should not be either null or empty")
210
+ end
211
+ if !query.upcase.start_with?("DELETE")
212
+ raise PeaInvalidSyntaxQueryError.new("Query should start with the DELETE SQL keyword")
213
+ end
214
+
215
+ nb_row, sql_state, sql_message = modify_table(query)
216
+
217
+ return PeaDeleteResponse.new(sql_message.eql?("00000"), sql_message, sql_state, nb_row)
218
+ end
219
+
220
+ ##
221
+ # Sends the ALTER SQL query to the server that execute it and retrieve the desired data.
222
+ #
223
+ # Params:
224
+ # +query+:: SQL query that should start with the ALTER keyword.
225
+ #
226
+ # raises a PeaInvalidSyntaxQueryError if query is empty or doesn't start with ALTER.
227
+
228
+ def execute_alter(query, retrieve_table_schema)
229
+ if query.empty?
230
+ raise PeaInvalidSyntaxQueryError.new("Query should not be either null or empty")
231
+ end
232
+ if !query.upcase.start_with?("ALTER")
233
+ raise PeaInvalidSyntaxQueryError.new("Query should start with the ALTER SQL keyword")
234
+ end
235
+
236
+ nb_row, sql_state, sql_message = modify_table(query)
237
+
238
+ tb_schema = Hash.new()
239
+ if retrieve_table_schema
240
+ query_words = query.split(' ')
241
+ names = query_words[2].split('/')
242
+ tb_query = """SELECT COLUMN_NAME, ORDINAL_POSITION, DATA_TYPE, LENGTH, NUMERIC_SCALE, IS_NULLABLE, IS_UPDATABLE, NUMERIC_PRECISION FROM
243
+ QSYS2.SYSCOLUMNS WHERE SYSTEM_TABLE_NAME = '""" + names[1].upcase + "' AND SYSTEM_TABLE_SCHEMA = '" + names[0].upcase + "'"
244
+
245
+ result, list_name, nb_row, sql_state, sql_message = build_data(tb_query)
246
+
247
+ for i in 0..(nb_row - 1) do
248
+ tb_schema["column_name"] = ColumnInfo.new(result["COLUMN_NAME"][i], result["ORDINAL_POSITION"][i], result["DATA_TYPE"][i], result["LENGTH"][i],
249
+ result["NUMERIC_SCALE"][i], result["IS_NULLABLE"][i], result["IS_UPDATABLE"][i], result["NUMERIC_PRECISION"][i])
250
+ end
251
+ end
252
+
253
+ return PeaAlterResponse.new(sql_message.eql?("00000"), sql_message, sql_state, tb_schema)
254
+ end
255
+
256
+ ##
257
+ # Sends the DROP SQL query to the server that execute it and retrieve the desired data.
258
+ #
259
+ # Params:
260
+ # +query+:: SQL query that should start with the DROP keyword.
261
+ #
262
+ # raises a PeaInvalidSyntaxQueryError if query is empty or doesn't start with DROP.
263
+
264
+ def execute_drop(query)
265
+ if query.empty?
266
+ raise PeaInvalidSyntaxQueryError.new("Query should not be either null or empty")
267
+ end
268
+ if !query.upcase.start_with?("DROP")
269
+ raise PeaInvalidSyntaxQueryError.new("Query should start with the DROP SQL keyword")
270
+ end
271
+
272
+ nb_row, sql_state, sql_message = modify_table(query)
273
+
274
+ return PeaDropResponse.new(sql_message.eql?("00000"), sql_message, sql_state)
275
+ end
276
+
277
+ ##
278
+ # Sends the INSERT SQL query to the server that execute it and retrieve the desired data.
279
+ #
280
+ # Params:
281
+ # +query+:: SQL query that should start with the INSERT keyword.
282
+ #
283
+ # raises a PeaInvalidSyntaxQueryError if query is empty or doesn't start with INSERT.
284
+
285
+ def execute_insert(query)
286
+ if query.empty?
287
+ raise PeaInvalidSyntaxQueryError.new("Query should not be either null or empty")
288
+ end
289
+ if !query.upcase.start_with?("INSERT")
290
+ raise PeaInvalidSyntaxQueryError.new("Query should start with the INSERT SQL keyword")
291
+ end
292
+
293
+ nb_row, sql_state, sql_message = modify_table(query)
294
+
295
+ return PeaInsertResponse.new(sql_message.eql?("00000"), sql_message, sql_state, nb_row)
296
+ end
297
+
298
+ ##
299
+ # Sends the SQL query to the server that execute it and retrieve the desired data.
300
+ #
301
+ # Params:
302
+ # +query+:: SQL query.
303
+ #
304
+ # raises a PeaInvalidSyntaxQueryError if query is empty.
305
+
306
+ def execute_sql(query)
307
+ if query.empty?
308
+ raise PeaInvalidSyntaxQueryError.new("Query should not be either null or empty")
309
+ end
310
+
311
+ nb_row, sql_state, sql_message = modify_table(query)
312
+
313
+ return PeaResponse.new(sql_message.eql?("00000"), sql_message, sql_state)
314
+ end
315
+
316
+ ##
317
+ # Sends a OS/400 command to the server and retreives the potential warning messages.
318
+ #
319
+ # Params:
320
+ # +command+:: The command that will be sent to the server.
321
+
322
+ def execute_command(command)
323
+ data = retrieve_data("exas" + command + @@end_pack)
324
+ description_offset = 112
325
+ result = Array.new()
326
+
327
+ /C[A-Z]{2}[0-9]{4}/.match(data) do |m|
328
+
329
+ if !m[0].start_with?("CPI") && m.offset(0)[0] + description_offset < data.length
330
+ description = data[m.offset(0)[0] + description_offset..(data.length - (m.offset(0)[0] + description_offset))]
331
+ description = description[0..description.index(".")]
332
+ description = description.gsub(/[^a-zA-Z0-9 ._'*:-]/, '')
333
+ end
334
+
335
+ result.append(m[0] + " " + description)
336
+
337
+ end
338
+ return PeaCommandResponse.new(result)
339
+ end
340
+
341
+ ##
342
+ # Closes the TCP connexion with the server.
343
+
344
+ def disconnect()
345
+ return if @tcp_client.nil? || @tcp_client.closed?
346
+ @tcp_client.send("stopdipsjbiemg", 0)
347
+ @tcp_client.close()
348
+ rescue IOError
349
+ # Socket already closed, ignore
350
+ end
351
+
352
+ def id_client
353
+ @id_client
354
+ end
355
+
356
+ def partition_name
357
+ @partition_name
358
+ end
359
+
360
+ def username
361
+ @username
362
+ end
363
+
364
+ def port
365
+ @port
366
+ end
367
+
368
+ def online_version
369
+ @online_version
370
+ end
371
+
372
+ def retrieve_statistics
373
+ @retrieve_statistics
374
+ end
375
+
376
+ def connexion_status
377
+ @connexion_status
378
+ end
379
+
380
+ def connexion_message
381
+ @connexion_message
382
+ end
383
+
384
+ private
385
+
386
+ def build_data(query)
387
+ header = retrieve_data("geth" + query + @@end_pack)
388
+ sql_state = "00000"
389
+ sql_message = "SELECT correctly executed"
390
+
391
+ begin
392
+ header_data = JSON.parse(header)
393
+ rescue
394
+ sql_state = header[1..5];
395
+ sql_message = header[6..];
396
+ else
397
+ list_name = Array.new()
398
+ list_type = Array.new()
399
+ list_prec = Array.new()
400
+ list_scal = Array.new();
401
+
402
+ header_data.each do |item|
403
+ list_name = list_name.append(item["name"].strip)
404
+ list_type = list_type.append(item["type"].to_i)
405
+ list_prec = list_prec.append(item["prec"].to_i)
406
+ list_scal = list_scal.append(item["scal"].to_i)
407
+ end
408
+ end
409
+
410
+ nb_col = list_name.length
411
+ sum_precision = 0
412
+ result = Hash.new()
413
+ list_prec.each_index do |i|
414
+ sum_precision += list_prec[i]
415
+ result[list_name[i]] = Array.new()
416
+ end
417
+
418
+ data = retrieve_data("getd" + query + @@end_pack)
419
+
420
+ # sends statistics
421
+
422
+ nb_row = data.length / sum_precision;
423
+ pointer = 0;
424
+ while pointer != data.length
425
+ for m in 0..(nb_col - 1) do
426
+ scale = list_scal[m]
427
+ precision = list_prec[m]
428
+ type = list_type[m]
429
+ name = list_name[m]
430
+
431
+ if ((type == 484 && scale != 0) || (type == 485 && scale != 0) || (type == 488 && scale != 0) || (type == 489 && scale != 0)) # numeric packed
432
+ temp_float_data = data[pointer..(pointer + precision - 1)].to_f / 10 ** scale
433
+ pointer += precision;
434
+ result[name].append(temp_float_data.to_s);
435
+ elsif (type == 492 || type == 493) # long
436
+ result[name].append(data[pointer..(pointer + 20 - 1)].strip);
437
+ pointer += 20;
438
+ elsif (type == 496 || type == 497) # int
439
+ result[name].append(data[pointer..(pointer + 10 - 1)].strip);
440
+ pointer += 10;
441
+ elsif (type == 500 || type == 501) # short
442
+ result[name].append(data[pointer..(pointer + 5 - 1)].strip);
443
+ pointer += 5;
444
+ else # string, date, time, timestamp
445
+ result[name].append(data[pointer..(pointer + precision - 1)].strip);
446
+ pointer += precision;
447
+ end
448
+ end
449
+ end
450
+ return result, list_name, nb_row, sql_state, sql_message
451
+ end
452
+
453
+ def modify_table(query)
454
+ header = retrieve_data("updt" + query + @@end_pack)
455
+ sql_state = header[1..5]
456
+ sql_message = header[6..]
457
+
458
+ # retrieve stats
459
+
460
+ row_count = 0
461
+ if query.upcase.start_with?("INSERT") || query.upcase.start_with?("UPDATE") || query.upcase.start_with?("DELETE")
462
+ row_count = sql_state.eql?("00000") ? sql_message[..1].to_i : 0
463
+ end
464
+
465
+ return row_count, sql_state, sql_message
466
+ end
467
+
468
+ def retrieve_data(command)
469
+
470
+ @tcp_client.send(command, 0)
471
+
472
+ data = ""
473
+ if command.start_with?("geth") || command.start_with?("updt")
474
+ data += "["
475
+ end
476
+
477
+ while data.length < @@end_pack.length || data[(data.length - @@end_pack.length)..(data.length-1)] != @@end_pack
478
+ data += @tcp_client.read(1)
479
+ end
480
+ return data[0..(data.length - (@@end_pack.length + 1))]
481
+ end
478
482
  end