devart-postgresql-connector 1.2.0__cp313-cp313-win_amd64.whl

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.
@@ -0,0 +1,25 @@
1
+ """
2
+ Python Connector for PostgreSQL is a connectivity solution for accessing
3
+ PostgreSQL databases from Python applications. It fully implements the Python
4
+ DB API 2.0 specification. The connector is distributed as a wheel package
5
+ for Windows, macOS, and Linux.
6
+
7
+ Direct connection
8
+
9
+ The connector enables you to establish a direct connection to PostgreSQL from
10
+ a Python application via TCP/IP, eliminating the need for the database client
11
+ library. A direct connection increases the speed of data transmission between
12
+ the application and PostgreSQL database server. It also streamlines
13
+ the deployment process since you don't have to distribute any client
14
+ libraries with the application.
15
+
16
+ Secure communication
17
+
18
+ The connector supports encrypted communications using SSL/TLS, SSH tunneling,
19
+ and HTTP/HTTPS tunneling.
20
+
21
+ Version: 1.2.0
22
+
23
+ Homepage: https://www.devart.com/python/postgresql/
24
+ """
25
+ from .postgresql import *
@@ -0,0 +1,743 @@
1
+ <?php
2
+
3
+ /* ##########################
4
+
5
+ Devart HttpTunnel v1.69.
6
+
7
+ HTTP tunnel script.
8
+
9
+ This script allows you to manage server even if the corresponding port is blocked or remote access to server is not allowed.
10
+
11
+ ##########################
12
+ */
13
+ if ( !function_exists('sys_get_temp_dir')) {
14
+ function sys_get_temp_dir() {
15
+ if (!empty($_ENV['TMP'])) { return realpath($_ENV['TMP']); }
16
+ if (!empty($_ENV['TMPDIR'])) { return realpath( $_ENV['TMPDIR']); }
17
+ if (!empty($_ENV['TEMP'])) { return realpath( $_ENV['TEMP']); }
18
+ $tempfile=tempnam(__FILE__,'');
19
+ if (file_exists($tempfile)) {
20
+ unlink($tempfile);
21
+ return realpath(dirname($tempfile));
22
+ }
23
+ return false;
24
+ }
25
+ }
26
+
27
+ $tmp_dir = sys_get_temp_dir();
28
+ if(!$tmp_dir){
29
+ define('SYSTEM_TMP_DIR', '');
30
+ }
31
+ else{
32
+ $last_symbol = substr($tmp_dir, -1);
33
+ if($last_symbol == DIRECTORY_SEPARATOR){
34
+ define('SYSTEM_TMP_DIR', $tmp_dir);
35
+ }
36
+ else{
37
+ define('SYSTEM_TMP_DIR', $tmp_dir . DIRECTORY_SEPARATOR);
38
+ }
39
+ }
40
+
41
+ $SUB_DIRECTORY = SYSTEM_TMP_DIR . 'tunnel_files';
42
+ $LOG_FILE_NAME = 'httptunnel_server.log';
43
+ $CONN_FILE_NAME = '_connections.id.php';
44
+ $LOGFILE = $SUB_DIRECTORY . '/' . $LOG_FILE_NAME;
45
+ $CONN_FILE = $SUB_DIRECTORY . '/' . $CONN_FILE_NAME;
46
+
47
+ $LOG = 0; // Set to "0" to disable logging
48
+ $LOG_DEBUG = 0; // Set to "0" to disable additional debug logging
49
+ $LOGFILEHANDLE = 0;
50
+ $MAXLOGSIZE = "4000000";
51
+ $LIFETIME = 180; // script lifetime in seconds. If script was started and got no client within that time - it exits.
52
+ $READ_WRITE_ATTEMPTS = 100;
53
+ $CREATE_CLIENT_SOCKET_ATTEMPTS = 3;
54
+ $IPC_TMPDIR = "/tmp/";
55
+
56
+ global $SUB_DIRECTORY;
57
+
58
+ function checkFunctionExists($functionName) {
59
+ if (!function_exists($functionName)) {
60
+ echo "Required function <b>$functionName</b> does not exist.</br>";
61
+ return false;
62
+ }
63
+
64
+ return true;
65
+ }
66
+
67
+ // Creates connection temporary file if not exists and checks permission to write
68
+ function CreateAndCheckConnFile($fileName) {
69
+
70
+ global $SUB_DIRECTORY;
71
+
72
+ if (file_exists($fileName)){
73
+ $newFile = @fopen($fileName, 'a');
74
+ if($newFile)
75
+ fclose($newFile);
76
+ else
77
+ echo "<b>Error</b>: Failed to open ($fileName) file: Permission denied.";
78
+
79
+ }
80
+ else{
81
+ if(!is_dir($SUB_DIRECTORY)){
82
+ mkdir($SUB_DIRECTORY);
83
+ }
84
+ $newFile = @fopen($fileName, 'w');
85
+ if($newFile){
86
+ fwrite($newFile, "<?php echo 'Devart HTTP tunnel temporary file.'; exit; ?>\r\n"); // forbid viewing this file through browser
87
+ fclose($newFile);
88
+ }
89
+ else
90
+ echo "<b>Error</b>: Failed to create ($fileName) file: Permission denied.";
91
+ }
92
+
93
+ if(!$newFile)
94
+ exit;
95
+ }
96
+
97
+ if (!isset($_REQUEST["a"])) { // query from browser
98
+
99
+ echo "Devart HttpTunnel v1.69<br />";
100
+
101
+ $functionList = array(
102
+ // "set_time_limit",
103
+ "stream_socket_server",
104
+ "stream_socket_client",
105
+ "stream_socket_get_name",
106
+ "stream_set_blocking",
107
+ "stream_socket_accept",
108
+ "stream_select"
109
+ );
110
+
111
+ $exist = true;
112
+ foreach($functionList as $functionName) {
113
+ $result = checkFunctionExists($functionName);
114
+ $exist = $exist && $result;
115
+ }
116
+
117
+ if ($exist)
118
+ CreateAndCheckConnFile($CONN_FILE);
119
+
120
+ if ($exist) {
121
+ echo "Tunnel script is installed correctly. <br />You can establish connections through the HTTP tunnel.";
122
+ if ($LOG==1)
123
+ echo "<br /> <br /><b>Loging is enabled.</b><br />Log files are located in the tunnel_files folder, which, in its turn, is located in the temporary folder of the operating system: " .$LOGFILE;
124
+ }
125
+ else
126
+ echo "Required PHP functions listed above are not available. Tunneling script will not work without these functions. Please read PHP manuals about how to install listed functions.";
127
+
128
+ exit;
129
+ }
130
+
131
+ function myErrorHandler($errno, $errstr, $errfile, $errline) {
132
+ switch ($errno) {
133
+ case E_ERROR:
134
+ $errfile = preg_replace('|^.*[\\\\/]|','',$errfile);
135
+ echo $ERRSTR."Error in line $errline of file $errfile: [$errno] $errstr\n";
136
+ exit;
137
+ }
138
+ }
139
+
140
+ function shutdown () {
141
+ global $ipsock, $rmsock, $outcount, $incount, $td, $te, $sockname, $useunix;
142
+
143
+ if (connection_status() & 1) { // ABORTED
144
+ logline ($_SERVER["REMOTE_ADDR"].": Irregular tunnel disconnect -> disconnecting server");
145
+ logline ($_SERVER["REMOTE_ADDR"].": Sent ".$outcount." bytes, received ".$incount." bytes");
146
+ } elseif (connection_status() & 2) { // TIMEOUT
147
+ logline ($_SERVER["REMOTE_ADDR"].": PHP script timeout -> disconnecting server");
148
+ logline ($_SERVER["REMOTE_ADDR"].": Sent ".$outcount." bytes, received ".$incount." bytes");
149
+ }
150
+
151
+ if ($ipsock) fclose($ipsock);
152
+ if ($rmsock) fclose($rmsock);
153
+ }
154
+
155
+ function logline ($msg) {
156
+ log_line_to_file(0, $msg);
157
+ }
158
+
159
+ function logdebug($msg) {
160
+ log_line_to_file(1, $msg);
161
+ }
162
+
163
+ function logerr($msg) {
164
+ global $ERRSTR;
165
+ logline($msg);
166
+ echo $ERRSTR;
167
+ echo $msg;
168
+ }
169
+
170
+ function log_line_to_file ($debug, $msg) {
171
+ global $LOG, $LOG_DEBUG, $MAXLOGSIZE, $LOGFILE, $LOGFILEHANDLE;
172
+ if ($LOG && ((! $debug) || $LOG_DEBUG)) {
173
+ $LOGFILEHANDLE=fopen ($LOGFILE, "a");
174
+ if ($LOGFILEHANDLE) {
175
+ fwrite ($LOGFILEHANDLE, date("d.m.Y H:i:s")." - $msg\r\n");
176
+ $lstat=fstat($LOGFILEHANDLE);
177
+ if ($lstat["size"]>$MAXLOGSIZE) rotatelog();
178
+ fclose($LOGFILEHANDLE);
179
+ }
180
+ }
181
+ }
182
+
183
+ function rotatelog() {
184
+ global $LOG, $MAXLOGSIZE, $LOGFILE, $LOGFILEHANDLE;
185
+ if ($LOG) {
186
+ fwrite ($LOGFILEHANDLE, date("d.m.Y H:i:s")." - Logfile reached maximum size ($MAXLOGSIZE)- rotating.\r\n");
187
+ fclose ($LOGFILEHANDLE);
188
+ rename ($LOGFILE, substr_replace($LOGFILE,md5(microtime()),-3).".log");
189
+ $LOGFILEHANDLE=fopen ($LOGFILE, "a");
190
+ if (!$LOGFILEHANDLE)
191
+ $LOG=0;
192
+ else
193
+ fwrite ($LOGFILEHANDLE, date("d.m.Y H:i:s")." - Opening new Logfile.\r\n");
194
+ }
195
+ }
196
+
197
+ function create_client_socket() {
198
+ global $CREATE_CLIENT_SOCKET_ATTEMPTS, $_REQUEST, $IPC_TMPDIR;
199
+
200
+ if (!isset($_REQUEST["port"])) {
201
+ echo $ERRSTR."Port not set.";
202
+ return 0;
203
+ }
204
+
205
+ $port = $_REQUEST["port"];
206
+ $useunix = in_array("unix", stream_get_transports());
207
+
208
+ $retryCount = 0;
209
+ do {
210
+ if ($retryCount > 0) {
211
+ usleep(10000); // 10ms
212
+ logdebug("Attempt to create client socket #".($retryCount + 1)." ErrorCode:".$errcode." ErrorMessage:".$errmessage." Port:".$port);
213
+ }
214
+
215
+ if ($useunix) { // this is for the unix socket type
216
+ $sockname = preg_replace('/\\\\/','/', $IPC_TMPDIR."tun$port.sock");
217
+ $client = stream_socket_client("unix://".$sockname, $errcode, $errmessage);
218
+ }
219
+ else {
220
+ $client = stream_socket_client("tcp://127.0.0.1:".$port, $errcode, $errmessage);
221
+ }
222
+ $retryCount = $retryCount + 1;
223
+ } while(!$client && $retryCount < $CREATE_CLIENT_SOCKET_ATTEMPTS);
224
+
225
+ if ($client) {
226
+ stream_set_blocking($client, 1);
227
+ }
228
+ return $client;
229
+ }
230
+
231
+ function send_server_script_message($command) {
232
+ global $_REQUEST;
233
+
234
+ $client = create_client_socket();
235
+ if (!$client) {
236
+ logerr("Failed to create client socket");
237
+ return FALSE;
238
+ }
239
+ if (fwrite($client, $command, 1) === FALSE) {
240
+ logerr("Failed to send message to server script.");
241
+ fclose($client);
242
+ return FALSE;
243
+ }
244
+ fclose($client);
245
+ return TRUE;
246
+ }
247
+
248
+ function increase_script_lifetime() {
249
+ global $LIFETIME;
250
+ if (function_exists("set_time_limit")) {
251
+ set_time_limit($LIFETIME);
252
+ logdebug("Script liftetime incremented with $LIFETIME");
253
+ }
254
+ }
255
+
256
+ function write_to_socket($socket, $buffer, $count) {
257
+ global $READ_WRITE_ATTEMPTS;
258
+
259
+ $totalCount = 0;
260
+ $retryCount = 0;
261
+
262
+ do {
263
+ if ($retryCount > 0)
264
+ usleep(10000); // 10ms
265
+
266
+ if (!$socket)
267
+ break;
268
+
269
+ $written = fwrite($socket, $buffer, $count);
270
+ $buffer = substr($buffer, $written);
271
+ $totalCount += $written;
272
+
273
+ if ($retryCount > 0)
274
+ logdebug("Attempt to write #".($retryCount + 1)." Write: ".$written);
275
+
276
+ if ($written <= 0)
277
+ $retryCount = $retryCount + 1;
278
+
279
+ } while($totalCount < $count && $retryCount < $READ_WRITE_ATTEMPTS);
280
+
281
+ if ($totalCount != $count)
282
+ logline("ERROR: Failed to write to socket $count bytes, $totalCount actually written.");
283
+
284
+ return $totalCount;
285
+ }
286
+
287
+ // reads specified byte count from socket
288
+ function read_from_socket($socket, &$buffer, $count) {
289
+ global $READ_WRITE_ATTEMPTS;
290
+
291
+ $totalCount = 0;
292
+ $retryCount = 0;
293
+
294
+ $buffer = "";
295
+ $readBuffer;
296
+
297
+ do {
298
+ if ($retryCount > 0)
299
+ usleep(10000); // 10ms
300
+
301
+ if (!$socket)
302
+ break;
303
+
304
+ $readBuffer = fread($socket, $count);
305
+ $read = strlen($readBuffer);
306
+ $buffer = $buffer.$readBuffer;
307
+
308
+ if ($retryCount > 0)
309
+ logdebug("Attempt to read #".($retryCount + 1)." Read: ".$read);
310
+
311
+ $totalCount += $read;
312
+ if ($read <= 0)
313
+ $retryCount = $retryCount + 1;
314
+
315
+ } while($totalCount < $count && $retryCount < $READ_WRITE_ATTEMPTS);
316
+
317
+ if ($totalCount != $count)
318
+ logerr("Failed to read from socket $count bytes, $totalCount actually read.");
319
+
320
+ return $totalCount;
321
+ }
322
+
323
+ // packet: size of data count | data count | data
324
+ // lengths: 1 byte | up to 255 bytes, typically 1 - 5| up to $MaxCount
325
+ function write_data_packet($socket, &$buffer, $count) {
326
+
327
+ $countLength = strlen($count);
328
+ // write length of data count digit
329
+ write_to_socket($socket, $countLength, 1);
330
+ // write data count
331
+ write_to_socket($socket, $count, $countLength);
332
+ // write data
333
+ $writeCount = write_to_socket($socket, $buffer, $count);
334
+ if ($writeCount == $count)
335
+ return $writeCount;
336
+ else
337
+ return 0;
338
+ }
339
+
340
+ function read_data_packet($socket, &$buffer) {
341
+
342
+ // obtain data length digit length
343
+ read_from_socket($socket, $countSize, 1);
344
+ // read data length
345
+ read_from_socket($socket, $readCount, $countSize);
346
+ $expectedReadCount = $readCount;
347
+ // read data
348
+ $readCount = read_from_socket($socket, $buffer, $readCount);
349
+ if ($readCount == $expectedReadCount)
350
+ return $readCount;
351
+ else
352
+ return FALSE;
353
+ }
354
+
355
+ // Start of the tunnel script
356
+ $isServer = FALSE;
357
+
358
+ if (version_compare("5.0.0", phpversion())==1) die ("Only PHP 5 or above supported");
359
+ error_reporting(0);
360
+ set_error_handler("myErrorHandler");
361
+ register_shutdown_function ("shutdown");
362
+ // no-cache
363
+ Header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
364
+ Header("Cache-Control: no-cache, must-revalidate");
365
+ Header("Pragma: no-cache"); // HTTP/1.1
366
+ Header("Last-Modified: ".gmdate("D, d M Y H:i:s")."GMT");
367
+ Header("Content-Type: application/octet-stream");
368
+
369
+ ob_implicit_flush();
370
+
371
+ // Maximum bytes to read at once
372
+ $MaxReadCount = 16*1024;
373
+
374
+ // operation success identification
375
+ $OKSTR = "OK:";
376
+ $ERRSTR = "ER:";
377
+
378
+ $CONN_FILE_MAXSIZE = 100;
379
+
380
+ // Primary tunnel connection
381
+ // need the following REQUEST vars:
382
+ // a: "c"
383
+ // s: remote server name
384
+ // p: remote server port
385
+
386
+ // every operation output at least first three chars identifying the success of operation: "OK:" if succeeded, "ER:" if not.
387
+ //
388
+
389
+ if ($_REQUEST["a"]=="c") { // run server script
390
+ $isServer=TRUE;
391
+ // clear log
392
+ if ($LOG_DEBUG) {
393
+ // truncate log file
394
+ $logfile = fopen($LOGFILE, 'w');
395
+ fclose($logfile);
396
+ }
397
+
398
+ $useunix = in_array("unix", stream_get_transports());
399
+ $dad = $_REQUEST["s"];
400
+ $dpo = $_REQUEST["p"];
401
+
402
+ // open the interprocess socket
403
+ $errno = 0;
404
+ $errstr = "";
405
+ $ipsock = stream_socket_server("tcp://127.0.0.1:0", $errno, $errstr);
406
+
407
+ if (!$ipsock) {
408
+ logerr("stream_socket_server() failed: reason:".$errno." ".$errstr);
409
+ exit;
410
+ }
411
+
412
+ $port = stream_socket_get_name($ipsock, false);
413
+ $port = preg_replace('/^.*?:/','', $port);
414
+
415
+ if ($useunix) { // this is for the unix socket type
416
+ if ($ipsock) fclose($ipsock);
417
+ $ipsock = 0;
418
+ $sockname = preg_replace('/\\\\/','/', $IPC_TMPDIR."tun$port.sock");
419
+ unlink($sockname);
420
+ if (file_exists($sockname)) {
421
+ logerr("Temporary UNIX socket exists and cannot be deleted ($sockname)");
422
+ exit;
423
+ }
424
+ $ipsock = stream_socket_server("unix://".$sockname, $errno, $errstr);
425
+ if (!$ipsock) {
426
+ logerr("stream_socket_server() failed: reason:".$errno." ".$errstr);
427
+ exit;
428
+ }
429
+ }
430
+
431
+ stream_set_blocking($ipsock, 1);
432
+
433
+ // open the remote socket
434
+ logline("Connecting to remote $dad: $dpo");
435
+ $rmsock = stream_socket_client("tcp://".$dad.":".$dpo, $errno, $errstr);
436
+
437
+ if (!$rmsock) {
438
+ logerr("Failed to create remote socket at $dad: $dpo. ".$errno." ".$errstr);
439
+ exit;
440
+ }
441
+ else {
442
+ if (isset($_REQUEST["nonblock"]))
443
+ $block = 0;
444
+ else
445
+ $block = 1;
446
+ stream_set_blocking($rmsock, $block);
447
+ logline("Connected to remote $dad: $dpo");
448
+ }
449
+
450
+ // write connection identificator to file. Echo'ing is not appropriate in case of antiviral software, it would be blocked until script finishes
451
+ $newConnFile = FALSE;
452
+ $connFileMode = "a";
453
+
454
+ if (file_exists($CONN_FILE)) {
455
+ $connFile = fopen($CONN_FILE, "r");
456
+ $lstat=fstat($connFile);
457
+ fclose($connFile);
458
+ if ($lstat["size"]>$CONN_FILE_MAXSIZE) {
459
+ $connFileMode = "w";
460
+ $newConnFile = TRUE;
461
+ }
462
+ }
463
+ else {
464
+ $newConnFile = TRUE;
465
+ }
466
+
467
+ $connFile = fopen($CONN_FILE, $connFileMode);
468
+ if ($connFile) {
469
+ if ($newConnFile) {
470
+ fwrite($connFile, "<?php echo 'Devart HTTP tunnel temporary file.'; exit; ?>\r\n"); // forbid viewing this file through browser
471
+ }
472
+ $connectionId = str_replace("_", " ", $_REQUEST["id"]);
473
+ fwrite ($connFile, $connectionId." ".$port."\r\n");
474
+ fclose($connFile);
475
+ }
476
+ else {
477
+ logerr("Failed to create connection temporary file.");
478
+ exit;
479
+ }
480
+
481
+ if (function_exists("set_time_limit")) {
482
+ set_time_limit($LIFETIME);
483
+ }
484
+
485
+ $exit = false;
486
+ $buffer = array();
487
+ $countBuffer = array();
488
+
489
+ while (!$exit) {
490
+ logdebug("Waiting for client...");
491
+ $client = stream_socket_accept($ipsock);
492
+ logline("Client accepted");
493
+ if ($client === FALSE) {
494
+ logline("ERROR: Bad client.");
495
+ continue;
496
+ }
497
+ // read command
498
+ $count = read_from_socket($client, $buffer, 1);
499
+ if ($count == 0) {
500
+ logline("Error reading client command.");
501
+ $exit = true;
502
+ }
503
+
504
+ logdebug("Read from client ($count): ".$buffer[0]);
505
+
506
+ $command = $buffer[0];
507
+
508
+ increase_script_lifetime();
509
+
510
+ if ($command == "x") { // close
511
+ logline("Shutting down on client request.");
512
+ $exit = true; // shutdown
513
+ }
514
+ else if ($command == "r") { // read
515
+ if (!$rmsock) {
516
+ logline("ERROR: rmsock is off");
517
+ $exit = true;
518
+ break;
519
+ }
520
+
521
+ $readCount = 0;
522
+ $buffer = fread($rmsock, $MaxReadCount);
523
+ if ($buffer === FALSE) {
524
+ logline("ERROR: Remote server disconnected.");
525
+ $exit = true;
526
+ break;
527
+ }
528
+ else {
529
+ $readCount = strlen($buffer);
530
+ logline("Read from remote:($readCount)");
531
+ }
532
+
533
+ if ($readCount >= 0) {
534
+ if ($readCount == 0)
535
+ logline("Nothing to read from remote.");
536
+
537
+ $writeCount = write_data_packet($client, $buffer, $readCount);
538
+ logdebug("Write to client($writeCount): $buffer");
539
+ if ($readCount > 0 && $writeCount == 0) {
540
+ logerr("Failed to write to client.");
541
+ $exit = true;
542
+ }
543
+ }
544
+ }
545
+ else if ($command == "s") { // select
546
+ if (!$rmsock) {
547
+ logline("ERROR: rmsock is off");
548
+ $exit = true;
549
+ break;
550
+ }
551
+
552
+ $readSocks = array($ipsock, $rmsock);
553
+ $writeSocks = NULL;
554
+ $exceptSocks = NULL;
555
+ if (!stream_select($readSocks, $writeSocks, $exceptSocks, NULL))
556
+ $res = $ERRSTR;
557
+ else
558
+ if (in_array($rmsock, $readSocks))
559
+ $res = $OKSTR;
560
+ else
561
+ $res = $ERRSTR;
562
+ $writeCount = write_to_socket($client, $res, strlen($res));
563
+ logdebug("Write to client($writeCount): $res");
564
+ }
565
+ else if ($command == "w") { // write
566
+ if (!$rmsock) {
567
+ logline("ERROR: rmsock is off");
568
+ $exit = true;
569
+ break;
570
+ }
571
+ $readCount = read_data_packet($client, $buffer);
572
+ logline("Read from client: $readCount");
573
+ if ($readCount > 0) {
574
+ $writeCount = write_to_socket($rmsock, $buffer, $readCount);
575
+ logdebug("Write to remote($writeCount): $buffer");
576
+ }
577
+ }
578
+ else if ($command == "l") { // increment lease time
579
+ logline("Lease time increased.");
580
+ }
581
+ else if ($command == "t") { // test connection command
582
+ $writeCount = write_to_socket($client, $OKSTR, strlen($OKSTR));
583
+ if ($writeCount == 0)
584
+ $exit = true;
585
+ }
586
+ else {
587
+ logline("ERROR: Unknown command: $command. Exiting.");
588
+ $exit = true;
589
+ }
590
+ }
591
+
592
+ logline("Server script closed.");
593
+ exit;
594
+ }
595
+
596
+ if ($_REQUEST["a"]=="r") { // read
597
+
598
+ $client = create_client_socket();
599
+ if (!$client) {
600
+ logerr("Failed to connect to server script.");
601
+ exit;
602
+ }
603
+
604
+ logdebug("Client: Reading from server script");
605
+
606
+ if (write_to_socket($client, "r", 1) == 0) { // write "Read" command
607
+ logerr("Write to server script failed.");
608
+ fclose($client);
609
+ exit;
610
+ }
611
+
612
+ $buffer;
613
+ $readCount = read_data_packet($client, $buffer);
614
+ if ($readCount === FALSE) {
615
+ logerr("Failed to read response from server script.");
616
+ fclose($client);
617
+ exit;
618
+ }
619
+
620
+ $totalCount = strlen($OKSTR) + $readCount;
621
+
622
+ $outputStr = $OKSTR.$buffer;
623
+
624
+ header("Content-Length: ".$totalCount);
625
+ header("Content-Type: application/octet-stream");
626
+
627
+ logline("Client: Read from server $readCount");
628
+ echo $outputStr;
629
+
630
+ fclose($client);
631
+ exit;
632
+ }
633
+
634
+ if ($_REQUEST["a"]=="s") { // select
635
+
636
+ $client = create_client_socket();
637
+ if (!$client) {
638
+ logerr("Failed to connect to server script.");
639
+ exit;
640
+ }
641
+
642
+ logdebug("Client: Selecting from server script");
643
+
644
+ if (write_to_socket($client, "s", 1) == 0) { // write "Select" command
645
+ logerr("Write to server script failed.");
646
+ fclose($client);
647
+ exit;
648
+ }
649
+
650
+ $buffer;
651
+ $count = read_from_socket($client, $buffer, 3);
652
+ if ($count < 3) {
653
+ logerr("Failed to read response from server script.");
654
+ fclose($client);
655
+ exit;
656
+ }
657
+
658
+ fclose($client);
659
+ echo $buffer;
660
+ exit;
661
+ }
662
+
663
+ if ($_REQUEST["a"]=="w") { // write
664
+
665
+ $client = create_client_socket();
666
+ if (!$client) {
667
+ logerr("Failed to connect to server script.");
668
+ exit;
669
+ }
670
+
671
+ $postBody= isset($_POST['base64body'])?base64_decode($_POST['base64body']):file_get_contents("php://input"); // Retrieve RAW POST data
672
+ $writeData = $postBody;
673
+ $expectedWriteCount = strlen($writeData);
674
+ $writeCount = write_to_socket($client, "w", 1); // indicate that this is the "Write" command
675
+ if ($writeCount > 0)
676
+ $writeCount = write_data_packet($client, $writeData, $expectedWriteCount);
677
+
678
+ if ($writeCount == 0) {
679
+ logerr("Write to server script failed.");
680
+ fclose($client);
681
+ exit;
682
+ }
683
+
684
+ logdebug("Client: Written $writeCount");
685
+
686
+ fclose($client);
687
+ echo $OKSTR;
688
+ exit;
689
+ }
690
+
691
+ if ($_REQUEST["a"]=="x") { // close
692
+
693
+ echo $OKSTR."Shutted down.";
694
+ send_server_script_message("x");
695
+ exit;
696
+ }
697
+
698
+ if ($_REQUEST["a"] == "l") { // increment server script lease time
699
+
700
+ if (send_server_script_message("l"))
701
+ echo $OKSTR."Incremented server script lease time.";
702
+ exit;
703
+ }
704
+
705
+ if ($_REQUEST["a"] == "t") { // test newly created connection
706
+
707
+ $connectionId = str_replace("_", " ", $_REQUEST["id"]);
708
+ logline($connectionId);
709
+ $connections = file_get_contents($CONN_FILE);
710
+
711
+ if ($connections === FALSE) {
712
+ logerr("Failed to open $CONN_FILE.");
713
+ exit;
714
+ }
715
+
716
+ $lines = explode("\r\n", $connections);
717
+
718
+ // skip first line
719
+ for($i = 1; $i < count($lines); ++$i) {
720
+ $line = $lines[$i];
721
+ $pos = strpos($line, $connectionId);
722
+ if ($pos === FALSE)
723
+ continue;
724
+
725
+ if ($pos === 0) { // starts with
726
+ $parts = explode(" ", $line);
727
+ if (count($parts) != 3) {
728
+ echo "Invalid connection record";
729
+ exit;
730
+ }
731
+
732
+ echo $OKSTR.$parts[2]."\n"."$LIFETIME\n";
733
+ exit;
734
+ }
735
+ }
736
+
737
+ logerr("Connection entry not found.");
738
+ exit;
739
+ }
740
+
741
+ logerr("Invalid tunneling script parameter: ".$_REQUEST["a"]);
742
+
743
+ ?>
@@ -0,0 +1,403 @@
1
+ from typing import Tuple, List, Optional, Any, Dict
2
+ import datetime
3
+ import array
4
+
5
+ class description(object):
6
+ """
7
+ The description class describes a column in a rowset returned by the cursor.
8
+ """
9
+ name: str
10
+ """
11
+ The name of the column in the rowset.
12
+ """
13
+ type_code: int
14
+ """
15
+ The database type code that corresponds to the type of the column.
16
+ """
17
+ display_size: int
18
+ """
19
+ The actual length of the column in characters for a character column, `None` otherwise.
20
+ """
21
+ internal_size: int
22
+ """
23
+ The size in bytes used by the connector to store the column data.
24
+ """
25
+ precision: int
26
+ """
27
+ The total number of significant digits for a numeric column, `None` otherwise.
28
+ """
29
+ scale: int
30
+ """
31
+ The number of digits in the fractional part for a numeric column, `None` otherwise.
32
+ """
33
+ null_ok: bool
34
+ """
35
+ `Py_True` if the corresponding database column accepts `NULL` values, `Py_False` otherwise.
36
+ """
37
+ ...
38
+
39
+ class cursor(object):
40
+ """
41
+ The `cursor` class represents a database cursor, which is used to manage
42
+ the context of fetch operations. This class provides methods for executing SQL
43
+ statements and operating rowsets. Cursors are created using the `cursor()`
44
+ connection method.
45
+ """
46
+ connection: str
47
+ """
48
+ A read-only attribute that specifies the `connection` object
49
+ to which the cursor belongs.
50
+ """
51
+ arraysize: int
52
+ """
53
+ A read/write attribute that specifies the number of rows to fetch at a time
54
+ with the `fetchmany()` method.
55
+ """
56
+ description: Tuple[description]
57
+ """
58
+ A read-only attribute that describes the columns in a rowset returned
59
+ by the cursor.
60
+ """
61
+ rowcount: int
62
+ """
63
+ A read-only attribute that specifies the number of rows that the last
64
+ `execute()` call produced by a `SELECT` statement or affected by `UPDATE` or
65
+ `INSERT` statements.
66
+ """
67
+ rownumber: int
68
+ """
69
+ A read-only attribute that specifies the current 0-based index of the cursor
70
+ in the result set.
71
+ """
72
+ lastrowid: None
73
+ """
74
+ This read-only attribute is provided for compatibility with the DB API 2.0
75
+ specification. It currently returns `None`.
76
+ """
77
+ def setinputsizes(self, sizes: Optional[List[Any] | Tuple[Any]]) -> None:
78
+ """
79
+ Predefines the types of parameters for the further call to the `execute*()`
80
+ method.
81
+ """
82
+ ...
83
+ def execute(self, operation: str, parameters: Optional[List[Any] | Tuple[Any] | Dict[str, Any]]) -> cursor:
84
+ """
85
+ Prepares and executes a database operation.
86
+ """
87
+ ...
88
+ def executemany(self, operation: str, parameters: Optional[List[Any] | Tuple[Any] | Dict[str, Any]]) -> cursor:
89
+ """
90
+ Prepares and executes a batch database operation.
91
+ """
92
+ def fetchone(self) -> Tuple[Any]:
93
+ """
94
+ Fetches the next row of a query result set.
95
+ """
96
+ ...
97
+ def fetchmany(self, size: Optional[int]) -> List[Tuple[Any]]:
98
+ """
99
+ Fetches the next set of rows of a query result.
100
+ """
101
+ ...
102
+ def fetchall(self) -> List[Tuple[Any]]:
103
+ """
104
+ Fetches all remaning rows of a query result.
105
+ """
106
+ ...
107
+ def next(self) -> Tuple[Any]:
108
+ """
109
+ Returns the next row from the currently executed SQL statement.
110
+ """
111
+ ...
112
+ def scroll(value: int, mode: Optional[str]) -> bool:
113
+ """
114
+ Scrolls the cursor in the result set to a new position.
115
+ """
116
+ ...
117
+ def addtypecast(self, column: int | dbtype | str | description | Dict[str, type], python_type: Optional[type]) -> None:
118
+ """
119
+ Defines a data type cast rule to use when fetching data from the cursor.
120
+ """
121
+ ...
122
+ def cleartypecast(self) -> None:
123
+ """
124
+ Removes all data type cast rules defined for the cursor.
125
+ """
126
+ ...
127
+ def close(self) -> None:
128
+ """
129
+ Closes the cursor.
130
+ """
131
+ ...
132
+ def setoutputsize(size: int, column: Optional[int]):
133
+ """
134
+ This method is provided for compatibility with the DB API 2.0 specification.
135
+ It currently does nothing but is safe to call.
136
+ """
137
+ ...
138
+
139
+ class connection(object):
140
+ """
141
+ The `connection` class encapsulates a database session. It provides methods
142
+ for creating cursors, type casting, and transaction handling. Connections
143
+ are created using the `connect()` module method.
144
+ """
145
+ connectstring: str
146
+ """
147
+ A read-only attribute that returns a string literal of the form
148
+ `"parameter=value;parameter=value"` that contains the parameters
149
+ for the current connection.
150
+ """
151
+ def cursor(self) -> cursor:
152
+ """
153
+ Creates a new cursor object, which is used to manage the context of fetch
154
+ operations.
155
+ """
156
+ ...
157
+ def close(self) -> None:
158
+ """
159
+ Closes the connection.
160
+ """
161
+ ...
162
+ def commit(self) -> None:
163
+ """
164
+ Commits any pending transaction to the database.
165
+ """
166
+ ...
167
+ def rollback(self) -> None:
168
+ """
169
+ Causes the database to roll back any pending transaction.
170
+ """
171
+ ...
172
+ def addtypecast(self, column: int | dbtype | str | description | Dict[str, type], python_type: Optional[type]) -> None:
173
+ """
174
+ Defines a data type cast rule to use when fetching data from the cursor.
175
+ """
176
+ ...
177
+ def cleartypecast(self) -> None:
178
+ """
179
+ Removes all data type cast rules defined for the connection.
180
+ """
181
+ ...
182
+
183
+ class connection_pool(object):
184
+ """
185
+ Description of the `connection_pool` class is not available yet.
186
+ """
187
+ enabled: bool = False
188
+ """
189
+ Description of the `enabled` attribute is not available yet.
190
+ """
191
+ max_size: int = 1000
192
+ """
193
+ Description of the `max_size` attribute is not available yet.
194
+ """
195
+ min_size: int = 1000
196
+ """
197
+ Description of the `min_size` attribute is not available yet.
198
+ """
199
+ lifetime: int = 0
200
+ """
201
+ Description of the `lifetime` attribute is not available yet.
202
+ """
203
+ validate: bool = False
204
+ """
205
+ Description of the `validate` attribute is not available yet.
206
+ """
207
+
208
+ class Warning(Exception):
209
+ """
210
+ This exception is raised for important warnings like data truncations while
211
+ inserting, etc. The `Warning` exception is a subclass of the Python
212
+ `Exception` class.
213
+ """
214
+ ...
215
+
216
+ class Error(Exception):
217
+ """
218
+ This exception is the base class of all error exceptions. You can use
219
+ it to catch all errors with a single `except` statement. The `Error` exception
220
+ is a subclass of the Python `Exception` class.
221
+ """
222
+ ...
223
+
224
+ class InterfaceError(Error):
225
+ """
226
+ This exception is raised for errors that are related to the database interface
227
+ rather than the database itself. The `InterfaceError` exception is a subclass
228
+ of `Error`.
229
+ """
230
+ ...
231
+
232
+ class DatabaseError(Error):
233
+ """
234
+ This exception is raised for errors that are related to the database.
235
+ The `DatabaseError` exception is a subclass of `Error`.
236
+ """
237
+ ...
238
+
239
+ class DataError(DatabaseError):
240
+ """
241
+ This exception is raised for errors caused by issues with the processed data
242
+ like division by zero, numeric value out of range, etc. The `DataError`
243
+ exception is a subclass of `DatabaseError`.
244
+ """
245
+ ...
246
+
247
+ class OperationalError(DatabaseError):
248
+ """
249
+ This exception is raised for errors that are related to the database operation
250
+ and not necessarily under the control of the developer, for example,
251
+ an unexpected disconnect occurs, the data source name isn't found,
252
+ a transaction couldn't be processed, a memory allocation error occurred
253
+ during processing, etc. The OperationalError exception is a subclass
254
+ of `DatabaseError`.
255
+ """
256
+ ...
257
+
258
+ class IntegrityError(DatabaseError):
259
+ """
260
+ This exception raised when the relational integrity of the database
261
+ is affected, for example, a foreign key check fails. The `IntegrityError`
262
+ exception is a subclass of `DatabaseError`.
263
+ """
264
+ ...
265
+
266
+ class InternalError(DatabaseError):
267
+ """
268
+ This exception is raised when the database encounters an internal error,
269
+ for example, the cursor isn't valid anymore, the transaction is out of sync,
270
+ etc. The `InternalError` exception is a subclass of `DatabaseError`.
271
+ """
272
+ ...
273
+
274
+ class ProgrammingError(DatabaseError):
275
+ """
276
+ This exception is raised for programming errors, for example, table not found
277
+ or already exists, syntax error in the SQL statement, wrong number
278
+ of parameters specified, etc. The `ProgrammingError` exception is a subclass
279
+ of `DatabaseError`.
280
+ """
281
+ ...
282
+
283
+ class NotSupportedError(DatabaseError):
284
+ """
285
+ This exception is raised when a method or database API isn't supported
286
+ by the database, for example, requesting a `rollback()` on a connection
287
+ that doesn't support transactions or has transactions turned off.
288
+ The `NotSupportedError` exception is a subclass of `DatabaseError`.
289
+ """
290
+ ...
291
+
292
+ class binary(object):
293
+ """
294
+ This type object describes an object that holds binary data. By default, this
295
+ type object is used to fetch BLOB-based columns from the cursor. You can also
296
+ create a `binary` object using the `Binary()` constructor.
297
+ """
298
+ value: bytes
299
+ """
300
+ A value of type `bytes` that represents binary data. This is a read/write attribute
301
+ that accepts values of type `str`, `bytes`, `bytearray`, `array.array`, and `binary`.
302
+ """
303
+
304
+ class dbtype(object):
305
+ name: str
306
+ values: Dict[int, str]
307
+
308
+ apilevel: str = "2.0"
309
+ """
310
+ Indicates the DB API level supported by the module. Returns a string value "2.0".
311
+ """
312
+
313
+ threadsafety: int = 2
314
+ """
315
+ Indicates the thread safety level of the module. Returns an integer value `2` that means
316
+ that threads may share the module and connections.
317
+ """
318
+
319
+ paramstyle: str = "named"
320
+ """
321
+ Indicates the type of parameter marker formatting expected by the module.
322
+ Returns a string value "named" that means that the module supports named style parameters,
323
+ for example, `...WHERE name=:name`.
324
+ """
325
+
326
+ def connect(connection_string: str, **kwargs: Optional[Any]) -> connection:
327
+ """
328
+ Creates a new connection to the database.
329
+ """
330
+ ...
331
+
332
+ def Date(year: int, month: int, day: int) -> datetime.date:
333
+ """
334
+ Creates an object that holds a date value.
335
+ """
336
+ ...
337
+
338
+ def Time(hour: int, minute: int, second: int | float, timezone: Optional[datetime.tzinfo]) -> datetime.time:
339
+ """
340
+ Creates an object that holds a time value.
341
+ """
342
+ ...
343
+
344
+ def Timestamp(year: int, month: int, day: int, hour: Optional[int], minute:Optional[int], second: Optional[int | float], timezone: Optional[datetime.tzinfo]) -> datetime.datetime:
345
+ """
346
+ Creates an object that holds a timestamp value.
347
+ """
348
+ ...
349
+
350
+ def DateFromTicks(ticks: float) -> datetime.date:
351
+ """
352
+ Creates an object that holds a date value from the given ticks value
353
+ (the number of seconds since the Unix epoch). For more information, see
354
+ the `time` module in the standard Python documentation.
355
+ """
356
+ ...
357
+
358
+ def TimeFromTicks(ticks: float) -> datetime.time:
359
+ """
360
+ Creates an object that holds a time value from the given ticks value (number
361
+ of seconds since the Unix epoch). For more information, see the `time` module
362
+ in the standard Python documentation.
363
+ """
364
+ ...
365
+
366
+ def TimestampFromTicks(ticks: float) -> datetime.datetime:
367
+ """
368
+ Creates an object that holds a timestamp value from the given ticks value
369
+ (number of seconds since the Unix epoch). For more information, see the `time`
370
+ module in the standard Python documentation.
371
+ """
372
+ ...
373
+
374
+ def Binary(value: str | bytes | bytearray | array.array) -> binary:
375
+ """
376
+ Creates an object that holds binary data.
377
+ """
378
+ ...
379
+
380
+ STRING: dbtype
381
+ """
382
+ This type object describes string-based columns in a database.
383
+ """
384
+
385
+ BINARY: dbtype
386
+ """
387
+ This type object describes binary columns in a database.
388
+ """
389
+
390
+ NUMBER: dbtype
391
+ """
392
+ This type object describes numeric columns in a database.
393
+ """
394
+
395
+ DATETIME: dbtype
396
+ """
397
+ This type object describes date/time columns in a database.
398
+ """
399
+
400
+ ROWID: dbtype
401
+ """
402
+ This type object describes the `row id` columns in a database.
403
+ """
@@ -0,0 +1,17 @@
1
+ from sqlalchemy.dialects import registry
2
+ from sqlalchemy.dialects.postgresql.base import PGDialect
3
+
4
+ registry.register('devart.postgresql', 'devart.postgresql.sqlalchemy', 'DevartPostgreSqlDialect')
5
+
6
+ class DevartPostgreSqlDialect(PGDialect):
7
+ driver = "devart"
8
+ name = "postgresql"
9
+
10
+ supports_statement_cache = False
11
+ supports_server_side_cursors = False
12
+ default_paramstyle = "named"
13
+
14
+ @classmethod
15
+ def import_dbapi(cls):
16
+ import devart.postgresql
17
+ return devart.postgresql
@@ -0,0 +1,85 @@
1
+ Python Connector License Agreement
2
+ Copyright 2022-2024, Devart. All Rights Reserved
3
+ --------------------------------------------------
4
+
5
+ PLEASE READ THIS LICENSE AGREEMENT CAREFULLY. BY INSTALLING OR USING THIS SOFTWARE, YOU INDICATE ACCEPTANCE OF AND AGREE TO BECOME BOUND BY THE TERMS AND CONDITIONS OF THIS LICENSE. IF YOU DO NOT AGREE TO THE TERMS OF THIS LICENSE, DO NOT INSTALL OR USE THIS SOFTWARE AND PROMPTLY RETURN IT TO DEVART.
6
+
7
+ INTRODUCTION
8
+
9
+ This Devart end-user license agreement ("Agreement") is a legal agreement between you (either an individual person or a single legal entity) and Devart, for the use of the Python Connector software application, demos, intermediate files, printed materials, and online or electronic documentation contained in this installation file. For the purpose of this Agreement, the software program(s) and supporting documentation will be referred to as the "Software".
10
+
11
+ LICENSE
12
+
13
+ 1. GRANT OF LICENSE
14
+
15
+ The enclosed Software is licensed, not sold. You have the following rights and privileges, subject to all limitations, restrictions, and policies specified in this Agreement.
16
+
17
+ 1.1. If you are a legally licensed user, depending on the License Type specified in the registration letter you have received from Devart upon purchase of the Software:
18
+ - the "Single License" allows you to install and use the Software on one or more computers, provided it is used by 1 (one) user for the sole purposes of developing, testing, and deploying scripts or applications in a single company at one physical address in accordance with this Agreement;
19
+ - the "Team License" allows you to install and use the Software on one or more computers, provided it is used by up to 4 (four) users for the sole purposes of developing, testing, and deploying scripts or applications in a single company at one physical address in accordance with this Agreement;
20
+ - the "Site License" allows you to install and use the Software on one or more computers, provided it is used by unlimited number of users for the sole purposes of developing, testing, and deploying scripts or applications in a single company at one physical address in accordance with this Agreement;
21
+ - the "OEM License" allows you to install and use the Software as part of a licensee's script or application that can be deployed to web servers, application servers, batch servers, desktops, and other end-user devices. This definition includes the ability to install and use the script or application containing the Software an unlimited number of times, without any additional fees in favor of the licensor.
22
+
23
+ 1.2. If you are a legally licensed user, depending on the License Type specified in the registration letter you have received from Devart upon purchase of the Software:
24
+ - the "Subscription-based License" allows you to install and use the Software on a single computer only during the subscription term specified at purchase. An Internet connection is required to activate the license and check the license status when the Software is used. Once the subscription term is over, you will be able to either stop using the Software or renew the license for a new subscription term;
25
+ - the "Perpetual License" allows you to install and use the specific Software product version on a single computer without an active subscription. A subscription provides access to new product releases, regular upgrades, and support for new server versions provided during the subscription term;
26
+
27
+ 1.3. If you are a legally licensed user of the Software, you are also entitled to:
28
+ - make one copy of the Software for archival purposes only, or copy the Software onto the hard disk of your computer and retain the original for archival purposes;
29
+ - develop and test Applications with the Software, subject to the Limitations below.
30
+
31
+ 1.4. If you have the "OEM License", you are also entitled to:
32
+ - make any number of copies of the Software to deploy it to your end-user.
33
+ - deploy the Software to your end-user as a Software installation package or integrate it into your Applications.
34
+
35
+ 1.5. You are allowed to use evaluation versions of the Software as specified in the Evaluation section.
36
+
37
+ No other rights or privileges are granted in this Agreement.
38
+
39
+ 2. LIMITATIONS
40
+
41
+ Only legally registered users are licensed to use the Software, subject to all of the conditions of this Agreement. Usage of the Software is subject to the following restrictions.
42
+
43
+ 2.1. You may not reverse engineer, decompile, or disassemble the Software.
44
+
45
+ 2.2. You may not build any other Python packages through inheritance for public distribution or commercial sale.
46
+
47
+ 2.3. You may not reproduce or distribute any Software documentation without express written permission from Devart.
48
+
49
+ 2.4. You may not distribute and sell any portion of the Software integrating it into your Applications.
50
+
51
+ 2.5. You may not transfer, assign, or modify the Software in whole or in part. In particular, the Software license is non-transferable, and you may not transfer the Software installation package.
52
+
53
+ 2.6. You may not remove or alter any Devart's copyright, trademark, or other proprietary rights notice contained in any portion of Devart files.
54
+
55
+ 3. REDISTRIBUTION
56
+
57
+ The license grants you a non-exclusive right to reproduce any new software programs (Applications) created using the Software. You cannot distribute the Software integrated into your Applications unless you are an "OEM License" holder. Any Devart's files remain Devart's exclusive property.
58
+
59
+ 4. TRANSFER
60
+
61
+ You may not transfer the Software to any individual or entity without express written permission from Devart. In particular, you may not share copies of the Software under �Single License� and �Team License� with other co-developers without obtaining proper license of these copies for each individual.
62
+
63
+ 5. TERMINATION
64
+
65
+ Devart may immediately terminate this Agreement without notice or judicial resolution in the event of any failure to comply with any provision of this Agreement. Upon such termination you must destroy the Software, all accompanying written materials, and all copies.
66
+
67
+ 6. EVALUATION
68
+
69
+ Devart may provide evaluation ("Trial") versions of the Software. You may transfer or distribute Trial versions of the Software as an original installation package only. If the Software you have obtained is marked as a "Trial" version, you may install and use the Software for a period of up to 30 calendar days from the date of installation (the "Trial Period"), subject to the additional restriction that it is used solely for evaluation of the Software and not in conjunction with the development or deployment of any application in production. You may not use Applications developed using Trial versions of the Software for any commercial purposes. Upon expiration of the Trial Period, the Software must be uninstalled, all its copies and all accompanying written materials must be destroyed.
70
+
71
+ 7. WARRANTY
72
+
73
+ The Software and documentation are provided "AS IS" without warranty of any kind. Devart makes no warranties, expressed or implied, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose or use.
74
+
75
+ 8. SUBSCRIPTION AND SUPPORT
76
+
77
+ The Software is sold on a subscription basis. The Software subscription entitles you to download improvements and enhancement from Devart's web site as they become available, during the active subscription period. The initial subscription period is one year from the date of purchase of the license. The subscription is automatically activated upon purchase, and may be subsequently renewed by Devart, subject to receipt applicable fees. Licensed users of the Software with an active subscription may request technical assistance with using the Software over email from the Software development. Devart shall use its reasonable endeavors to answer queries raised, but does not guarantee that your queries or problems will be fixed or solved.
78
+
79
+ Devart reserves the right to cease offering and providing support for legacy Python and Database versions.
80
+
81
+ 9. COPYRIGHT
82
+
83
+ The Software is confidential and proprietary copyrighted work of Devart and is protected by international copyright laws and treaty provisions. You may not remove the copyright notice from any copy of the Software or any copy of the written materials, accompanying the Software.
84
+
85
+ This Agreement contains the total agreement between the two parties and supersedes any other agreements, written, oral, expressed, or implied.
@@ -0,0 +1,89 @@
1
+ Metadata-Version: 2.1
2
+ Name: devart-postgresql-connector
3
+ Version: 1.2.0
4
+ Summary: New level of functionality and performance in data access via Python
5
+ Home-page: https://devart.com
6
+ Author: Devart
7
+ Author-email: support@devart.com
8
+ License: Other/Proprietary License
9
+ Project-URL: Homepage, http://devart.com/python/postgresql
10
+ Project-URL: Download, http://devart.com/python/postgresql/download.html
11
+ Project-URL: History, http://devart.com/python/postgresql/revision_history.html
12
+ Project-URL: License, https://www.devart.com/python/eula.html
13
+ Project-URL: Documentation, http://docs.devart.com/python/postgresql/overview.htm
14
+ Requires-Python: >=3.7
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE
17
+
18
+ # Python Connector for PostgreSQL #
19
+
20
+ Python Connector for PostgreSQL is a connectivity solution for accessing
21
+ PostgreSQL databases from Python applications. It fully implements the Python
22
+ DB API 2.0 specification. The connector is distributed as a wheel package
23
+ for Windows, macOS, and Linux.
24
+
25
+ Direct connection
26
+
27
+ The connector enables you to establish a direct connection to PostgreSQL from
28
+ a Python application via TCP/IP, eliminating the need for the database client
29
+ library. A direct connection increases the speed of data transmission between
30
+ the application and PostgreSQL database server. It also streamlines
31
+ the deployment process since you don't have to distribute any client
32
+ libraries with the application.
33
+
34
+ Secure communication
35
+
36
+ The connector supports encrypted communications using SSL/TLS, SSH tunneling,
37
+ and HTTP/HTTPS tunneling.
38
+
39
+ ## Using the connector ##
40
+
41
+ To retrieve data from a database:
42
+
43
+ Import the module.
44
+ ```
45
+ import devart.postgresql
46
+ ```
47
+
48
+ Connect to a database using the `connect()` module method and obtain a `connection` object.
49
+ ```
50
+ my_connection = devart.postgresql.connect(
51
+ Server="your_server",
52
+ Database="your_database",
53
+ UserId="your_username",
54
+ Password="your_password"
55
+ )
56
+ ```
57
+
58
+ Create a `cursor` object using the `cursor()` connection method.
59
+ ```
60
+ my_cursor = my_connection.cursor()
61
+ ```
62
+
63
+ Execute the SQL statement using the `execute()` cursor method.
64
+ ```
65
+ my_cursor.execute("SELECT * FROM employees")
66
+ ```
67
+
68
+ Retrieve the result set using one of the `fetch*()` cursor methods.
69
+ ```
70
+ for row in my_cursor.fetchall():
71
+ print(row)
72
+ ```
73
+
74
+ ## Ordering and activating the license ##
75
+
76
+ You can purchase a license for the connector on the ordering page:
77
+ https://www.devart.com/python/postgresql/ordering.html
78
+
79
+ To activate the license, follow the instructions in the documentation:
80
+ https://docs.devart.com/python/postgresql/activate-a-license.htm
81
+
82
+ ## What's new ##
83
+
84
+ Python Connector for PostgreSQL 1.2
85
+
86
+ - Added support for Python 3.13
87
+ - Added support for PostgreSQL 17
88
+ - Added support for the pgvector extension
89
+ - Added Read Only mode for connection
@@ -0,0 +1,10 @@
1
+ devart/postgresql/__init__.py,sha256=qVu0auvx8Jb3xhYAuceQwzRozweiHAwdkvHXpr_d6Jo,969
2
+ devart/postgresql/postgresql.cp313-win_amd64.pyd,sha256=VCMLJpsJFeptS_iSkvnTMGtStnURVqm-9pEZp-2E3C0,1095328
3
+ devart/postgresql/postgresql.pyi,sha256=siUkOQO84--DMMEy7dZvnuJzIkp7UehEJPErcZaZIU0,12770
4
+ devart/postgresql/http/tunnel.php,sha256=qjhBbshLEKSmoA7RAXVi29TbVNsPBad364d2YHsbyNQ,20720
5
+ devart/postgresql/sqlalchemy/__init__.py,sha256=9T8yOdqr93tCiO3_79gBcO978mycjTt4STwuY8Kvv1g,525
6
+ devart_postgresql_connector-1.2.0.dist-info/LICENSE,sha256=3sjizf07RF-z3Lp3tnA-jy3rN103Ypw11NO9tFnRLtU,8559
7
+ devart_postgresql_connector-1.2.0.dist-info/METADATA,sha256=hwz8Ay3uRUorv1GTNIWprSarzCjNwfwwpCpfbP61-pk,2895
8
+ devart_postgresql_connector-1.2.0.dist-info/WHEEL,sha256=YY3whN5zaIpzxWCxMHGQtwoICDXEsGAh-bKATaD2hj4,101
9
+ devart_postgresql_connector-1.2.0.dist-info/top_level.txt,sha256=h_mZcghGiX6pnc-Kb1EoAfIW2iHeDA0kJKfcLJMbq44,7
10
+ devart_postgresql_connector-1.2.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (72.1.0)
3
+ Root-Is-Purelib: false
4
+ Tag: cp313-cp313-win_amd64
5
+