Skip to content

Commit 6fe5ebb

Browse files
author
Ronan Dunklau
committed
Multicorn reborn
1 parent 0aa6bd6 commit 6fe5ebb

File tree

15 files changed

+33
-14
lines changed

15 files changed

+33
-14
lines changed

.git_hooks/README.md

100644100755
File mode changed.

.gitignore

100644100755
File mode changed.

META.json

100644100755
File mode changed.

Makefile

100644100755
File mode changed.

README.md

100644100755
File mode changed.

doc/dummy_fdw.md

100644100755
File mode changed.

multicorn.control

100644100755
File mode changed.

python/multicorn/__init__.py

100644100755
File mode changed.

python/multicorn/csvfdw.py

100644100755
File mode changed.

python/multicorn/fsfdw.py

100644100755
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
from . import ForeignDataWrapper
22
from structuredfs import StructuredDirectory
33

4+
45
class FilesystemFdw(ForeignDataWrapper):
56

67
def __init__(self, options, columns):
78
super(FilesystemFdw, self).__init__(options)
8-
root_dir = options.get('root_dir');
9-
pattern = options.get('pattern');
9+
root_dir = options.get('root_dir')
10+
pattern = options.get('pattern')
1011
self.sd = StructuredDirectory(root_dir, pattern)
1112

1213
def execute(self):

python/multicorn/ldapfdw.py

100644100755
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,6 @@ def execute(self):
1515
for _, item in self.ldap.search_s(
1616
self.path, ldap.SCOPE_ONELEVEL,
1717
"(objectClass=%s)" % self.objectClass):
18-
yield [
18+
yield [
1919
item.get(field, [None])[0]
2020
for field in self.field_list]

recreate_extension.sql

100644100755
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ drop extension multicorn cascade;
3333
create extension multicorn;
3434
create server multicorn_srv foreign data wrapper multicorn;
3535
create foreign table fstest (
36-
field1 character varying,
37-
field2 character varying,
38-
field3 character varying
36+
field1 character varying collate "fr_FR.utf8",
37+
field2 character varying collate "fr_FR.utf8",
38+
field3 character varying collate "fr_FR.utf8"
3939
) server multicorn_srv options (
4040
wrapper 'multicorn.fsfdw.FilesystemFdw',
4141
root_dir '/tmp/data',

setup.py

100644100755
File mode changed.

sql/multicorn.sql

100644100755
File mode changed.

src/multicorn.c

100644100755
Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "catalog/pg_foreign_table.h"
1717
#include "catalog/pg_foreign_server.h"
1818
#include "catalog/pg_user_mapping.h"
19+
#include "catalog/pg_collation.h"
1920
#include "commands/defrem.h"
2021
#include "commands/explain.h"
2122
#include "foreign/fdwapi.h"
@@ -26,6 +27,7 @@
2627
#include "optimizer/cost.h"
2728
#include "utils/rel.h"
2829
#include "utils/builtins.h"
30+
#include "utils/syscache.h"
2931
#include <Python.h>
3032

3133
PG_MODULE_MAGIC;
@@ -62,7 +64,7 @@ static void multicorn_get_options(Oid foreign_table_id, PyObject *options_dict,
6264
static void multicorn_get_attributes_name(TupleDesc desc, PyObject* list);
6365
static HeapTuple pysequence_to_postgres_tuple(TupleDesc desc, PyObject *pyseq);
6466
static HeapTuple pydict_to_postgres_tuple(TupleDesc desc, PyObject *pydict);
65-
static char* pyobject_to_cstring(PyObject *pyobject);
67+
static char* pyobject_to_cstring(PyObject *pyobject, Form_pg_attribute attribute);
6668

6769
const char* DATE_FORMAT_STRING = "%Y-%m-%d";
6870

@@ -308,9 +310,8 @@ pydict_to_postgres_tuple(TupleDesc desc, PyObject *pydict)
308310
tup_values = (char **) palloc(sizeof(char *) * natts);
309311
for(i = 0; i< natts; i++){
310312
key = NameStr(desc->attrs[i]->attname);
311-
312313
pStr = PyMapping_GetItemString(pydict, key);
313-
tup_values[i] = pyobject_to_cstring(pStr);
314+
tup_values[i] = pyobject_to_cstring(pStr, desc->attrs[i]);
314315
Py_DECREF(pStr);
315316
}
316317
tuple = BuildTupleFromCStrings(attinmeta, tup_values);
@@ -333,7 +334,7 @@ pysequence_to_postgres_tuple(TupleDesc desc, PyObject *pyseq)
333334
tup_values = (char **) palloc(sizeof(char *) * natts);
334335
for(i = 0; i< natts; i++){
335336
pStr = PySequence_GetItem(pyseq, i);
336-
tup_values[i] = pyobject_to_cstring(pStr);
337+
tup_values[i] = pyobject_to_cstring(pStr, desc->attrs[i]);
337338
Py_DECREF(pStr);
338339
}
339340
tuple = BuildTupleFromCStrings(attinmeta, tup_values);
@@ -342,23 +343,40 @@ pysequence_to_postgres_tuple(TupleDesc desc, PyObject *pyseq)
342343
}
343344

344345

345-
static char* pyobject_to_cstring(PyObject *pyobject)
346+
static char* pyobject_to_cstring(PyObject *pyobject, Form_pg_attribute attribute)
346347
{
347348
PyObject * date_module = PyImport_Import(
348349
PyUnicode_FromString("datetime"));
349-
Py_ssize_t unicode_size;
350350
PyObject * date_cls = PyObject_GetAttrString(date_module, "date");
351351
PyObject *pStr;
352+
353+
354+
355+
352356
if(PyNumber_Check(pyobject)){
353357
return PyString_AsString(PyObject_Str(pyobject));
354358
}
355359
if(pyobject == Py_None){
356360
return NULL;
357361
}
358362
if(PyUnicode_Check(pyobject)){
363+
Py_ssize_t unicode_size;
364+
HeapTuple tp;
365+
Form_pg_collation colltup;
366+
char * encoding_name;
359367
unicode_size = PyUnicode_GET_SIZE(pyobject);
360-
elog(INFO, "Unicode object");
361-
return PyString_AsString(PyUnicode_Encode(pyobject, unicode_size, "utf8", NULL));
368+
tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(attribute->attcollation));
369+
if (!HeapTupleIsValid(tp))
370+
elog(ERROR, "cache lookup failed for collation %u", attribute->attcollation);
371+
colltup = (Form_pg_collation) GETSTRUCT(tp);
372+
ReleaseSysCache(tp);
373+
if(colltup->collencoding == -1){
374+
/* No encoding information, do stupid things */
375+
return PyString_AsString(pyobject);
376+
} else {
377+
encoding_name = pg_encoding_to_char(colltup->collencoding);
378+
return PyString_AsString(PyUnicode_Encode(PyUnicode_AsUnicode(pyobject), unicode_size, encoding_name, NULL));
379+
}
362380
}
363381
if(PyObject_IsInstance(pyobject, date_cls)){
364382
PyObject * date_format_method = PyObject_GetAttrString(pyobject, "strftime");

0 commit comments

Comments
 (0)